diff --git a/app/vendor/cakephp-plugins.php b/app/vendor/cakephp-plugins.php index 2a207981b..7520a9c95 100644 --- a/app/vendor/cakephp-plugins.php +++ b/app/vendor/cakephp-plugins.php @@ -14,6 +14,7 @@ 'EnvSource' => $baseDir . '/plugins/EnvSource/', 'Migrations' => $baseDir . '/vendor/cakephp/migrations/', 'OrcidSource' => $baseDir . '/plugins/OrcidSource/', + 'SshKeyAuthenticator' => $baseDir . '/plugins/SshKeyAuthenticator/', 'TestWidget' => $baseDir . '/plugins/TestWidget/', ], ]; diff --git a/app/vendor/cakephp/cakephp-codesniffer/.github/workflows/ci.yml b/app/vendor/cakephp/cakephp-codesniffer/.github/workflows/ci.yml index 92cbce0f7..29190d14d 100644 --- a/app/vendor/cakephp/cakephp-codesniffer/.github/workflows/ci.yml +++ b/app/vendor/cakephp/cakephp-codesniffer/.github/workflows/ci.yml @@ -14,11 +14,13 @@ jobs: strategy: fail-fast: false matrix: - php-version: ['7.2', '7.4', '8.0'] - prefer-lowest: [''] + php-version: ['7.2', '7.4'] + dependencies: [highest] include: - php-version: '7.2' - prefer-lowest: 'prefer-lowest' + dependencies: 'lowest' + - php-version: '8.0' + composer-options: "--ignore-platform-reqs" steps: - uses: actions/checkout@v2 @@ -30,29 +32,11 @@ jobs: extensions: mbstring, intl coverage: pcov - - name: Get composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Get date part for cache key - id: key-date - run: echo "::set-output name=date::$(date +'%Y-%m')" - - - name: Cache composer dependencies - uses: actions/cache@v1 + - name: Composer install + uses: ramsey/composer-install@v3 with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ steps.key-date.outputs.date }}-${{ hashFiles('composer.json') }}-${{ matrix.prefer-lowest }} - - - name: Composer Install - run: | - if [[ ${{ matrix.php-version }} == '8.0' ]]; then - composer install --ignore-platform-reqs - elif ${{ matrix.prefer-lowest == 'prefer-lowest' }}; then - composer update --prefer-lowest --prefer-stable - else - composer install - fi + dependency-versions: ${{ matrix.dependencies }} + composer-options: "${{ matrix.composer-options }}" - name: Setup problem matchers for PHPUnit if: matrix.php-version == '7.4' @@ -82,22 +66,8 @@ jobs: tools: cs2pr coverage: none - - name: Get composer cache directory - id: composer-cache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Get date part for cache key - id: key-date - run: echo "::set-output name=date::$(date +'%Y-%m')" - - - name: Cache composer dependencies - uses: actions/cache@v1 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ steps.key-date.outputs.date }}-${{ hashFiles('composer.json') }}-${{ matrix.prefer-lowest }} - - name: Composer install - run: composer install + uses: ramsey/composer-install@v3 - name: Run PHP CodeSniffer run: vendor/bin/phpcs --report=checkstyle CakePHP/ | cs2pr diff --git a/app/vendor/cakephp/cakephp-codesniffer/CakePHP/Sniffs/Classes/ReturnTypeHintSniff.php b/app/vendor/cakephp/cakephp-codesniffer/CakePHP/Sniffs/Classes/ReturnTypeHintSniff.php index 9f1764cab..699115c5a 100644 --- a/app/vendor/cakephp/cakephp-codesniffer/CakePHP/Sniffs/Classes/ReturnTypeHintSniff.php +++ b/app/vendor/cakephp/cakephp-codesniffer/CakePHP/Sniffs/Classes/ReturnTypeHintSniff.php @@ -230,7 +230,7 @@ protected function getClassNameWithNamespace(File $phpCsFile): ?string return ClassHelper::getFullyQualifiedName( $phpCsFile, - $phpCsFile->findPrevious(TokenHelper::$typeKeywordTokenCodes, $lastToken) + $phpCsFile->findPrevious([T_CLASS, T_TRAIT, T_INTERFACE, T_ENUM], $lastToken) ); } } diff --git a/app/vendor/cakephp/cakephp-codesniffer/CakePHP/Sniffs/Formatting/BlankLineBeforeReturnSniff.php b/app/vendor/cakephp/cakephp-codesniffer/CakePHP/Sniffs/Formatting/BlankLineBeforeReturnSniff.php index 39fd15204..f5da30288 100644 --- a/app/vendor/cakephp/cakephp-codesniffer/CakePHP/Sniffs/Formatting/BlankLineBeforeReturnSniff.php +++ b/app/vendor/cakephp/cakephp-codesniffer/CakePHP/Sniffs/Formatting/BlankLineBeforeReturnSniff.php @@ -56,17 +56,18 @@ public function process(File $phpcsFile, $stackPtr) $prevLineTokens = []; while ($current >= 0 && $tokens[$current]['line'] >= $previousLine) { + $currentTokenCode = $tokens[$current]['code']; if ( $tokens[$current]['line'] == $previousLine - && $tokens[$current]['code'] !== T_WHITESPACE - && $tokens[$current]['code'] !== T_COMMENT - && $tokens[$current]['code'] !== T_DOC_COMMENT_OPEN_TAG - && $tokens[$current]['code'] !== T_DOC_COMMENT_TAG - && $tokens[$current]['code'] !== T_DOC_COMMENT_STRING - && $tokens[$current]['code'] !== T_DOC_COMMENT_CLOSE_TAG - && $tokens[$current]['code'] !== T_DOC_COMMENT_WHITESPACE + && $currentTokenCode !== T_WHITESPACE + && $currentTokenCode !== T_COMMENT + && $currentTokenCode !== T_DOC_COMMENT_OPEN_TAG + && $currentTokenCode !== T_DOC_COMMENT_TAG + && $currentTokenCode !== T_DOC_COMMENT_STRING + && $currentTokenCode !== T_DOC_COMMENT_CLOSE_TAG + && $currentTokenCode !== T_DOC_COMMENT_WHITESPACE ) { - $prevLineTokens[] = $tokens[$current]['code']; + $prevLineTokens[] = $currentTokenCode; } $current--; } diff --git a/app/vendor/cakephp/cakephp-codesniffer/CakePHP/ruleset.xml b/app/vendor/cakephp/cakephp-codesniffer/CakePHP/ruleset.xml index c5dba1351..5ad91117b 100644 --- a/app/vendor/cakephp/cakephp-codesniffer/CakePHP/ruleset.xml +++ b/app/vendor/cakephp/cakephp-codesniffer/CakePHP/ruleset.xml @@ -51,10 +51,15 @@ */tests/* - + + + + + + @@ -81,7 +86,6 @@ - diff --git a/app/vendor/cakephp/cakephp/VERSION.txt b/app/vendor/cakephp/cakephp/VERSION.txt index 4ee60801c..7b31d540c 100644 --- a/app/vendor/cakephp/cakephp/VERSION.txt +++ b/app/vendor/cakephp/cakephp/VERSION.txt @@ -16,4 +16,4 @@ // @license https://opensource.org/licenses/mit-license.php MIT License // +--------------------------------------------------------------------------------------------+ // //////////////////////////////////////////////////////////////////////////////////////////////////// -4.6.0 +4.6.2 diff --git a/app/vendor/cakephp/cakephp/composer.json b/app/vendor/cakephp/cakephp/composer.json index 0060696c6..7f9c27d9a 100644 --- a/app/vendor/cakephp/cakephp/composer.json +++ b/app/vendor/cakephp/cakephp/composer.json @@ -26,7 +26,7 @@ "ext-intl": "*", "ext-json": "*", "ext-mbstring": "*", - "cakephp/chronos": "^2.4.0-RC2", + "cakephp/chronos": "^2.4.0", "composer/ca-bundle": "^1.2", "laminas/laminas-diactoros": "^2.2.2", "laminas/laminas-httphandlerrunner": "^1.1 || ^2.0", diff --git a/app/vendor/cakephp/cakephp/src/Cache/Engine/MemcachedEngine.php b/app/vendor/cakephp/cakephp/src/Cache/Engine/MemcachedEngine.php index 29c56954a..687987603 100644 --- a/app/vendor/cakephp/cakephp/src/Cache/Engine/MemcachedEngine.php +++ b/app/vendor/cakephp/cakephp/src/Cache/Engine/MemcachedEngine.php @@ -365,7 +365,7 @@ public function getMultiple($keys, $default = null): array $values = $this->_Memcached->getMulti($cacheKeys); $return = []; foreach ($cacheKeys as $original => $prefixed) { - $return[$original] = $values[$prefixed] ?? $default; + $return[$original] = array_key_exists($prefixed, $values) ? $values[$prefixed] : $default; } return $return; diff --git a/app/vendor/cakephp/cakephp/src/Cache/Engine/NullEngine.php b/app/vendor/cakephp/cakephp/src/Cache/Engine/NullEngine.php index 4612a276b..89defe467 100644 --- a/app/vendor/cakephp/cakephp/src/Cache/Engine/NullEngine.php +++ b/app/vendor/cakephp/cakephp/src/Cache/Engine/NullEngine.php @@ -62,7 +62,13 @@ public function get($key, $default = null) */ public function getMultiple($keys, $default = null): iterable { - return []; + $result = []; + + foreach ($keys as $key) { + $result[$key] = $default; + } + + return $result; } /** diff --git a/app/vendor/cakephp/cakephp/src/Database/Retry/ReconnectStrategy.php b/app/vendor/cakephp/cakephp/src/Database/Retry/ReconnectStrategy.php index ac847810f..25fb69f80 100644 --- a/app/vendor/cakephp/cakephp/src/Database/Retry/ReconnectStrategy.php +++ b/app/vendor/cakephp/cakephp/src/Database/Retry/ReconnectStrategy.php @@ -109,7 +109,7 @@ protected function reconnect(): bool } try { - $this->connection->connect(); + $this->connection->getDriver()->connect(); if ($this->connection->isQueryLoggingEnabled()) { $this->connection->log('[RECONNECT]'); } diff --git a/app/vendor/cakephp/cakephp/src/ORM/BehaviorRegistry.php b/app/vendor/cakephp/cakephp/src/ORM/BehaviorRegistry.php index 9f006a1bd..fc06b3118 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/BehaviorRegistry.php +++ b/app/vendor/cakephp/cakephp/src/ORM/BehaviorRegistry.php @@ -203,6 +203,24 @@ protected function _getMethods(Behavior $instance, string $class, string $alias) return compact('methods', 'finders'); } + /** + * Set an object directly into the registry by name. + * + * @param string $name The name of the object to set in the registry. + * @param \Cake\ORM\Behavior $object instance to store in the registry + * @return $this + */ + public function set(string $name, object $object) + { + parent::set($name, $object); + + $methods = $this->_getMethods($object, get_class($object), $name); + $this->_methodMap += $methods['methods']; + $this->_finderMap += $methods['finders']; + + return $this; + } + /** * Remove an object from the registry. * diff --git a/app/vendor/cakephp/cakephp/src/ORM/EagerLoader.php b/app/vendor/cakephp/cakephp/src/ORM/EagerLoader.php index d4fa10a25..21e337dcd 100644 --- a/app/vendor/cakephp/cakephp/src/ORM/EagerLoader.php +++ b/app/vendor/cakephp/cakephp/src/ORM/EagerLoader.php @@ -64,6 +64,7 @@ class EagerLoader 'joinType' => 1, 'strategy' => 1, 'negateMatch' => 1, + 'includeFields' => 1, ]; /** diff --git a/app/vendor/cakephp/twig-view/README.md b/app/vendor/cakephp/twig-view/README.md index fca06df62..ca1eab94b 100644 --- a/app/vendor/cakephp/twig-view/README.md +++ b/app/vendor/cakephp/twig-view/README.md @@ -7,13 +7,13 @@ [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE) -This plugin allows you to use the [Twig Templating Language](http://twig.sensiolabs.org/documentation) for your views. +This plugin allows you to use the [Twig Templating Language](https://twig.symfony.com/doc) for your views. It provides wrappers for common View opertions and many helpful extensions that expose CakePHP functions and `jasny/twig-extensions` helpers. ## Installation -To install with [Composer](http://getcomposer.org/), use the command below. +To install with [Composer](https://getcomposer.org/), use the command below. ```bash composer require cakephp/twig-view @@ -205,8 +205,8 @@ All wrapper functions are pre-escaped and do not require using `|raw` filter. Ho ### Extension Filters -* `low` maps to [`strtolower`](http://php.net/strtolower) -* `up` maps to [`strtoupper`](http://php.net/strtoupper) +* `low` maps to [`strtolower`](https://php.net/strtolower) +* `up` maps to [`strtoupper`](https://php.net/strtoupper) * `env` maps to [`env`](https://book.cakephp.org/4/en/core-libraries/global-constants-and-functions.html#global-functions) * `pluralize` maps to [`Cake\Utility\Inflector::pluralize`](https://book.cakephp.org/4/en/core-libraries/inflector.html#Cake\\Utility\\Inflector::pluralize) * `singularize` maps to [`Cake\Utility\Inflector::singularize`](https://book.cakephp.org/4/en/core-libraries/inflector.html#Cake\\Utility\\Inflector::singularize) @@ -222,7 +222,7 @@ All wrapper functions are pre-escaped and do not require using `|raw` filter. Ho * `cake_number_format` maps to [`Cake\I18n\Number::format`](https://book.cakephp.org/4/en/core-libraries/number.html#Cake\\I18n\\Number::format) * `formatDelta` maps to [`Cake\I18n\Number::formatDelta`](https://book.cakephp.org/4/en/core-libraries/number.html#Cake\\I18n\\Number::formatDelta) * `currency` maps to [`Cake\I18n\Number::currency`](https://book.cakephp.org/4/en/core-libraries/number.html#Cake\\I18n\\Number::currency) -* `substr` maps to [`substr`](http://php.net/substr) +* `substr` maps to [`substr`](https://php.net/substr) * `tokenize` maps to [`Cake\Utility\Text::tokenize`](https://book.cakephp.org/4/en/core-libraries/text.html#simple-string-parsing) * `insert` maps to [`Cake\Utility\Text::insert`](https://book.cakephp.org/4/en/core-libraries/text.html#formatting-strings) * `cleanInsert` maps to [`Cake\Utility\Text::cleanInsert`](https://book.cakephp.org/4/en/core-libraries/text.html#formatting-strings) @@ -239,24 +239,24 @@ All wrapper functions are pre-escaped and do not require using `|raw` filter. Ho * `utf8` maps to `Cake\Utility\Text::utf8` * `ascii` maps to `Cake\Utility\Text::ascii` * `parseFileSize` maps to [`Cake\Utility\Text::parseFileSize`](https://book.cakephp.org/4/en/core-libraries/text.html#simple-string-parsing) -* `serialize` maps to [`serialize`](http://php.net/serialize) -* `unserialize` maps to [`unserialize`](http://php.net/unserialize) -* `md5` maps to [`md5`](http://php.net/md5) -* `base64_encode` maps to [`base64_encode`](http://php.net/base64_encode) -* `base64_decode` maps to [`base64_decode`](http://php.net/base64_decode) -* `string` cast to [`string`](http://php.net/manual/en/language.types.type-juggling.php) +* `serialize` maps to [`serialize`](https://php.net/serialize) +* `unserialize` maps to [`unserialize`](https://php.net/unserialize) +* `md5` maps to [`md5`](https://php.net/md5) +* `base64_encode` maps to [`base64_encode`](https://php.net/base64_encode) +* `base64_decode` maps to [`base64_decode`](https://php.net/base64_decode) +* `string` cast to [`string`](https://php.net/manual/en/language.types.type-juggling.php) See `jasny/twig-extensions` for the filters they provide. ### Extension Functions -* `in_array` maps to [`in_array`](http://php.net/in_array) -* `explode` maps to [`explode`](http://php.net/explode) -* `array` cast to [`array`](http://php.net/manual/en/language.types.type-juggling.php) -* `array_push` maps to [`push`](http://php.net/array_push) -* `array_prev` maps to [`prev`](http://php.net/prev) -* `array_next` maps to [`next`](http://php.net/next) -* `array_current` maps to [`current`](http://php.net/current) +* `in_array` maps to [`in_array`](https://php.net/in_array) +* `explode` maps to [`explode`](https://php.net/explode) +* `array` cast to [`array`](https://php.net/manual/en/language.types.type-juggling.php) +* `array_push` maps to [`push`](https://php.net/array_push) +* `array_prev` maps to [`prev`](https://php.net/prev) +* `array_next` maps to [`next`](https://php.net/next) +* `array_current` maps to [`current`](https://php.net/current) * `__` maps to [`__`](https://book.cakephp.org/4/en/core-libraries/internationalization-and-localization.html) * `__d` maps to [`__d`](https://book.cakephp.org/4/en/core-libraries/internationalization-and-localization.html) * `__n` maps to [`__n`](https://book.cakephp.org/4/en/core-libraries/internationalization-and-localization.html) diff --git a/app/vendor/cakephp/twig-view/composer.json b/app/vendor/cakephp/twig-view/composer.json index fff940a58..3c3640a8b 100644 --- a/app/vendor/cakephp/twig-view/composer.json +++ b/app/vendor/cakephp/twig-view/composer.json @@ -22,11 +22,10 @@ "source": "https://github.com/cakephp/twig-view" }, "require": { - "php": ">=7.2", "cakephp/cakephp": "^4.0", "jasny/twig-extensions": "^1.3", "twig/markdown-extra": "^3.0", - "twig/twig": "^3.0" + "twig/twig": "^3.11.0" }, "require-dev": { "cakephp/cakephp-codesniffer": "^4.0", @@ -64,12 +63,16 @@ "@phpstan", "@psalm" ], - "stan-setup": "cp composer.json composer.backup && composer require --dev phpstan/phpstan:^0.12.54 psalm/phar:~4.3.0 && mv composer.backup composer.json", + "stan-setup": "cp composer.json composer.backup && composer require --dev phpstan/phpstan:~1.7.0 psalm/phar:~4.23.0 && mv composer.backup composer.json", "test": [ "phpunit" ] }, "config": { - "sort-packages": true + "sort-packages": true, + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true, + "cakephp/plugin-installer": true + } } } diff --git a/app/vendor/cakephp/twig-view/src/Twig/Extension/I18nExtension.php b/app/vendor/cakephp/twig-view/src/Twig/Extension/I18nExtension.php index 3b52084c9..c5977e3e5 100644 --- a/app/vendor/cakephp/twig-view/src/Twig/Extension/I18nExtension.php +++ b/app/vendor/cakephp/twig-view/src/Twig/Extension/I18nExtension.php @@ -35,10 +35,13 @@ public function getFunctions(): array { return [ new TwigFunction('__', '__'), - new TwigFunction('__d', '__d'), new TwigFunction('__n', '__n'), - new TwigFunction('__x', '__x'), + new TwigFunction('__d', '__d'), new TwigFunction('__dn', '__dn'), + new TwigFunction('__x', '__x'), + new TwigFunction('__xn', '__xn'), + new TwigFunction('__dx', '__dx'), + new TwigFunction('__dxn', '__dxn'), ]; } } diff --git a/app/vendor/cakephp/twig-view/src/View/TwigView.php b/app/vendor/cakephp/twig-view/src/View/TwigView.php index 2be780314..2c35a47df 100644 --- a/app/vendor/cakephp/twig-view/src/View/TwigView.php +++ b/app/vendor/cakephp/twig-view/src/View/TwigView.php @@ -64,12 +64,12 @@ class TwigView extends View * Use ViewBuilder::setOption()/setOptions() in your controller to set these options. * * - `environment` - Array of config you would pass into \Twig\Environment to overwrite the default settings. - * See http://twig.sensiolabs.org/doc/api.html#environment-options. + * See https://twig.symfony.com/doc/3.x/api.html#environment-options. * - `markdown` - Set to 'default' to use `DefaultMarkdown` or * provide custom Twig\Extra\Markdown\MarkdownInterface instance. * See https://twig.symfony.com/doc/3.x/filters/markdown_to_html.html. * - * @var array + * @var array */ protected $_defaultConfig = [ 'environment' => [ diff --git a/app/vendor/composer/ClassLoader.php b/app/vendor/composer/ClassLoader.php index afef3fa2a..a72151c77 100644 --- a/app/vendor/composer/ClassLoader.php +++ b/app/vendor/composer/ClassLoader.php @@ -42,6 +42,9 @@ */ class ClassLoader { + /** @var \Closure(string):void */ + private static $includeFile; + /** @var ?string */ private $vendorDir; @@ -106,6 +109,7 @@ class ClassLoader public function __construct($vendorDir = null) { $this->vendorDir = $vendorDir; + self::initializeIncludeClosure(); } /** @@ -425,7 +429,8 @@ public function unregister() public function loadClass($class) { if ($file = $this->findFile($class)) { - includeFile($file); + $includeFile = self::$includeFile; + $includeFile($file); return true; } @@ -555,18 +560,26 @@ private function findFileWithExtension($class, $ext) return false; } -} -/** - * Scope isolated include. - * - * Prevents access to $this/self from included files. - * - * @param string $file - * @return void - * @private - */ -function includeFile($file) -{ - include $file; + /** + * @return void + */ + private static function initializeIncludeClosure() + { + if (self::$includeFile !== null) { + return; + } + + /** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + */ + self::$includeFile = \Closure::bind(static function($file) { + include $file; + }, null, null); + } } diff --git a/app/vendor/composer/autoload_files.php b/app/vendor/composer/autoload_files.php index a3f9ae503..2929593d3 100644 --- a/app/vendor/composer/autoload_files.php +++ b/app/vendor/composer/autoload_files.php @@ -6,9 +6,9 @@ $baseDir = dirname($vendorDir); return array( + '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php', '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php', - '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php', '89efb1254ef2d1c5d80096acd12c4098' => $vendorDir . '/twig/twig/src/Resources/core.php', 'ffecb95d45175fd40f75be8a23b34f90' => $vendorDir . '/twig/twig/src/Resources/debug.php', 'c7baa00073ee9c61edf148c51917cfb4' => $vendorDir . '/twig/twig/src/Resources/escaper.php', @@ -43,6 +43,7 @@ '0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php', 'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php', '23c18046f52bef3eea034657bafda50f' => $vendorDir . '/symfony/polyfill-php81/bootstrap.php', + 'f278094c42a52b6bff77f375d59c1278' => $vendorDir . '/twig/markdown-extra/Resources/functions.php', '6124b4c8570aa390c21fafd04a26c69f' => $vendorDir . '/myclabs/deep-copy/src/DeepCopy/deep_copy.php', '667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php', 'ec07570ca5a812141189b1fa81503674' => $vendorDir . '/phpunit/phpunit/src/Framework/Assert/Functions.php', diff --git a/app/vendor/composer/autoload_psr4.php b/app/vendor/composer/autoload_psr4.php index 2dbb2f4f2..21a723094 100644 --- a/app/vendor/composer/autoload_psr4.php +++ b/app/vendor/composer/autoload_psr4.php @@ -8,6 +8,8 @@ return array( 'Twig\\Extra\\Markdown\\' => array($vendorDir . '/twig/markdown-extra'), 'Twig\\' => array($vendorDir . '/twig/twig/src'), + 'TestPlugin\\Test\\' => array($baseDir . '/availableplugins/TestPlugin/tests'), + 'TestPlugin\\' => array($baseDir . '/availableplugins/TestPlugin/src'), 'Symfony\\Polyfill\\Php81\\' => array($vendorDir . '/symfony/polyfill-php81'), 'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'), 'Symfony\\Polyfill\\Php73\\' => array($vendorDir . '/symfony/polyfill-php73'), @@ -24,6 +26,8 @@ 'Symfony\\Component\\Filesystem\\' => array($vendorDir . '/symfony/filesystem'), 'Symfony\\Component\\Console\\' => array($vendorDir . '/symfony/console'), 'Symfony\\Component\\Config\\' => array($vendorDir . '/symfony/config'), + 'SshKeyAuthenticator\\Test\\' => array($baseDir . '/plugins/SshKeyAuthenticator/tests'), + 'SshKeyAuthenticator\\' => array($baseDir . '/plugins/SshKeyAuthenticator/src'), 'SqlConnector\\Test\\' => array($baseDir . '/availableplugins/SqlConnector/tests'), 'SqlConnector\\' => array($baseDir . '/availableplugins/SqlConnector/src'), 'SlevomatCodingStandard\\' => array($vendorDir . '/slevomat/coding-standard/SlevomatCodingStandard'), @@ -43,12 +47,15 @@ 'PipelineToolkit\\' => array($baseDir . '/availableplugins/PipelineToolkit/src'), 'PhpParser\\' => array($vendorDir . '/nikic/php-parser/lib/PhpParser'), 'Phinx\\' => array($vendorDir . '/robmorgan/phinx/src/Phinx'), + 'PasswordAuthenticator\\Test\\' => array($baseDir . '/availableplugins/PasswordAuthenticator/tests'), + 'PasswordAuthenticator\\' => array($baseDir . '/availableplugins/PasswordAuthenticator/src'), 'PHPStan\\PhpDocParser\\' => array($vendorDir . '/phpstan/phpdoc-parser/src'), 'PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\' => array($vendorDir . '/dealerdirect/phpcodesniffer-composer-installer/src'), 'OrcidSource\\Test\\' => array($baseDir . '/plugins/OrcidSource/tests'), 'OrcidSource\\' => array($baseDir . '/plugins/OrcidSource/src'), 'Migrations\\' => array($vendorDir . '/cakephp/migrations/src'), 'Masterminds\\' => array($vendorDir . '/masterminds/html5/src'), + 'MabeEnum\\' => array($vendorDir . '/marc-mabe/php-enum/src'), 'M1\\Env\\' => array($vendorDir . '/m1/env/src'), 'League\\Uri\\' => array($vendorDir . '/league/uri', $vendorDir . '/league/uri-interfaces'), 'League\\Container\\' => array($vendorDir . '/league/container/src'), @@ -62,15 +69,16 @@ 'EnvSource\\' => array($baseDir . '/plugins/EnvSource/src'), 'Doctrine\\SqlFormatter\\' => array($vendorDir . '/doctrine/sql-formatter/src'), 'Doctrine\\Instantiator\\' => array($vendorDir . '/doctrine/instantiator/src/Doctrine/Instantiator'), - 'Doctrine\\Deprecations\\' => array($vendorDir . '/doctrine/deprecations/lib/Doctrine/Deprecations'), + 'Doctrine\\Deprecations\\' => array($vendorDir . '/doctrine/deprecations/src'), 'Doctrine\\DBAL\\' => array($vendorDir . '/doctrine/dbal/src'), - 'Doctrine\\Common\\Cache\\' => array($vendorDir . '/doctrine/cache/lib/Doctrine/Common/Cache'), 'Doctrine\\Common\\' => array($vendorDir . '/doctrine/event-manager/src'), 'DeepCopy\\' => array($vendorDir . '/myclabs/deep-copy/src/DeepCopy'), 'DebugKit\\Test\\Fixture\\' => array($vendorDir . '/cakephp/debug_kit/tests/Fixture'), 'DebugKit\\' => array($vendorDir . '/cakephp/debug_kit/src'), 'CoreServer\\Test\\' => array($baseDir . '/plugins/CoreServer/tests'), 'CoreServer\\' => array($baseDir . '/plugins/CoreServer/src'), + 'CoreReport\\Test\\' => array($baseDir . '/plugins/CoreReport/tests'), + 'CoreReport\\' => array($baseDir . '/plugins/CoreReport/src'), 'CoreJob\\Test\\' => array($baseDir . '/plugins/CoreJob/tests'), 'CoreJob\\' => array($baseDir . '/plugins/CoreJob/src'), 'CoreEnroller\\Test\\' => array($baseDir . '/plugins/CoreEnroller/tests'), diff --git a/app/vendor/composer/autoload_real.php b/app/vendor/composer/autoload_real.php index ea4df5fa0..8072a483a 100644 --- a/app/vendor/composer/autoload_real.php +++ b/app/vendor/composer/autoload_real.php @@ -33,25 +33,18 @@ public static function getLoader() $loader->register(true); - $includeFiles = \Composer\Autoload\ComposerStaticInitb25f76eec921984aa94dcf4015a4846e::$files; - foreach ($includeFiles as $fileIdentifier => $file) { - composerRequireb25f76eec921984aa94dcf4015a4846e($fileIdentifier, $file); + $filesToLoad = \Composer\Autoload\ComposerStaticInitb25f76eec921984aa94dcf4015a4846e::$files; + $requireFile = \Closure::bind(static function ($fileIdentifier, $file) { + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + + require $file; + } + }, null, null); + foreach ($filesToLoad as $fileIdentifier => $file) { + $requireFile($fileIdentifier, $file); } return $loader; } } - -/** - * @param string $fileIdentifier - * @param string $file - * @return void - */ -function composerRequireb25f76eec921984aa94dcf4015a4846e($fileIdentifier, $file) -{ - if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { - $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; - - require $file; - } -} diff --git a/app/vendor/composer/autoload_static.php b/app/vendor/composer/autoload_static.php index d5738fcc7..93eb7e9c7 100644 --- a/app/vendor/composer/autoload_static.php +++ b/app/vendor/composer/autoload_static.php @@ -7,9 +7,9 @@ class ComposerStaticInitb25f76eec921984aa94dcf4015a4846e { public static $files = array ( + '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php', '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php', - '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php', '89efb1254ef2d1c5d80096acd12c4098' => __DIR__ . '/..' . '/twig/twig/src/Resources/core.php', 'ffecb95d45175fd40f75be8a23b34f90' => __DIR__ . '/..' . '/twig/twig/src/Resources/debug.php', 'c7baa00073ee9c61edf148c51917cfb4' => __DIR__ . '/..' . '/twig/twig/src/Resources/escaper.php', @@ -44,6 +44,7 @@ class ComposerStaticInitb25f76eec921984aa94dcf4015a4846e '0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php', 'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php', '23c18046f52bef3eea034657bafda50f' => __DIR__ . '/..' . '/symfony/polyfill-php81/bootstrap.php', + 'f278094c42a52b6bff77f375d59c1278' => __DIR__ . '/..' . '/twig/markdown-extra/Resources/functions.php', '6124b4c8570aa390c21fafd04a26c69f' => __DIR__ . '/..' . '/myclabs/deep-copy/src/DeepCopy/deep_copy.php', '667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php', 'ec07570ca5a812141189b1fa81503674' => __DIR__ . '/..' . '/phpunit/phpunit/src/Framework/Assert/Functions.php', @@ -55,6 +56,8 @@ class ComposerStaticInitb25f76eec921984aa94dcf4015a4846e array ( 'Twig\\Extra\\Markdown\\' => 20, 'Twig\\' => 5, + 'TestPlugin\\Test\\' => 16, + 'TestPlugin\\' => 11, ), 'S' => array ( @@ -74,6 +77,8 @@ class ComposerStaticInitb25f76eec921984aa94dcf4015a4846e 'Symfony\\Component\\Filesystem\\' => 29, 'Symfony\\Component\\Console\\' => 26, 'Symfony\\Component\\Config\\' => 25, + 'SshKeyAuthenticator\\Test\\' => 25, + 'SshKeyAuthenticator\\' => 20, 'SqlConnector\\Test\\' => 18, 'SqlConnector\\' => 13, 'SlevomatCodingStandard\\' => 23, @@ -99,18 +104,21 @@ class ComposerStaticInitb25f76eec921984aa94dcf4015a4846e 'PipelineToolkit\\' => 16, 'PhpParser\\' => 10, 'Phinx\\' => 6, + 'PasswordAuthenticator\\Test\\' => 27, + 'PasswordAuthenticator\\' => 22, 'PHPStan\\PhpDocParser\\' => 21, 'PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\' => 57, ), - 'O' => + 'O' => array ( 'OrcidSource\\Test\\' => 17, 'OrcidSource\\' => 12, ), - 'M' => + 'M' => array ( 'Migrations\\' => 11, 'Masterminds\\' => 12, + 'MabeEnum\\' => 9, 'M1\\Env\\' => 7, ), 'L' => @@ -141,7 +149,6 @@ class ComposerStaticInitb25f76eec921984aa94dcf4015a4846e 'Doctrine\\Instantiator\\' => 22, 'Doctrine\\Deprecations\\' => 22, 'Doctrine\\DBAL\\' => 14, - 'Doctrine\\Common\\Cache\\' => 22, 'Doctrine\\Common\\' => 16, 'DeepCopy\\' => 9, 'DebugKit\\Test\\Fixture\\' => 22, @@ -151,6 +158,8 @@ class ComposerStaticInitb25f76eec921984aa94dcf4015a4846e array ( 'CoreServer\\Test\\' => 16, 'CoreServer\\' => 11, + 'CoreReport\\Test\\' => 16, + 'CoreReport\\' => 11, 'CoreJob\\Test\\' => 13, 'CoreJob\\' => 8, 'CoreEnroller\\Test\\' => 18, @@ -197,6 +206,14 @@ class ComposerStaticInitb25f76eec921984aa94dcf4015a4846e array ( 0 => __DIR__ . '/..' . '/twig/twig/src', ), + 'TestPlugin\\Test\\' => + array ( + 0 => __DIR__ . '/../..' . '/availableplugins/TestPlugin/tests', + ), + 'TestPlugin\\' => + array ( + 0 => __DIR__ . '/../..' . '/availableplugins/TestPlugin/src', + ), 'Symfony\\Polyfill\\Php81\\' => array ( 0 => __DIR__ . '/..' . '/symfony/polyfill-php81', @@ -261,6 +278,14 @@ class ComposerStaticInitb25f76eec921984aa94dcf4015a4846e array ( 0 => __DIR__ . '/..' . '/symfony/config', ), + 'SshKeyAuthenticator\\Test\\' => + array ( + 0 => __DIR__ . '/../..' . '/plugins/SshKeyAuthenticator/tests', + ), + 'SshKeyAuthenticator\\' => + array ( + 0 => __DIR__ . '/../..' . '/plugins/SshKeyAuthenticator/src', + ), 'SqlConnector\\Test\\' => array ( 0 => __DIR__ . '/../..' . '/availableplugins/SqlConnector/tests', @@ -339,6 +364,14 @@ class ComposerStaticInitb25f76eec921984aa94dcf4015a4846e array ( 0 => __DIR__ . '/..' . '/robmorgan/phinx/src/Phinx', ), + 'PasswordAuthenticator\\Test\\' => + array ( + 0 => __DIR__ . '/../..' . '/availableplugins/PasswordAuthenticator/tests', + ), + 'PasswordAuthenticator\\' => + array ( + 0 => __DIR__ . '/../..' . '/availableplugins/PasswordAuthenticator/src', + ), 'PHPStan\\PhpDocParser\\' => array ( 0 => __DIR__ . '/..' . '/phpstan/phpdoc-parser/src', @@ -347,15 +380,15 @@ class ComposerStaticInitb25f76eec921984aa94dcf4015a4846e array ( 0 => __DIR__ . '/..' . '/dealerdirect/phpcodesniffer-composer-installer/src', ), - 'OrcidSource\\Test\\' => + 'OrcidSource\\Test\\' => array ( 0 => __DIR__ . '/../..' . '/plugins/OrcidSource/tests', ), - 'OrcidSource\\' => + 'OrcidSource\\' => array ( 0 => __DIR__ . '/../..' . '/plugins/OrcidSource/src', ), - 'Migrations\\' => + 'Migrations\\' => array ( 0 => __DIR__ . '/..' . '/cakephp/migrations/src', ), @@ -363,6 +396,10 @@ class ComposerStaticInitb25f76eec921984aa94dcf4015a4846e array ( 0 => __DIR__ . '/..' . '/masterminds/html5/src', ), + 'MabeEnum\\' => + array ( + 0 => __DIR__ . '/..' . '/marc-mabe/php-enum/src', + ), 'M1\\Env\\' => array ( 0 => __DIR__ . '/..' . '/m1/env/src', @@ -418,16 +455,12 @@ class ComposerStaticInitb25f76eec921984aa94dcf4015a4846e ), 'Doctrine\\Deprecations\\' => array ( - 0 => __DIR__ . '/..' . '/doctrine/deprecations/lib/Doctrine/Deprecations', + 0 => __DIR__ . '/..' . '/doctrine/deprecations/src', ), 'Doctrine\\DBAL\\' => array ( 0 => __DIR__ . '/..' . '/doctrine/dbal/src', ), - 'Doctrine\\Common\\Cache\\' => - array ( - 0 => __DIR__ . '/..' . '/doctrine/cache/lib/Doctrine/Common/Cache', - ), 'Doctrine\\Common\\' => array ( 0 => __DIR__ . '/..' . '/doctrine/event-manager/src', @@ -452,6 +485,14 @@ class ComposerStaticInitb25f76eec921984aa94dcf4015a4846e array ( 0 => __DIR__ . '/../..' . '/plugins/CoreServer/src', ), + 'CoreReport\\Test\\' => + array ( + 0 => __DIR__ . '/../..' . '/plugins/CoreReport/tests', + ), + 'CoreReport\\' => + array ( + 0 => __DIR__ . '/../..' . '/plugins/CoreReport/src', + ), 'CoreJob\\Test\\' => array ( 0 => __DIR__ . '/../..' . '/plugins/CoreJob/tests', diff --git a/app/vendor/composer/ca-bundle/res/cacert.pem b/app/vendor/composer/ca-bundle/res/cacert.pem index 584af3c0b..4acd8e536 100644 --- a/app/vendor/composer/ca-bundle/res/cacert.pem +++ b/app/vendor/composer/ca-bundle/res/cacert.pem @@ -1,14 +1,14 @@ ## ## Bundle of CA Root Certificates ## -## Certificate data from Mozilla as of: Tue Feb 25 04:12:03 2025 GMT +## Certificate data from Mozilla as of: Tue May 20 03:12:02 2025 GMT ## ## Find updated versions here: https://curl.se/docs/caextract.html ## ## This is a bundle of X.509 certificates of public Certificate Authorities ## (CA). These were automatically extracted from Mozilla's root certificates ## file (certdata.txt). This file can be found in the mozilla source tree: -## https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt +## https://raw.githubusercontent.com/mozilla-firefox/firefox/refs/heads/release/security/nss/lib/ckfw/builtins/certdata.txt ## ## It contains the certificates in PEM format and therefore ## can be directly used with curl / libcurl / php_curl, or with @@ -16,76 +16,10 @@ ## Just configure this file as the SSLCACertificateFile. ## ## Conversion done with mk-ca-bundle.pl version 1.29. -## SHA256: 620fd89c02acb0019f1899dab7907db5d20735904f5a9a0d3a8771a5857ac482 +## SHA256: 8944ec6b572b577daee4fc681a425881f841ec2660e4cb5f0eee727f84620697 ## -GlobalSign Root CA -================== ------BEGIN CERTIFICATE----- -MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkGA1UEBhMCQkUx -GTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jvb3QgQ0ExGzAZBgNVBAMTEkds -b2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAwMDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNV -BAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYD -VQQDExJHbG9iYWxTaWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDa -DuaZjc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavpxy0Sy6sc -THAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp1Wrjsok6Vjk4bwY8iGlb -Kk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdGsnUOhugZitVtbNV4FpWi6cgKOOvyJBNP -c1STE4U6G7weNLWLBYy5d4ux2x8gkasJU26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrX -gzT/LCrBbBlDSgeF59N89iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0BAQUF -AAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOzyj1hTdNGCbM+w6Dj -Y1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE38NflNUVyRRBnMRddWQVDf9VMOyG -j/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymPAbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhH -hm4qxFYxldBniYUr+WymXUadDKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveC -X4XSQRjbgbMEHMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== ------END CERTIFICATE----- - -Entrust.net Premium 2048 Secure Server CA -========================================= ------BEGIN CERTIFICATE----- -MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u -ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp -bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV -BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx -NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 -d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl -MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u -ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL -Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr -hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW -nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi -VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E -BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ -KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy -T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf -zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT -J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e -nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE= ------END CERTIFICATE----- - -Baltimore CyberTrust Root -========================= ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJRTESMBAGA1UE -ChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3li -ZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoXDTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMC -SUUxEjAQBgNVBAoTCUJhbHRpbW9yZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFs -dGltb3JlIEN5YmVyVHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKME -uyKrmD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjrIZ3AQSsB -UnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeKmpYcqWe4PwzV9/lSEy/C -G9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSuXmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9 -XbIGevOF6uvUA65ehD5f/xXtabz5OTZydc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjpr -l3RjM71oGDHweI12v/yejl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoI -VDaGezq1BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEB -BQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT929hkTI7gQCvlYpNRh -cL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3WgxjkzSswF07r51XgdIGn9w/xZchMB5 -hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsa -Y71k5h+3zvDyny67G7fyUIhzksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9H -RCwBXbsdtTLSR9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp ------END CERTIFICATE----- - Entrust Root Certification Authority ==================================== -----BEGIN CERTIFICATE----- @@ -112,30 +46,6 @@ W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0 tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8 -----END CERTIFICATE----- -Comodo AAA Services root -======================== ------BEGIN CERTIFICATE----- -MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwS -R3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0Eg -TGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAw -MFoXDTI4MTIzMTIzNTk1OVowezELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hl -c3RlcjEQMA4GA1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNV -BAMMGEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQuaBtDFcCLNSS1UY8y2bmhG -C1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe3M/vg4aijJRPn2jymJBGhCfHdr/jzDUs -i14HZGWCwEiwqJH5YZ92IFCokcdmtet4YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszW -Y19zjNoFmag4qMsXeDZRrOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjH -Ypy+g8cmez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQUoBEK -Iz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wewYDVR0f -BHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNl -cy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29tb2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2Vz -LmNybDANBgkqhkiG9w0BAQUFAAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm -7l3sAg9g1o1QGE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz -Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2G9w84FoVxp7Z -8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsil2D4kF501KKaU73yqWjgom7C -12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== ------END CERTIFICATE----- - QuoVadis Root CA 2 ================== -----BEGIN CERTIFICATE----- @@ -202,78 +112,6 @@ vGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeTmJlglFwjz1onl14LBQaTNx47aTbr qZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK4SVhM7JZG+Ju1zdXtg2pEto= -----END CERTIFICATE----- -XRamp Global CA Root -==================== ------BEGIN CERTIFICATE----- -MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UE -BhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2Vj -dXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB -dXRob3JpdHkwHhcNMDQxMTAxMTcxNDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMx -HjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkg -U2VydmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp -dHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS638eMpSe2OAtp87ZOqCwu -IR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCPKZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMx -foArtYzAQDsRhtDLooY2YKTVMIJt2W7QDxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FE -zG+gSqmUsE3a56k0enI4qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqs -AxcZZPRaJSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNViPvry -xS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1Ud -EwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASsjVy16bYbMDYGA1UdHwQvMC0wK6Ap -oCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMC -AQEwDQYJKoZIhvcNAQEFBQADggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc -/Kh4ZzXxHfARvbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt -qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLaIR9NmXmd4c8n -nxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSyi6mx5O+aGtA9aZnuqCij4Tyz -8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQO+7ETPTsJ3xCwnR8gooJybQDJbw= ------END CERTIFICATE----- - -Go Daddy Class 2 CA -=================== ------BEGIN CERTIFICATE----- -MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMY -VGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRp -ZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkG -A1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g -RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQAD -ggENADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv -2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+qN1j3hybX2C32 -qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiOr18SPaAIBQi2XKVlOARFmR6j -YGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmY -vLEHZ6IVDd2gWMZEewo+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0O -BBYEFNLEsNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h/t2o -atTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMu -MTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwG -A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wim -PQoZ+YeAEW5p5JYXMP80kWNyOO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKt -I3lpjbi2Tc7PTMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ -HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mERdEr/VxqHD3VI -Ls9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5CufReYNnyicsbkqWletNw+vHX/b -vZ8= ------END CERTIFICATE----- - -Starfield Class 2 CA -==================== ------BEGIN CERTIFICATE----- -MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzElMCMGA1UEChMc -U3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZpZWxkIENsYXNzIDIg -Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQwNjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBo -MQswCQYDVQQGEwJVUzElMCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAG -A1UECxMpU3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqG -SIb3DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf8MOh2tTY -bitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN+lq2cwQlZut3f+dZxkqZ -JRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVm -epsZGD3/cVE8MC5fvj13c7JdBmzDI1aaK4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSN -F4Azbl5KXZnJHoe0nRrA1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HF -MIHCMB0GA1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fRzt0f -hvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVsZCBUZWNo -bm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAyIENlcnRpZmljYXRpb24g -QXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGs -afPzWdqbAYcaT1epoXkJKtv3L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLM -PUxA2IGvd56Deruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl -xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynpVSJYACPq4xJD -KVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEYWQPJIrSPnNVeKtelttQKbfi3 -QBFGmh95DmK/D5fs4C8fF5Q= ------END CERTIFICATE----- - DigiCert Assured ID Root CA =========================== -----BEGIN CERTIFICATE----- diff --git a/app/vendor/composer/class-map-generator/README.md b/app/vendor/composer/class-map-generator/README.md index 4b5d6a26d..ff27e2ea3 100644 --- a/app/vendor/composer/class-map-generator/README.md +++ b/app/vendor/composer/class-map-generator/README.md @@ -12,7 +12,7 @@ Installation Install the latest version with: ```bash -$ composer require composer/class-map-generator +composer require composer/class-map-generator ``` diff --git a/app/vendor/composer/class-map-generator/composer.json b/app/vendor/composer/class-map-generator/composer.json index 59aa759e7..496912c26 100644 --- a/app/vendor/composer/class-map-generator/composer.json +++ b/app/vendor/composer/class-map-generator/composer.json @@ -19,11 +19,11 @@ "composer/pcre": "^2.1 || ^3.1" }, "require-dev": { - "symfony/phpunit-bridge": "^5", - "phpstan/phpstan": "^1.6", - "phpstan/phpstan-deprecation-rules": "^1", - "phpstan/phpstan-strict-rules": "^1.1", - "phpstan/phpstan-phpunit": "^1", + "phpunit/phpunit": "^8", + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-deprecation-rules": "^1 || ^2", + "phpstan/phpstan-strict-rules": "^1.1 || ^2", + "phpstan/phpstan-phpunit": "^1 || ^2", "symfony/filesystem": "^5.4 || ^6" }, "autoload": { @@ -42,7 +42,7 @@ } }, "scripts": { - "test": "SYMFONY_PHPUNIT_REMOVE_RETURN_TYPEHINT=1 vendor/bin/simple-phpunit", - "phpstan": "phpstan analyse" + "test": "@php phpunit", + "phpstan": "@php phpstan analyse" } } diff --git a/app/vendor/composer/class-map-generator/src/ClassMap.php b/app/vendor/composer/class-map-generator/src/ClassMap.php index d6e2899c2..797efc688 100644 --- a/app/vendor/composer/class-map-generator/src/ClassMap.php +++ b/app/vendor/composer/class-map-generator/src/ClassMap.php @@ -12,6 +12,8 @@ namespace Composer\ClassMapGenerator; +use Composer\Pcre\Preg; + /** * @author Jordi Boggiano */ @@ -28,7 +30,7 @@ class ClassMap implements \Countable private $ambiguousClasses = []; /** - * @var string[] + * @var array> */ private $psrViolations = []; @@ -55,7 +57,13 @@ public function getMap(): array */ public function getPsrViolations(): array { - return $this->psrViolations; + if (\count($this->psrViolations) === 0) { + return []; + } + + return array_map(static function (array $violation): string { + return $violation['warning']; + }, array_merge(...array_values($this->psrViolations))); } /** @@ -65,11 +73,36 @@ public function getPsrViolations(): array * * To get the path the class is being mapped to, call getClassPath * + * By default, paths that contain test(s), fixture(s), example(s) or stub(s) are ignored + * as those are typically not problematic when they're dummy classes in the tests folder. + * If you want to get these back as well you can pass false to $duplicatesFilter. Or + * you can pass your own pattern to exclude if you need to change the default. + * + * @param non-empty-string|false $duplicatesFilter + * * @return array> */ - public function getAmbiguousClasses(): array + public function getAmbiguousClasses($duplicatesFilter = '{/(test|fixture|example|stub)s?/}i'): array { - return $this->ambiguousClasses; + if (false === $duplicatesFilter) { + return $this->ambiguousClasses; + } + + if (true === $duplicatesFilter) { + throw new \InvalidArgumentException('$duplicatesFilter should be false or a string with a valid regex, got true.'); + } + + $ambiguousClasses = []; + foreach ($this->ambiguousClasses as $class => $paths) { + $paths = array_filter($paths, function ($path) use ($duplicatesFilter) { + return !Preg::isMatch($duplicatesFilter, strtr($path, '\\', '/')); + }); + if (\count($paths) > 0) { + $ambiguousClasses[$class] = array_values($paths); + } + } + + return $ambiguousClasses; } /** @@ -86,6 +119,8 @@ public function sort(): void */ public function addClass(string $className, string $path): void { + unset($this->psrViolations[strtr($path, '\\', '/')]); + $this->map[$className] = $path; } @@ -110,9 +145,22 @@ public function hasClass(string $className): bool return isset($this->map[$className]); } - public function addPsrViolation(string $warning): void + public function addPsrViolation(string $warning, string $className, string $path): void { - $this->psrViolations[] = $warning; + $path = rtrim(strtr($path, '\\', '/'), '/'); + + $this->psrViolations[$path][] = ['warning' => $warning, 'className' => $className]; + } + + public function clearPsrViolationsByPath(string $pathPrefix): void + { + $pathPrefix = rtrim(strtr($pathPrefix, '\\', '/'), '/'); + + foreach ($this->psrViolations as $path => $violations) { + if ($path === $pathPrefix || 0 === \strpos($path, $pathPrefix.'/')) { + unset($this->psrViolations[$path]); + } + } } /** @@ -128,4 +176,16 @@ public function count(): int { return \count($this->map); } + + /** + * Get the raw psr violations + * + * This is a map of filepath to an associative array of the warning string + * and the offending class name. + * @return array> + */ + public function getRawPsrViolations(): array + { + return $this->psrViolations; + } } diff --git a/app/vendor/composer/class-map-generator/src/ClassMapGenerator.php b/app/vendor/composer/class-map-generator/src/ClassMapGenerator.php index fd905c3ca..2bfa1ed97 100644 --- a/app/vendor/composer/class-map-generator/src/ClassMapGenerator.php +++ b/app/vendor/composer/class-map-generator/src/ClassMapGenerator.php @@ -45,6 +45,11 @@ class ClassMapGenerator */ private $classMap; + /** + * @var non-empty-string + */ + private $streamWrappersRegex; + /** * @param list $extensions File extensions to scan for classes in the given paths */ @@ -52,6 +57,7 @@ public function __construct(array $extensions = ['php', 'inc']) { $this->extensions = $extensions; $this->classMap = new ClassMap; + $this->streamWrappersRegex = sprintf('{^(?:%s)://}', implode('|', array_map('preg_quote', stream_get_wrappers()))); } /** @@ -61,7 +67,7 @@ public function __construct(array $extensions = ['php', 'inc']) * * @return $this */ - public function avoidDuplicateScans(FileList $scannedFiles = null): self + public function avoidDuplicateScans(?FileList $scannedFiles = null): self { $this->scannedFiles = $scannedFiles ?? new FileList; @@ -97,10 +103,11 @@ public function getClassMap(): ClassMap * @param non-empty-string|null $excluded Regex that matches file paths to be excluded from the classmap * @param 'classmap'|'psr-0'|'psr-4' $autoloadType Optional autoload standard to use mapping rules with the namespace instead of purely doing a classmap * @param string|null $namespace Optional namespace prefix to filter by, only for psr-0/psr-4 autoloading + * @param array $excludedDirs Optional dirs to exclude from search relative to $path * * @throws \RuntimeException When the path is neither an existing file nor directory */ - public function scanPaths($path, string $excluded = null, string $autoloadType = 'classmap', ?string $namespace = null): void + public function scanPaths($path, ?string $excluded = null, string $autoloadType = 'classmap', ?string $namespace = null, array $excludedDirs = []): void { if (!in_array($autoloadType, ['psr-0', 'psr-4', 'classmap'], true)) { throw new \InvalidArgumentException('$autoloadType must be one of: "psr-0", "psr-4" or "classmap"'); @@ -124,7 +131,8 @@ public function scanPaths($path, string $excluded = null, string $autoloadType = ->files() ->followLinks() ->name('/\.(?:'.implode('|', array_map('preg_quote', $this->extensions)).')$/') - ->in($path); + ->in($path) + ->exclude($excludedDirs); } else { throw new \RuntimeException( 'Could not scan for classes inside "'.$path.'" which does not appear to be a file nor a folder' @@ -140,18 +148,21 @@ public function scanPaths($path, string $excluded = null, string $autoloadType = continue; } - if (!self::isAbsolutePath($filePath)) { + $isStreamWrapperPath = Preg::isMatch($this->streamWrappersRegex, $filePath); + if (!self::isAbsolutePath($filePath) && !$isStreamWrapperPath) { $filePath = $cwd . '/' . $filePath; $filePath = self::normalizePath($filePath); } else { - $filePath = Preg::replace('{[\\\\/]{2,}}', '/', $filePath); + $filePath = Preg::replace('{(?getPathname()); } - $realPath = realpath($filePath); + $realPath = $isStreamWrapperPath + ? $filePath + : realpath($filePath); // fallback just in case but this really should not happen if (false === $realPath) { @@ -189,7 +200,7 @@ public function scanPaths($path, string $excluded = null, string $autoloadType = foreach ($classes as $class) { if (!$this->classMap->hasClass($class)) { $this->classMap->addClass($class, $filePath); - } elseif ($filePath !== $this->classMap->getClassPath($class) && !Preg::isMatch('{/(test|fixture|example|stub)s?/}i', strtr($this->classMap->getClassPath($class).' '.$filePath, '\\', '/'))) { + } elseif ($filePath !== $this->classMap->getClassPath($class)) { $this->classMap->addAmbiguousClass($class, $filePath); } } @@ -205,6 +216,8 @@ public function scanPaths($path, string $excluded = null, string $autoloadType = * @param 'psr-0'|'psr-4' $namespaceType * @param string $basePath root directory of given autoload mapping * @return array valid classes + * + * @throws \InvalidArgumentException When namespaceType is neither psr-0 nor psr-4 */ private function filterByNamespace(array $classes, string $filePath, string $baseNamespace, string $namespaceType, string $basePath): array { @@ -216,10 +229,6 @@ private function filterByNamespace(array $classes, string $filePath, string $bas $realSubPath = substr($realSubPath, 0, $dotPosition === false ? PHP_INT_MAX : $dotPosition); foreach ($classes as $class) { - // silently skip if ns doesn't have common root - if ('' !== $baseNamespace && 0 !== strpos($class, $baseNamespace)) { - continue; - } // transform class name to file path and validate if ('psr-0' === $namespaceType) { $namespaceLength = strrpos($class, '\\'); @@ -245,8 +254,16 @@ private function filterByNamespace(array $classes, string $filePath, string $bas } // warn only if no valid classes, else silently skip invalid if (\count($validClasses) === 0) { + $cwd = realpath(self::getCwd()); + if ($cwd === false) { + $cwd = self::getCwd(); + } + $cwd = self::normalizePath($cwd); + $shortPath = Preg::replace('{^'.preg_quote($cwd).'}', '.', self::normalizePath($filePath), 1); + $shortBasePath = Preg::replace('{^'.preg_quote($cwd).'}', '.', self::normalizePath($basePath), 1); + foreach ($rejectedClasses as $class) { - $this->classMap->addPsrViolation("Class $class located in ".Preg::replace('{^'.preg_quote(self::getCwd()).'}', '.', $filePath, 1)." does not comply with $namespaceType autoloading standard. Skipping."); + $this->classMap->addPsrViolation("Class $class located in $shortPath does not comply with $namespaceType autoloading standard (rule: $baseNamespace => $shortBasePath). Skipping.", $class, $filePath); } return []; diff --git a/app/vendor/composer/class-map-generator/src/PhpFileCleaner.php b/app/vendor/composer/class-map-generator/src/PhpFileCleaner.php index 3a74478e4..b6222aad0 100644 --- a/app/vendor/composer/class-map-generator/src/PhpFileCleaner.php +++ b/app/vendor/composer/class-map-generator/src/PhpFileCleaner.php @@ -238,10 +238,11 @@ private function peek(string $char): bool /** * @param non-empty-string $regex - * @param null|array $match + * @param null|array $match + * @param-out array $match */ - private function match(string $regex, array &$match = null): bool + private function match(string $regex, ?array &$match = null): bool { - return Preg::isMatch($regex, $this->contents, $match, 0, $this->index); + return Preg::isMatchStrictGroups($regex, $this->contents, $match, 0, $this->index); } } diff --git a/app/vendor/composer/class-map-generator/src/PhpFileParser.php b/app/vendor/composer/class-map-generator/src/PhpFileParser.php index b678aeee0..5a6875dce 100644 --- a/app/vendor/composer/class-map-generator/src/PhpFileParser.php +++ b/app/vendor/composer/class-map-generator/src/PhpFileParser.php @@ -24,12 +24,15 @@ class PhpFileParser * * @param string $path The file to check * @throws \RuntimeException - * @return array The found classes + * @return list The found classes */ public static function findClasses(string $path): array { $extraTypes = self::getExtraTypes(); + if (!function_exists('php_strip_whitespace')) { + throw new \RuntimeException('Classmap generation relies on the php_strip_whitespace function, but it has been disabled by the disable_functions directive.'); + } // Use @ here instead of Silencer to actively suppress 'unhelpful' output // @link https://github.com/composer/composer/pull/4886 $contents = @php_strip_whitespace($path); @@ -63,8 +66,8 @@ public static function findClasses(string $path): array Preg::matchAll('{ (?: - \b(?])(?Pclass|interface|trait'.$extraTypes.') \s++ (?P[a-zA-Z_\x7f-\xff:][a-zA-Z0-9_\x7f-\xff:\-]*+) - | \b(?])(?Pnamespace) (?P\s++[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\s*+\\\\\s*+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)*+)? \s*+ [\{;] + \b(?])(?Pclass|interface|trait'.$extraTypes.') \s++ (?P[a-zA-Z_\x7f-\xff:][a-zA-Z0-9_\x7f-\xff:\-]*+) + | \b(?])(?Pnamespace) (?P\s++[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\s*+\\\\\s*+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)*+)? \s*+ [\{;] ) }ix', $contents, $matches); @@ -98,7 +101,9 @@ public static function findClasses(string $path): array $name = substr($name, 0, $colonPos); } } - $classes[] = ltrim($namespace . $name, '\\'); + /** @var class-string */ + $className = ltrim($namespace . $name, '\\'); + $classes[] = $className; } } @@ -118,7 +123,10 @@ private static function getExtraTypes(): string $extraTypes .= '|enum'; } - PhpFileCleaner::setTypeConfig(array_merge(['class', 'interface', 'trait'], array_filter(explode('|', $extraTypes)))); + $extraTypesArray = array_filter(explode('|', $extraTypes), function (string $type) { + return $type !== ''; + }); + PhpFileCleaner::setTypeConfig(array_merge(['class', 'interface', 'trait'], $extraTypesArray)); } return $extraTypes; diff --git a/app/vendor/composer/composer/bin/composer b/app/vendor/composer/composer/bin/composer index 8bc77e660..4f6d08f72 100755 --- a/app/vendor/composer/composer/bin/composer +++ b/app/vendor/composer/composer/bin/composer @@ -42,7 +42,12 @@ if (!extension_loaded('iconv') && !extension_loaded('mbstring')) { } if (function_exists('ini_set')) { - @ini_set('display_errors', '1'); + // check if error logging is on, but to an empty destination - for the CLI SAPI, that means stderr + $logsToSapiDefault = ('' === ini_get('error_log') && (bool) ini_get('log_errors')); + // on the CLI SAPI, ensure errors are displayed on stderr, either via display_errors or via error_log + if (PHP_SAPI === 'cli') { + @ini_set('display_errors', $logsToSapiDefault ? '0' : 'stderr'); + } // Set user defined memory limit if ($memoryLimit = getenv('COMPOSER_MEMORY_LIMIT')) { diff --git a/app/vendor/composer/composer/composer.json b/app/vendor/composer/composer/composer.json index 2cbcfa73d..2d6b132de 100644 --- a/app/vendor/composer/composer/composer.json +++ b/app/vendor/composer/composer/composer.json @@ -23,34 +23,34 @@ ], "require": { "php": "^7.2.5 || ^8.0", - "composer/ca-bundle": "^1.0", - "composer/class-map-generator": "^1.0", + "composer/ca-bundle": "^1.5", + "composer/class-map-generator": "^1.4.0", "composer/metadata-minifier": "^1.0", - "composer/semver": "^3.2.5", + "composer/semver": "^3.3", "composer/spdx-licenses": "^1.5.7", "composer/xdebug-handler": "^2.0.2 || ^3.0.3", - "justinrainbow/json-schema": "^5.2.11", + "justinrainbow/json-schema": "^6.3.1", "psr/log": "^1.0 || ^2.0 || ^3.0", "seld/jsonlint": "^1.4", "seld/phar-utils": "^1.2", - "symfony/console": "^5.4.11 || ^6.0.11 || ^7", - "symfony/filesystem": "^5.4 || ^6.0 || ^7", - "symfony/finder": "^5.4 || ^6.0 || ^7", - "symfony/process": "^5.4 || ^6.0 || ^7", - "react/promise": "^2.8 || ^3", - "composer/pcre": "^2.1 || ^3.1", + "symfony/console": "^5.4.35 || ^6.3.12 || ^7.0.3", + "symfony/filesystem": "^5.4.35 || ^6.3.12 || ^7.0.3", + "symfony/finder": "^5.4.35 || ^6.3.12 || ^7.0.3", + "symfony/process": "^5.4.35 || ^6.3.12 || ^7.0.3", + "react/promise": "^2.11 || ^3.2", + "composer/pcre": "^2.2 || ^3.2", "symfony/polyfill-php73": "^1.24", "symfony/polyfill-php80": "^1.24", "symfony/polyfill-php81": "^1.24", "seld/signal-handler": "^2.0" }, "require-dev": { - "symfony/phpunit-bridge": "^6.4.1 || ^7.0.1", - "phpstan/phpstan": "^1.9.3", - "phpstan/phpstan-phpunit": "^1.0", - "phpstan/phpstan-deprecation-rules": "^1", - "phpstan/phpstan-strict-rules": "^1", - "phpstan/phpstan-symfony": "^1.2.10" + "symfony/phpunit-bridge": "^6.4.3 || ^7.0.1", + "phpstan/phpstan": "^1.11.8", + "phpstan/phpstan-phpunit": "^1.4.0", + "phpstan/phpstan-deprecation-rules": "^1.2.0", + "phpstan/phpstan-strict-rules": "^1.6.0", + "phpstan/phpstan-symfony": "^1.4.0" }, "suggest": { "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", @@ -65,7 +65,7 @@ }, "extra": { "branch-alias": { - "dev-main": "2.7-dev" + "dev-main": "2.8-dev" }, "phpstan": { "includes": [ @@ -81,7 +81,13 @@ "autoload-dev": { "psr-4": { "Composer\\Test\\": "tests/Composer/Test/" - } + }, + "exclude-from-classmap": [ + "tests/Composer/Test/Fixtures/", + "tests/Composer/Test/Autoload/Fixtures", + "tests/Composer/Test/Autoload/MinimumVersionSupport", + "tests/Composer/Test/Plugin/Fixtures" + ] }, "bin": [ "bin/composer" diff --git a/app/vendor/composer/composer/composer.lock b/app/vendor/composer/composer/composer.lock index 2f1cd7693..abf0d4e3b 100644 --- a/app/vendor/composer/composer/composer.lock +++ b/app/vendor/composer/composer/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "bbb9ffc97dcec54f38fdc5b4bf9a287d", + "content-hash": "346c859c80684f1cd23f57dc04f917b4", "packages": [ { "name": "composer/ca-bundle", - "version": "1.5.0", + "version": "1.5.7", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "0c5ccfcfea312b5c5a190a21ac5cef93f74baf99" + "reference": "d665d22c417056996c59019579f1967dfe5c1e82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/0c5ccfcfea312b5c5a190a21ac5cef93f74baf99", - "reference": "0c5ccfcfea312b5c5a190a21ac5cef93f74baf99", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/d665d22c417056996c59019579f1967dfe5c1e82", + "reference": "d665d22c417056996c59019579f1967dfe5c1e82", "shasum": "" }, "require": { @@ -27,8 +27,8 @@ }, "require-dev": { "phpstan/phpstan": "^1.10", - "psr/log": "^1.0", - "symfony/phpunit-bridge": "^4.2 || ^5", + "phpunit/phpunit": "^8 || ^9", + "psr/log": "^1.0 || ^2.0 || ^3.0", "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" }, "type": "library", @@ -64,7 +64,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.5.0" + "source": "https://github.com/composer/ca-bundle/tree/1.5.7" }, "funding": [ { @@ -80,20 +80,20 @@ "type": "tidelift" } ], - "time": "2024-03-15T14:00:32+00:00" + "time": "2025-05-26T15:08:54+00:00" }, { "name": "composer/class-map-generator", - "version": "1.1.1", + "version": "1.6.1", "source": { "type": "git", "url": "https://github.com/composer/class-map-generator.git", - "reference": "8286a62d243312ed99b3eee20d5005c961adb311" + "reference": "134b705ddb0025d397d8318a75825fe3c9d1da34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/class-map-generator/zipball/8286a62d243312ed99b3eee20d5005c961adb311", - "reference": "8286a62d243312ed99b3eee20d5005c961adb311", + "url": "https://api.github.com/repos/composer/class-map-generator/zipball/134b705ddb0025d397d8318a75825fe3c9d1da34", + "reference": "134b705ddb0025d397d8318a75825fe3c9d1da34", "shasum": "" }, "require": { @@ -102,12 +102,12 @@ "symfony/finder": "^4.4 || ^5.3 || ^6 || ^7" }, "require-dev": { - "phpstan/phpstan": "^1.6", - "phpstan/phpstan-deprecation-rules": "^1", - "phpstan/phpstan-phpunit": "^1", - "phpstan/phpstan-strict-rules": "^1.1", - "symfony/filesystem": "^5.4 || ^6", - "symfony/phpunit-bridge": "^5" + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-deprecation-rules": "^1 || ^2", + "phpstan/phpstan-phpunit": "^1 || ^2", + "phpstan/phpstan-strict-rules": "^1.1 || ^2", + "phpunit/phpunit": "^8", + "symfony/filesystem": "^5.4 || ^6" }, "type": "library", "extra": { @@ -137,7 +137,7 @@ ], "support": { "issues": "https://github.com/composer/class-map-generator/issues", - "source": "https://github.com/composer/class-map-generator/tree/1.1.1" + "source": "https://github.com/composer/class-map-generator/tree/1.6.1" }, "funding": [ { @@ -153,7 +153,7 @@ "type": "tidelift" } ], - "time": "2024-03-15T12:53:41+00:00" + "time": "2025-03-24T13:50:44+00:00" }, { "name": "composer/metadata-minifier", @@ -226,28 +226,36 @@ }, { "name": "composer/pcre", - "version": "2.1.3", + "version": "2.3.2", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "540af382c97b83c628227d5f87cf56466d476191" + "reference": "ebb81df8f52b40172d14062ae96a06939d80a069" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/540af382c97b83c628227d5f87cf56466d476191", - "reference": "540af382c97b83c628227d5f87cf56466d476191", + "url": "https://api.github.com/repos/composer/pcre/zipball/ebb81df8f52b40172d14062ae96a06939d80a069", + "reference": "ebb81df8f52b40172d14062ae96a06939d80a069", "shasum": "" }, "require": { "php": "^7.2 || ^8.0" }, + "conflict": { + "phpstan/phpstan": "<1.11.10" + }, "require-dev": { - "phpstan/phpstan": "^1.3", - "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^5" + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-strict-rules": "^1 || ^2", + "phpunit/phpunit": "^8 || ^9" }, "type": "library", "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + }, "branch-alias": { "dev-main": "2.x-dev" } @@ -277,7 +285,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/2.1.3" + "source": "https://github.com/composer/pcre/tree/2.3.2" }, "funding": [ { @@ -293,28 +301,28 @@ "type": "tidelift" } ], - "time": "2024-03-19T09:03:05+00:00" + "time": "2024-11-12T16:24:47+00:00" }, { "name": "composer/semver", - "version": "3.4.0", + "version": "3.4.3", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32" + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32", - "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32", + "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", "shasum": "" }, "require": { "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^1.4", - "symfony/phpunit-bridge": "^4.2 || ^5" + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" }, "type": "library", "extra": { @@ -358,7 +366,7 @@ "support": { "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.4.0" + "source": "https://github.com/composer/semver/tree/3.4.3" }, "funding": [ { @@ -374,28 +382,28 @@ "type": "tidelift" } ], - "time": "2023-08-31T09:50:34+00:00" + "time": "2024-09-19T14:15:21+00:00" }, { "name": "composer/spdx-licenses", - "version": "1.5.8", + "version": "1.5.9", "source": { "type": "git", "url": "https://github.com/composer/spdx-licenses.git", - "reference": "560bdcf8deb88ae5d611c80a2de8ea9d0358cc0a" + "reference": "edf364cefe8c43501e21e88110aac10b284c3c9f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/560bdcf8deb88ae5d611c80a2de8ea9d0358cc0a", - "reference": "560bdcf8deb88ae5d611c80a2de8ea9d0358cc0a", + "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/edf364cefe8c43501e21e88110aac10b284c3c9f", + "reference": "edf364cefe8c43501e21e88110aac10b284c3c9f", "shasum": "" }, "require": { "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^0.12.55", - "symfony/phpunit-bridge": "^4.2 || ^5" + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" }, "type": "library", "extra": { @@ -438,7 +446,7 @@ "support": { "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/spdx-licenses/issues", - "source": "https://github.com/composer/spdx-licenses/tree/1.5.8" + "source": "https://github.com/composer/spdx-licenses/tree/1.5.9" }, "funding": [ { @@ -454,20 +462,20 @@ "type": "tidelift" } ], - "time": "2023-11-20T07:44:33+00:00" + "time": "2025-05-12T21:07:07+00:00" }, { "name": "composer/xdebug-handler", - "version": "3.0.4", + "version": "3.0.5", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "4f988f8fdf580d53bdb2d1278fe93d1ed5462255" + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/4f988f8fdf580d53bdb2d1278fe93d1ed5462255", - "reference": "4f988f8fdf580d53bdb2d1278fe93d1ed5462255", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef", "shasum": "" }, "require": { @@ -504,7 +512,7 @@ "support": { "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/3.0.4" + "source": "https://github.com/composer/xdebug-handler/tree/3.0.5" }, "funding": [ { @@ -520,29 +528,34 @@ "type": "tidelift" } ], - "time": "2024-03-26T18:29:49+00:00" + "time": "2024-05-06T16:37:16+00:00" }, { "name": "justinrainbow/json-schema", - "version": "v5.2.13", + "version": "6.4.2", "source": { "type": "git", - "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "fbbe7e5d79f618997bc3332a6f49246036c45793" + "url": "https://github.com/jsonrainbow/json-schema.git", + "reference": "ce1fd2d47799bb60668643bc6220f6278a4c1d02" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/fbbe7e5d79f618997bc3332a6f49246036c45793", - "reference": "fbbe7e5d79f618997bc3332a6f49246036c45793", + "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/ce1fd2d47799bb60668643bc6220f6278a4c1d02", + "reference": "ce1fd2d47799bb60668643bc6220f6278a4c1d02", "shasum": "" }, "require": { - "php": ">=5.3.3" + "ext-json": "*", + "marc-mabe/php-enum": "^4.0", + "php": "^7.2 || ^8.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", + "friendsofphp/php-cs-fixer": "3.3.0", "json-schema/json-schema-test-suite": "1.2.0", - "phpunit/phpunit": "^4.8.35" + "marc-mabe/php-enum-phpstan": "^2.0", + "phpspec/prophecy": "^1.19", + "phpstan/phpstan": "^1.12", + "phpunit/phpunit": "^8.5" }, "bin": [ "bin/validate-json" @@ -550,7 +563,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0.x-dev" + "dev-master": "6.x-dev" } }, "autoload": { @@ -581,16 +594,89 @@ } ], "description": "A library to validate a json schema.", - "homepage": "https://github.com/justinrainbow/json-schema", + "homepage": "https://github.com/jsonrainbow/json-schema", "keywords": [ "json", "schema" ], "support": { - "issues": "https://github.com/justinrainbow/json-schema/issues", - "source": "https://github.com/justinrainbow/json-schema/tree/v5.2.13" + "issues": "https://github.com/jsonrainbow/json-schema/issues", + "source": "https://github.com/jsonrainbow/json-schema/tree/6.4.2" }, - "time": "2023-09-26T02:20:38+00:00" + "time": "2025-06-03T18:27:04+00:00" + }, + { + "name": "marc-mabe/php-enum", + "version": "v4.7.1", + "source": { + "type": "git", + "url": "https://github.com/marc-mabe/php-enum.git", + "reference": "7159809e5cfa041dca28e61f7f7ae58063aae8ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/marc-mabe/php-enum/zipball/7159809e5cfa041dca28e61f7f7ae58063aae8ed", + "reference": "7159809e5cfa041dca28e61f7f7ae58063aae8ed", + "shasum": "" + }, + "require": { + "ext-reflection": "*", + "php": "^7.1 | ^8.0" + }, + "require-dev": { + "phpbench/phpbench": "^0.16.10 || ^1.0.4", + "phpstan/phpstan": "^1.3.1", + "phpunit/phpunit": "^7.5.20 | ^8.5.22 | ^9.5.11", + "vimeo/psalm": "^4.17.0 | ^5.26.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-3.x": "3.2-dev", + "dev-master": "4.7-dev" + } + }, + "autoload": { + "psr-4": { + "MabeEnum\\": "src/" + }, + "classmap": [ + "stubs/Stringable.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Marc Bennewitz", + "email": "dev@mabe.berlin", + "homepage": "https://mabe.berlin/", + "role": "Lead" + } + ], + "description": "Simple and fast implementation of enumerations with native PHP", + "homepage": "https://github.com/marc-mabe/php-enum", + "keywords": [ + "enum", + "enum-map", + "enum-set", + "enumeration", + "enumerator", + "enummap", + "enumset", + "map", + "set", + "type", + "type-hint", + "typehint" + ], + "support": { + "issues": "https://github.com/marc-mabe/php-enum/issues", + "source": "https://github.com/marc-mabe/php-enum/tree/v4.7.1" + }, + "time": "2024-11-28T04:54:44+00:00" }, { "name": "psr/container", @@ -692,16 +778,16 @@ }, { "name": "react/promise", - "version": "v3.1.0", + "version": "v3.2.0", "source": { "type": "git", "url": "https://github.com/reactphp/promise.git", - "reference": "e563d55d1641de1dea9f5e84f3cccc66d2bfe02c" + "reference": "8a164643313c71354582dc850b42b33fa12a4b63" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/promise/zipball/e563d55d1641de1dea9f5e84f3cccc66d2bfe02c", - "reference": "e563d55d1641de1dea9f5e84f3cccc66d2bfe02c", + "url": "https://api.github.com/repos/reactphp/promise/zipball/8a164643313c71354582dc850b42b33fa12a4b63", + "reference": "8a164643313c71354582dc850b42b33fa12a4b63", "shasum": "" }, "require": { @@ -753,7 +839,7 @@ ], "support": { "issues": "https://github.com/reactphp/promise/issues", - "source": "https://github.com/reactphp/promise/tree/v3.1.0" + "source": "https://github.com/reactphp/promise/tree/v3.2.0" }, "funding": [ { @@ -761,27 +847,27 @@ "type": "open_collective" } ], - "time": "2023-11-16T16:21:57+00:00" + "time": "2024-05-24T10:39:05+00:00" }, { "name": "seld/jsonlint", - "version": "1.10.2", + "version": "1.11.0", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "9bb7db07b5d66d90f6ebf542f09fc67d800e5259" + "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/9bb7db07b5d66d90f6ebf542f09fc67d800e5259", - "reference": "9bb7db07b5d66d90f6ebf542f09fc67d800e5259", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/1748aaf847fc731cfad7725aec413ee46f0cc3a2", + "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2", "shasum": "" }, "require": { "php": "^5.3 || ^7.0 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^1.5", + "phpstan/phpstan": "^1.11", "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^8.5.13" }, "bin": [ @@ -813,7 +899,7 @@ ], "support": { "issues": "https://github.com/Seldaek/jsonlint/issues", - "source": "https://github.com/Seldaek/jsonlint/tree/1.10.2" + "source": "https://github.com/Seldaek/jsonlint/tree/1.11.0" }, "funding": [ { @@ -825,7 +911,7 @@ "type": "tidelift" } ], - "time": "2024-02-07T12:57:50+00:00" + "time": "2024-07-11T14:55:45+00:00" }, { "name": "seld/phar-utils", @@ -938,16 +1024,16 @@ }, { "name": "symfony/console", - "version": "v5.4.36", + "version": "v5.4.47", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "39f75d9d73d0c11952fdcecf4877b4d0f62a8f6e" + "reference": "c4ba980ca61a9eb18ee6bcc73f28e475852bb1ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/39f75d9d73d0c11952fdcecf4877b4d0f62a8f6e", - "reference": "39f75d9d73d0c11952fdcecf4877b4d0f62a8f6e", + "url": "https://api.github.com/repos/symfony/console/zipball/c4ba980ca61a9eb18ee6bcc73f28e475852bb1ed", + "reference": "c4ba980ca61a9eb18ee6bcc73f28e475852bb1ed", "shasum": "" }, "require": { @@ -1017,7 +1103,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.36" + "source": "https://github.com/symfony/console/tree/v5.4.47" }, "funding": [ { @@ -1033,20 +1119,20 @@ "type": "tidelift" } ], - "time": "2024-02-20T16:33:57+00:00" + "time": "2024-11-06T11:30:55+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v2.5.3", + "version": "v2.5.4", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "80d075412b557d41002320b96a096ca65aa2c98d" + "reference": "605389f2a7e5625f273b53960dc46aeaf9c62918" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/80d075412b557d41002320b96a096ca65aa2c98d", - "reference": "80d075412b557d41002320b96a096ca65aa2c98d", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/605389f2a7e5625f273b53960dc46aeaf9c62918", + "reference": "605389f2a7e5625f273b53960dc46aeaf9c62918", "shasum": "" }, "require": { @@ -1054,12 +1140,12 @@ }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { "dev-main": "2.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -1084,7 +1170,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.3" + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.4" }, "funding": [ { @@ -1100,20 +1186,20 @@ "type": "tidelift" } ], - "time": "2023-01-24T14:02:46+00:00" + "time": "2024-09-25T14:11:13+00:00" }, { "name": "symfony/filesystem", - "version": "v5.4.38", + "version": "v5.4.45", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "899330a01056077271e2f614c7b28b0379a671eb" + "reference": "57c8294ed37d4a055b77057827c67f9558c95c54" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/899330a01056077271e2f614c7b28b0379a671eb", - "reference": "899330a01056077271e2f614c7b28b0379a671eb", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/57c8294ed37d4a055b77057827c67f9558c95c54", + "reference": "57c8294ed37d4a055b77057827c67f9558c95c54", "shasum": "" }, "require": { @@ -1122,6 +1208,9 @@ "symfony/polyfill-mbstring": "~1.8", "symfony/polyfill-php80": "^1.16" }, + "require-dev": { + "symfony/process": "^5.4|^6.4" + }, "type": "library", "autoload": { "psr-4": { @@ -1148,7 +1237,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.4.38" + "source": "https://github.com/symfony/filesystem/tree/v5.4.45" }, "funding": [ { @@ -1164,20 +1253,20 @@ "type": "tidelift" } ], - "time": "2024-03-21T08:05:07+00:00" + "time": "2024-10-22T13:05:35+00:00" }, { "name": "symfony/finder", - "version": "v5.4.35", + "version": "v5.4.45", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "abe6d6f77d9465fed3cd2d029b29d03b56b56435" + "reference": "63741784cd7b9967975eec610b256eed3ede022b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/abe6d6f77d9465fed3cd2d029b29d03b56b56435", - "reference": "abe6d6f77d9465fed3cd2d029b29d03b56b56435", + "url": "https://api.github.com/repos/symfony/finder/zipball/63741784cd7b9967975eec610b256eed3ede022b", + "reference": "63741784cd7b9967975eec610b256eed3ede022b", "shasum": "" }, "require": { @@ -1211,7 +1300,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v5.4.35" + "source": "https://github.com/symfony/finder/tree/v5.4.45" }, "funding": [ { @@ -1227,24 +1316,24 @@ "type": "tidelift" } ], - "time": "2024-01-23T13:51:25+00:00" + "time": "2024-09-28T13:32:08+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.29.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4" + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4", - "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-ctype": "*" @@ -1255,8 +1344,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -1290,7 +1379,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0" }, "funding": [ { @@ -1306,24 +1395,24 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.29.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f" + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/32a9da87d7b3245e09ac426c83d334ae9f06f80f", - "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" @@ -1331,8 +1420,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -1368,7 +1457,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0" }, "funding": [ { @@ -1384,24 +1473,24 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.29.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "bc45c394692b948b4d383a08d7753968bed9a83d" + "reference": "3833d7255cc303546435cb650316bff708a1c75c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d", - "reference": "bc45c394692b948b4d383a08d7753968bed9a83d", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" @@ -1409,8 +1498,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -1449,7 +1538,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0" }, "funding": [ { @@ -1465,24 +1554,25 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.29.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec" + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec", - "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", "shasum": "" }, "require": { - "php": ">=7.1" + "ext-iconv": "*", + "php": ">=7.2" }, "provide": { "ext-mbstring": "*" @@ -1493,8 +1583,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -1529,7 +1619,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0" }, "funding": [ { @@ -1545,30 +1635,30 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-12-23T08:48:59+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.29.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "21bd091060673a1177ae842c0ef8fe30893114d2" + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/21bd091060673a1177ae842c0ef8fe30893114d2", - "reference": "21bd091060673a1177ae842c0ef8fe30893114d2", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f68c03565dcaaf25a890667542e8bd75fe7e5bb", + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -1605,7 +1695,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.32.0" }, "funding": [ { @@ -1621,30 +1711,30 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.29.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b" + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", - "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -1685,7 +1775,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.32.0" }, "funding": [ { @@ -1701,30 +1791,30 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2025-01-02T08:10:11+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.29.0", + "version": "v1.32.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "c565ad1e63f30e7477fc40738343c62b40bc672d" + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/c565ad1e63f30e7477fc40738343c62b40bc672d", - "reference": "c565ad1e63f30e7477fc40738343c62b40bc672d", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -1761,7 +1851,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.32.0" }, "funding": [ { @@ -1777,20 +1867,20 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/process", - "version": "v5.4.36", + "version": "v5.4.47", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "4fdf34004f149cc20b2f51d7d119aa500caad975" + "reference": "5d1662fb32ebc94f17ddb8d635454a776066733d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/4fdf34004f149cc20b2f51d7d119aa500caad975", - "reference": "4fdf34004f149cc20b2f51d7d119aa500caad975", + "url": "https://api.github.com/repos/symfony/process/zipball/5d1662fb32ebc94f17ddb8d635454a776066733d", + "reference": "5d1662fb32ebc94f17ddb8d635454a776066733d", "shasum": "" }, "require": { @@ -1823,7 +1913,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.36" + "source": "https://github.com/symfony/process/tree/v5.4.47" }, "funding": [ { @@ -1839,20 +1929,20 @@ "type": "tidelift" } ], - "time": "2024-02-12T15:49:53+00:00" + "time": "2024-11-06T11:36:42+00:00" }, { "name": "symfony/service-contracts", - "version": "v2.5.3", + "version": "v2.5.4", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "a2329596ddc8fd568900e3fc76cba42489ecc7f3" + "reference": "f37b419f7aea2e9abf10abd261832cace12e3300" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/a2329596ddc8fd568900e3fc76cba42489ecc7f3", - "reference": "a2329596ddc8fd568900e3fc76cba42489ecc7f3", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f37b419f7aea2e9abf10abd261832cace12e3300", + "reference": "f37b419f7aea2e9abf10abd261832cace12e3300", "shasum": "" }, "require": { @@ -1868,12 +1958,12 @@ }, "type": "library", "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, "branch-alias": { "dev-main": "2.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" } }, "autoload": { @@ -1906,7 +1996,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.5.3" + "source": "https://github.com/symfony/service-contracts/tree/v2.5.4" }, "funding": [ { @@ -1922,20 +2012,20 @@ "type": "tidelift" } ], - "time": "2023-04-21T15:04:16+00:00" + "time": "2024-09-25T14:11:13+00:00" }, { "name": "symfony/string", - "version": "v5.4.36", + "version": "v5.4.47", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "4e232c83622bd8cd32b794216aa29d0d266d353b" + "reference": "136ca7d72f72b599f2631aca474a4f8e26719799" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/4e232c83622bd8cd32b794216aa29d0d266d353b", - "reference": "4e232c83622bd8cd32b794216aa29d0d266d353b", + "url": "https://api.github.com/repos/symfony/string/zipball/136ca7d72f72b599f2631aca474a4f8e26719799", + "reference": "136ca7d72f72b599f2631aca474a4f8e26719799", "shasum": "" }, "require": { @@ -1992,7 +2082,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.36" + "source": "https://github.com/symfony/string/tree/v5.4.47" }, "funding": [ { @@ -2008,22 +2098,22 @@ "type": "tidelift" } ], - "time": "2024-02-01T08:49:30+00:00" + "time": "2024-11-10T20:33:58+00:00" } ], "packages-dev": [ { "name": "phpstan/phpstan", - "version": "1.10.67", + "version": "1.12.27", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "16ddbe776f10da6a95ebd25de7c1dbed397dc493" + "reference": "3a6e423c076ab39dfedc307e2ac627ef579db162" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/16ddbe776f10da6a95ebd25de7c1dbed397dc493", - "reference": "16ddbe776f10da6a95ebd25de7c1dbed397dc493", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/3a6e423c076ab39dfedc307e2ac627ef579db162", + "reference": "3a6e423c076ab39dfedc307e2ac627ef579db162", "shasum": "" }, "require": { @@ -2068,29 +2158,28 @@ "type": "github" } ], - "time": "2024-04-16T07:22:02+00:00" + "time": "2025-05-21T20:51:45+00:00" }, { "name": "phpstan/phpstan-deprecation-rules", - "version": "1.1.4", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-deprecation-rules.git", - "reference": "089d8a8258ed0aeefdc7b68b6c3d25572ebfdbaa" + "reference": "f94d246cc143ec5a23da868f8f7e1393b50eaa82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-deprecation-rules/zipball/089d8a8258ed0aeefdc7b68b6c3d25572ebfdbaa", - "reference": "089d8a8258ed0aeefdc7b68b6c3d25572ebfdbaa", + "url": "https://api.github.com/repos/phpstan/phpstan-deprecation-rules/zipball/f94d246cc143ec5a23da868f8f7e1393b50eaa82", + "reference": "f94d246cc143ec5a23da868f8f7e1393b50eaa82", "shasum": "" }, "require": { "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.10.3" + "phpstan/phpstan": "^1.12" }, "require-dev": { "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpstan-php-parser": "^1.1", "phpstan/phpstan-phpunit": "^1.0", "phpunit/phpunit": "^9.5" }, @@ -2114,27 +2203,27 @@ "description": "PHPStan rules for detecting usage of deprecated classes, methods, properties, constants and traits.", "support": { "issues": "https://github.com/phpstan/phpstan-deprecation-rules/issues", - "source": "https://github.com/phpstan/phpstan-deprecation-rules/tree/1.1.4" + "source": "https://github.com/phpstan/phpstan-deprecation-rules/tree/1.2.1" }, - "time": "2023-08-05T09:02:04+00:00" + "time": "2024-09-11T15:52:35+00:00" }, { "name": "phpstan/phpstan-phpunit", - "version": "1.3.16", + "version": "1.4.2", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-phpunit.git", - "reference": "d5242a59d035e46774f2e634b374bc39ff62cb95" + "reference": "72a6721c9b64b3e4c9db55abbc38f790b318267e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/d5242a59d035e46774f2e634b374bc39ff62cb95", - "reference": "d5242a59d035e46774f2e634b374bc39ff62cb95", + "url": "https://api.github.com/repos/phpstan/phpstan-phpunit/zipball/72a6721c9b64b3e4c9db55abbc38f790b318267e", + "reference": "72a6721c9b64b3e4c9db55abbc38f790b318267e", "shasum": "" }, "require": { "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.10" + "phpstan/phpstan": "^1.12" }, "conflict": { "phpunit/phpunit": "<7.0" @@ -2166,27 +2255,27 @@ "description": "PHPUnit extensions and rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-phpunit/issues", - "source": "https://github.com/phpstan/phpstan-phpunit/tree/1.3.16" + "source": "https://github.com/phpstan/phpstan-phpunit/tree/1.4.2" }, - "time": "2024-02-23T09:51:20+00:00" + "time": "2024-12-17T17:20:49+00:00" }, { "name": "phpstan/phpstan-strict-rules", - "version": "1.5.5", + "version": "1.6.2", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-strict-rules.git", - "reference": "2e193a07651a6f4be3baa44ddb21d822681f5918" + "reference": "b564ca479e7e735f750aaac4935af965572a7845" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/2e193a07651a6f4be3baa44ddb21d822681f5918", - "reference": "2e193a07651a6f4be3baa44ddb21d822681f5918", + "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/b564ca479e7e735f750aaac4935af965572a7845", + "reference": "b564ca479e7e735f750aaac4935af965572a7845", "shasum": "" }, "require": { "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.10.60" + "phpstan/phpstan": "^1.12.4" }, "require-dev": { "nikic/php-parser": "^4.13.0", @@ -2215,28 +2304,28 @@ "description": "Extra strict and opinionated rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-strict-rules/issues", - "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.5.5" + "source": "https://github.com/phpstan/phpstan-strict-rules/tree/1.6.2" }, - "time": "2024-04-19T15:12:26+00:00" + "time": "2025-01-19T13:02:24+00:00" }, { "name": "phpstan/phpstan-symfony", - "version": "1.3.12", + "version": "1.4.15", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan-symfony.git", - "reference": "f4b9407fa3203aebafd422ae8f0eb1ef94659a80" + "reference": "78b6b5a62f56731d938031c8f59817ed83b2328a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/f4b9407fa3203aebafd422ae8f0eb1ef94659a80", - "reference": "f4b9407fa3203aebafd422ae8f0eb1ef94659a80", + "url": "https://api.github.com/repos/phpstan/phpstan-symfony/zipball/78b6b5a62f56731d938031c8f59817ed83b2328a", + "reference": "78b6b5a62f56731d938031c8f59817ed83b2328a", "shasum": "" }, "require": { "ext-simplexml": "*", "php": "^7.2 || ^8.0", - "phpstan/phpstan": "^1.10.62" + "phpstan/phpstan": "^1.12" }, "conflict": { "symfony/framework-bundle": "<3.0" @@ -2287,22 +2376,22 @@ "description": "Symfony Framework extensions and rules for PHPStan", "support": { "issues": "https://github.com/phpstan/phpstan-symfony/issues", - "source": "https://github.com/phpstan/phpstan-symfony/tree/1.3.12" + "source": "https://github.com/phpstan/phpstan-symfony/tree/1.4.15" }, - "time": "2024-04-14T13:30:23+00:00" + "time": "2025-03-28T12:01:24+00:00" }, { "name": "symfony/phpunit-bridge", - "version": "v7.0.6", + "version": "v7.3.0", "source": { "type": "git", "url": "https://github.com/symfony/phpunit-bridge.git", - "reference": "a014167aa1f66cb9990675840da65609d3e61612" + "reference": "2eabda563921f21cbce1d1e3247b3c36568905e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/a014167aa1f66cb9990675840da65609d3e61612", - "reference": "a014167aa1f66cb9990675840da65609d3e61612", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/2eabda563921f21cbce1d1e3247b3c36568905e6", + "reference": "2eabda563921f21cbce1d1e3247b3c36568905e6", "shasum": "" }, "require": { @@ -2322,8 +2411,8 @@ "type": "symfony-bridge", "extra": { "thanks": { - "name": "phpunit/phpunit", - "url": "https://github.com/sebastianbergmann/phpunit" + "url": "https://github.com/sebastianbergmann/phpunit", + "name": "phpunit/phpunit" } }, "autoload": { @@ -2334,7 +2423,8 @@ "Symfony\\Bridge\\PhpUnit\\": "" }, "exclude-from-classmap": [ - "/Tests/" + "/Tests/", + "/bin/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -2354,7 +2444,7 @@ "description": "Provides utilities for PHPUnit, especially user deprecation notices management", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/phpunit-bridge/tree/v7.0.6" + "source": "https://github.com/symfony/phpunit-bridge/tree/v7.3.0" }, "funding": [ { @@ -2370,18 +2460,18 @@ "type": "tidelift" } ], - "time": "2024-03-19T11:57:22+00:00" + "time": "2025-05-23T07:26:30+00:00" } ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { "php": "^7.2.5 || ^8.0" }, - "platform-dev": [], + "platform-dev": {}, "platform-overrides": { "php": "7.2.5" }, diff --git a/app/vendor/composer/composer/res/composer-lock-schema.json b/app/vendor/composer/composer/res/composer-lock-schema.json new file mode 100644 index 000000000..b1ef31c2b --- /dev/null +++ b/app/vendor/composer/composer/res/composer-lock-schema.json @@ -0,0 +1,101 @@ +{ + "$schema": "https://json-schema.org/draft-04/schema#", + "title": "Composer Lock File", + "type": "object", + "required": [ "content-hash", "packages", "packages-dev" ], + "additionalProperties": true, + "properties": { + "_readme": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Informational text for humans reading the file" + }, + "content-hash": { + "type": "string", + "description": "Hash of all relevant properties of the composer.json that was used to create this lock file." + }, + "packages": { + "type": "array", + "description": "An array of packages that are required.", + "items": { + "$ref": "./composer-schema.json", + "required": ["name", "version"] + } + }, + "packages-dev": { + "type": "array", + "description": "An array of packages that are required in require-dev.", + "items": { + "$ref": "./composer-schema.json" + } + }, + "aliases": { + "type": "array", + "description": "Inline aliases defined in the root package.", + "items": { + "type": "object", + "required": [ "package", "version", "alias", "alias_normalized" ], + "properties": { + "package": { + "type": "string" + }, + "version": { + "type": "string" + }, + "alias": { + "type": "string" + }, + "alias_normalized": { + "type": "string" + } + } + } + }, + "minimum-stability": { + "type": "string", + "description": "The minimum-stability used to generate this lock file." + }, + "stability-flags": { + "type": "object", + "description": "Root package stability flags changing the minimum-stability for specific packages.", + "additionalProperties": { + "type": "integer" + } + }, + "prefer-stable": { + "type": "boolean", + "description": "Whether the --prefer-stable flag was used when building this lock file." + }, + "prefer-lowest": { + "type": "boolean", + "description": "Whether the --prefer-lowest flag was used when building this lock file." + }, + "platform": { + "type": "object", + "description": "Platform requirements of the root package.", + "additionalProperties": { + "type": "string" + } + }, + "platform-dev": { + "type": "object", + "description": "Platform dev-requirements of the root package.", + "additionalProperties": { + "type": "string" + } + }, + "platform-overrides": { + "type": "object", + "description": "Platform config overrides of the root package.", + "additionalProperties": { + "type": "string" + } + }, + "plugin-api-version": { + "type": "string", + "description": "The composer-plugin-api version that was used to generate this lock file." + } + } +} diff --git a/app/vendor/composer/composer/res/composer-repository-schema.json b/app/vendor/composer/composer/res/composer-repository-schema.json index adcc299d6..223f63abf 100644 --- a/app/vendor/composer/composer/res/composer-repository-schema.json +++ b/app/vendor/composer/composer/res/composer-repository-schema.json @@ -1,11 +1,12 @@ { "$schema": "https://json-schema.org/draft-04/schema#", - "description": "A representation of packages metadata.", + "title": "Composer Package Repository", "type": "object", "oneOf": [ { "required": [ "packages" ] }, { "required": [ "providers" ] }, - { "required": [ "provider-includes", "providers-url" ] } + { "required": [ "provider-includes", "providers-url" ] }, + { "required": [ "metadata-url" ] } ], "properties": { "packages": { @@ -13,31 +14,124 @@ "description": "A hashmap of package names in the form of /.", "additionalProperties": { "$ref": "#/definitions/versions" } }, + "metadata-url": { + "type": "string", + "description": "Endpoint to retrieve package metadata data from, in Composer v2 format, e.g. '/p2/%package%.json'." + }, + "available-packages": { + "type": "array", + "items": { + "type": "string" + }, + "description": "If your repository only has a small number of packages, and you want to avoid serving many 404s, specify all the package names that your repository contains here." + }, + "available-package-patterns": { + "type": "array", + "items": { + "type": "string" + }, + "description": "If your repository only has a small number of packages, and you want to avoid serving many 404s, specify package name patterns containing wildcards (*) that your repository contains here." + }, + "security-advisories": { + "type": "array", + "items": { + "type": "object", + "required": ["metadata", "api-url"], + "properties": { + "metadata": { + "type": "boolean", + "description": "Whether metadata files contain security advisory data or whether it should always be queried using the API URL." + }, + "api-url": { + "type": "string", + "description": "Endpoint to call to retrieve security advisories data." + } + } + } + }, + "metadata-changes-url": { + "type": "string", + "description": "Endpoint to retrieve package metadata updates from. This should receive a timestamp since last call to be able to return new changes. e.g. '/metadata/changes.json'." + }, + "providers-api": { + "type": "string", + "description": "Endpoint to retrieve package names providing a given name from, e.g. '/providers/%package%.json'." + }, + "notify-batch": { + "type": "string", + "description": "Endpoint to call after multiple packages have been installed, e.g. '/downloads/'." + }, + "search": { + "type": "string", + "description": "Endpoint that provides search capabilities, e.g. '/search.json?q=%query%&type=%type%'." + }, + "list": { + "type": "string", + "description": "Endpoint that provides a full list of packages present in the repository. It should accept an optional `?filter=xx` query param, which can contain `*` as wildcards matching any substring. e.g. '/list.json'." + }, + "warnings": { + "type": "array", + "items": { + "type": "object", + "required": ["message", "versions"], + "properties": { + "message": { + "type": "string", + "description": "A message that will be output by Composer as a warning when this source is consulted." + }, + "versions": { + "type": "string", + "description": "A version constraint to limit to which Composer versions the warning should be shown." + } + } + } + }, + "infos": { + "type": "array", + "items": { + "type": "object", + "required": ["message", "versions"], + "properties": { + "message": { + "type": "string", + "description": "A message that will be output by Composer as info when this source is consulted." + }, + "versions": { + "type": "string", + "description": "A version constraint to limit to which Composer versions the info should be shown." + } + } + } + }, "providers-url": { "type": "string", - "description": "Endpoint to retrieve provider data from, e.g. '/p/%package%$%hash%.json'." + "description": "DEPRECATED: Endpoint to retrieve provider data from, e.g. '/p/%package%$%hash%.json'." }, "provider-includes": { "type": "object", - "description": "A hashmap of provider listings.", + "description": "DEPRECATED: A hashmap of provider listings.", "additionalProperties": { "$ref": "#/definitions/provider" } }, "providers": { "type": "object", - "description": "A hashmap of package names in the form of /.", + "description": "DEPRECATED: A hashmap of package names in the form of /.", "additionalProperties": { "$ref": "#/definitions/provider" } }, - "notify-batch": { + "warning": { "type": "string", - "description": "Endpoint to call after multiple packages have been installed, e.g. '/downloads/'." + "description": "DEPRECATED: A message that will be output by Composer as a warning when this source is consulted." }, - "search": { + "warning-versions": { "type": "string", - "description": "Endpoint that provides search capabilities, e.g. '/search.json?q=%query%&type=%type%'." + "description": "DEPRECATED: A version constraint to limit to which Composer versions the warning should be shown." }, - "warning": { + "info": { + "type": "string", + "description": "DEPRECATED: A message that will be output by Composer as a info when this source is consulted." + }, + "info-versions": { "type": "string", - "description": "A message that will be output by Composer as a warning when this source is consulted." + "description": "DEPRECATED: A version constraint to limit to which Composer versions the info should be shown." } }, "definitions": { diff --git a/app/vendor/composer/composer/res/composer-schema.json b/app/vendor/composer/composer/res/composer-schema.json index 90714875c..d8728e973 100644 --- a/app/vendor/composer/composer/res/composer-schema.json +++ b/app/vendor/composer/composer/res/composer-schema.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft-04/schema#", - "title": "Package", + "title": "Composer Package", "type": "object", "properties": { "name": { @@ -28,7 +28,7 @@ "version": { "type": "string", "description": "Package version, see https://getcomposer.org/doc/04-schema.md#version for more info on valid schemes.", - "pattern": "^v?\\d+(\\.\\d+){0,3}|^dev-" + "pattern": "^[vV]?\\d+(?:[.-]\\d+){0,3}[._-]?(?:(?:[sS][tT][aA][bB][lL][eE]|[bB][eE][tT][aA]|[bB]|[rR][cC]|[aA][lL][pP][hH][aA]|[aA]|[pP][aA][tT][cC][hH]|[pP][lL]|[pP])(?:(?:[.-]?\\d+)*)?)?(?:[.-]?[dD][eE][vV]|\\.x-dev)?(?:\\+.*)?$|^dev-.*$" }, "default-branch": { "type": ["boolean"], @@ -311,6 +311,44 @@ "example": false, "default": true }, + "support-nts": { + "type": "boolean", + "description": "Does this package support non-Thread Safe mode", + "example": false, + "default": true + }, + "build-path": { + "type": ["string", "null"], + "description": "If specified, this is the subdirectory that will be used to build the extension instead of the root of the project.", + "example": "my-extension-source", + "default": null + }, + "download-url-method": { + "type": "string", + "description": "If specified, this technique will be used to override the URL that PIE uses to download the asset. The default, if not specified, is composer-default.", + "enum": ["composer-default", "pre-packaged-source"], + "example": "composer-default" + }, + "os-families": { + "type": "array", + "minItems": 1, + "description": "An array of OS families to mark as compatible with the extension. Specifying this property will mean this package is not installable with PIE on any OS family not listed here. Must not be specified alongside os-families-exclude.", + "items": { + "type": "string", + "enum": ["windows", "bsd", "darwin", "solaris", "linux", "unknown"], + "description": "The name of the OS family to mark as compatible." + } + }, + "os-families-exclude": { + "type": "array", + "minItems": 1, + "description": "An array of OS families to mark as incompatible with the extension. Specifying this property will mean this package is installable on any OS family except those listed here. Must not be specified alongside os-families.", + "items": { + "type": "string", + "enum": ["windows", "bsd", "darwin", "solaris", "linux", "unknown"], + "description": "The name of the OS family to exclude." + } + }, "configure-options": { "type": "array", "description": "These configure options make up the flags that can be passed to ./configure when installing the extension.", @@ -324,6 +362,12 @@ "example": "without-xdebug-compression", "pattern": "^[a-zA-Z0-9][a-zA-Z0-9-_]*$" }, + "needs-value": { + "type": "boolean", + "description": "If this is set to true, the flag needs a value (e.g. --with-somelib=), otherwise it is a flag without a value (e.g. --enable-some-feature).", + "example": false, + "default": false + }, "description": { "type": "string", "description": "The description of what the flag does or means.", @@ -332,7 +376,14 @@ } } } - } + }, + "allOf": [ + { + "not": { + "required": ["os-families", "os-families-exclude"] + } + } + ] }, "config": { "type": "object", @@ -656,6 +707,14 @@ "platform-check": { "type": ["boolean", "string"], "description": "Defaults to \"php-only\" which checks only the PHP version. Setting to true will also check the presence of required PHP extensions. If set to false, Composer will not create and require a platform_check.php file as part of the autoloader bootstrap." + }, + "bump-after-update": { + "type": ["string", "boolean"], + "description": "Defaults to false and can be any of true, false, \"dev\"` or \"no-dev\"`. If set to true, Composer will run the bump command after running the update command. If set to \"dev\" or \"no-dev\" then only the corresponding dependencies will be bumped." + }, + "allow-missing-requirements": { + "type": ["boolean"], + "description": "Defaults to false. If set to true, Composer will allow install when lock file is not up to date with the latest changes in composer.json." } } }, @@ -910,7 +969,10 @@ "options": { "type": "object", "properties": { - "symlink": { "type": ["boolean", "null"] } + "reference": { "type": ["string"], "enum": ["none", "config", "auto"] }, + "symlink": { "type": ["boolean", "null"] }, + "relative": { "type": ["boolean"] }, + "versions": { "type": "object", "additionalProperties": { "type": "string" } } }, "additionalProperties": true } diff --git a/app/vendor/composer/composer/src/Composer/Advisory/Auditor.php b/app/vendor/composer/composer/src/Composer/Advisory/Auditor.php index 38d827dfe..485b33267 100644 --- a/app/vendor/composer/composer/src/Composer/Advisory/Auditor.php +++ b/app/vendor/composer/composer/src/Composer/Advisory/Auditor.php @@ -19,7 +19,6 @@ use Composer\Package\PackageInterface; use Composer\Repository\RepositorySet; use Composer\Util\PackageInfo; -use Composer\Util\Platform; use InvalidArgumentException; use Symfony\Component\Console\Formatter\OutputFormatter; @@ -47,17 +46,30 @@ class Auditor public const ABANDONED_REPORT = 'report'; public const ABANDONED_FAIL = 'fail'; + /** @internal */ + public const ABANDONEDS = [ + self::ABANDONED_IGNORE, + self::ABANDONED_REPORT, + self::ABANDONED_FAIL, + ]; + + /** Values to determine the audit result. */ + public const STATUS_OK = 0; + public const STATUS_VULNERABLE = 1; + public const STATUS_ABANDONED = 2; + /** * @param PackageInterface[] $packages * @param self::FORMAT_* $format The format that will be used to output audit results. * @param bool $warningOnly If true, outputs a warning. If false, outputs an error. * @param string[] $ignoreList List of advisory IDs, remote IDs or CVE IDs that reported but not listed as vulnerabilities. * @param self::ABANDONED_* $abandoned + * @param array $ignoredSeverities List of ignored severity levels * - * @return int Amount of packages with vulnerabilities found + * @return int-mask A bitmask of STATUS_* constants or 0 on success * @throws InvalidArgumentException If no packages are passed in */ - public function audit(IOInterface $io, RepositorySet $repoSet, array $packages, string $format, bool $warningOnly = true, array $ignoreList = [], string $abandoned = self::ABANDONED_FAIL): int + public function audit(IOInterface $io, RepositorySet $repoSet, array $packages, string $format, bool $warningOnly = true, array $ignoreList = [], string $abandoned = self::ABANDONED_FAIL, array $ignoredSeverities = []): int { $allAdvisories = $repoSet->getMatchingSecurityAdvisories($packages, $format === self::FORMAT_SUMMARY); // we need the CVE & remote IDs set to filter ignores correctly so if we have any matches using the optimized codepath above @@ -65,10 +77,10 @@ public function audit(IOInterface $io, RepositorySet $repoSet, array $packages, if (count($allAdvisories) > 0 && $ignoreList !== [] && $format === self::FORMAT_SUMMARY) { $allAdvisories = $repoSet->getMatchingSecurityAdvisories($packages, false); } - ['advisories' => $advisories, 'ignoredAdvisories' => $ignoredAdvisories] = $this->processAdvisories($allAdvisories, $ignoreList); + ['advisories' => $advisories, 'ignoredAdvisories' => $ignoredAdvisories] = $this->processAdvisories($allAdvisories, $ignoreList, $ignoredSeverities); $abandonedCount = 0; - $affectedPackagesCount = 0; + $affectedPackagesCount = count($advisories); if ($abandoned === self::ABANDONED_IGNORE) { $abandonedPackages = []; } else { @@ -78,35 +90,37 @@ public function audit(IOInterface $io, RepositorySet $repoSet, array $packages, } } + $auditBitmask = $this->calculateBitmask(0 < $affectedPackagesCount, 0 < $abandonedCount); + if (self::FORMAT_JSON === $format) { $json = ['advisories' => $advisories]; if ($ignoredAdvisories !== []) { $json['ignored-advisories'] = $ignoredAdvisories; } - $json['abandoned'] = array_reduce($abandonedPackages, static function(array $carry, CompletePackageInterface $package): array { + $json['abandoned'] = array_reduce($abandonedPackages, static function (array $carry, CompletePackageInterface $package): array { $carry[$package->getPrettyName()] = $package->getReplacementPackage(); + return $carry; }, []); $io->write(JsonFile::encode($json)); - return count($advisories) + $abandonedCount; + return $auditBitmask; } $errorOrWarn = $warningOnly ? 'warning' : 'error'; - if (count($advisories) > 0 || count($ignoredAdvisories) > 0) { + if ($affectedPackagesCount > 0 || count($ignoredAdvisories) > 0) { $passes = [ [$ignoredAdvisories, "Found %d ignored security vulnerability advisor%s affecting %d package%s%s"], - // this has to run last to allow $affectedPackagesCount in the return statement to be correct [$advisories, "<$errorOrWarn>Found %d security vulnerability advisor%s affecting %d package%s%s"], ]; foreach ($passes as [$advisoriesToOutput, $message]) { - [$affectedPackagesCount, $totalAdvisoryCount] = $this->countAdvisories($advisoriesToOutput); - if ($affectedPackagesCount > 0) { + [$pkgCount, $totalAdvisoryCount] = $this->countAdvisories($advisoriesToOutput); + if ($pkgCount > 0) { $plurality = $totalAdvisoryCount === 1 ? 'y' : 'ies'; - $pkgPlurality = $affectedPackagesCount === 1 ? '' : 's'; + $pkgPlurality = $pkgCount === 1 ? '' : 's'; $punctuation = $format === 'summary' ? '.' : ':'; - $io->writeError(sprintf($message, $totalAdvisoryCount, $plurality, $affectedPackagesCount, $pkgPlurality, $punctuation)); + $io->writeError(sprintf($message, $totalAdvisoryCount, $plurality, $pkgCount, $pkgPlurality, $punctuation)); $this->outputAdvisories($io, $advisoriesToOutput, $format); } } @@ -122,7 +136,7 @@ public function audit(IOInterface $io, RepositorySet $repoSet, array $packages, $this->outputAbandonedPackages($io, $abandonedPackages, $format); } - return $affectedPackagesCount + $abandonedCount; + return $auditBitmask; } /** @@ -131,7 +145,7 @@ public function audit(IOInterface $io, RepositorySet $repoSet, array $packages, */ private function filterAbandonedPackages(array $packages): array { - return array_filter($packages, static function (PackageInterface $pkg) { + return array_filter($packages, static function (PackageInterface $pkg): bool { return $pkg instanceof CompletePackageInterface && $pkg->isAbandoned(); }); } @@ -139,11 +153,12 @@ private function filterAbandonedPackages(array $packages): array /** * @phpstan-param array> $allAdvisories * @param array|array $ignoreList List of advisory IDs, remote IDs or CVE IDs that reported but not listed as vulnerabilities. + * @param array $ignoredSeverities List of ignored severity levels * @phpstan-return array{advisories: array>, ignoredAdvisories: array>} */ - private function processAdvisories(array $allAdvisories, array $ignoreList): array + private function processAdvisories(array $allAdvisories, array $ignoreList, array $ignoredSeverities): array { - if ($ignoreList === []) { + if ($ignoreList === [] && $ignoredSeverities === []) { return ['advisories' => $allAdvisories, 'ignoredAdvisories' => []]; } @@ -167,6 +182,11 @@ private function processAdvisories(array $allAdvisories, array $ignoreList): arr } if ($advisory instanceof SecurityAdvisory) { + if (in_array($advisory->severity, $ignoredSeverities, true)) { + $isActive = false; + $ignoreReason = "Ignored via --ignore-severity={$advisory->severity}"; + } + if (in_array($advisory->cve, $ignoredIds, true)) { $isActive = false; $ignoreReason = $ignoreList[$advisory->cve] ?? null; @@ -388,4 +408,21 @@ private function getURL(SecurityAdvisory $advisory): string return 'link).'>'.OutputFormatter::escape($advisory->link).''; } + /** + * @return int-mask + */ + private function calculateBitmask(bool $hasVulnerablePackages, bool $hasAbandonedPackages): int + { + $bitmask = self::STATUS_OK; + + if ($hasVulnerablePackages) { + $bitmask |= self::STATUS_VULNERABLE; + } + + if ($hasAbandonedPackages) { + $bitmask |= self::STATUS_ABANDONED; + } + + return $bitmask; + } } diff --git a/app/vendor/composer/composer/src/Composer/Autoload/AutoloadGenerator.php b/app/vendor/composer/composer/src/Composer/Autoload/AutoloadGenerator.php index 844b80207..442228894 100644 --- a/app/vendor/composer/composer/src/Composer/Autoload/AutoloadGenerator.php +++ b/app/vendor/composer/composer/src/Composer/Autoload/AutoloadGenerator.php @@ -34,6 +34,7 @@ use Composer\Util\PackageSorter; use Composer\Json\JsonFile; use Composer\Package\Locker; +use Symfony\Component\Console\Formatter\OutputFormatter; /** * @author Igor Wiedler @@ -173,7 +174,7 @@ public function setPlatformRequirementFilter(PlatformRequirementFilterInterface * @throws \Seld\JsonLint\ParsingException * @throws \RuntimeException */ - public function dump(Config $config, InstalledRepositoryInterface $localRepo, RootPackageInterface $rootPackage, InstallationManager $installationManager, string $targetDir, bool $scanPsrPackages = false, ?string $suffix = null, ?Locker $locker = null) + public function dump(Config $config, InstalledRepositoryInterface $localRepo, RootPackageInterface $rootPackage, InstallationManager $installationManager, string $targetDir, bool $scanPsrPackages = false, ?string $suffix = null, ?Locker $locker = null, bool $strictAmbiguous = false) { if ($this->classMapAuthoritative) { // Force scanPsrPackages when classmap is authoritative @@ -319,7 +320,7 @@ public static function autoload(\$class) EOF; } - $excluded = null; + $excluded = []; if (!empty($autoloads['exclude-from-classmap'])) { $excluded = $autoloads['exclude-from-classmap']; } @@ -348,14 +349,26 @@ public static function autoload(\$class) continue; } - $classMapGenerator->scanPaths($dir, $this->buildExclusionRegex($dir, $excluded), $group['type'], $namespace); + // if the vendor dir is contained within a psr-0/psr-4 dir being scanned we exclude it + if (str_contains($vendorPath, $dir.'/')) { + $exclusionRegex = $this->buildExclusionRegex($dir, array_merge($excluded, [$vendorPath.'/'])); + } else { + $exclusionRegex = $this->buildExclusionRegex($dir, $excluded); + } + + $classMapGenerator->scanPaths($dir, $exclusionRegex, $group['type'], $namespace); } } } } $classMap = $classMapGenerator->getClassMap(); - foreach ($classMap->getAmbiguousClasses() as $className => $ambiguousPaths) { + if ($strictAmbiguous) { + $ambiguousClasses = $classMap->getAmbiguousClasses(false); + } else { + $ambiguousClasses = $classMap->getAmbiguousClasses(); + } + foreach ($ambiguousClasses as $className => $ambiguousPaths) { if (count($ambiguousPaths) > 1) { $this->io->writeError( 'Warning: Ambiguous class resolution, "'.$className.'"'. @@ -368,6 +381,12 @@ public static function autoload(\$class) ); } } + if (\count($ambiguousClasses) > 0) { + $this->io->writeError('To resolve ambiguity in classes not under your control you can ignore them by path using exclude-from-classmap'); + } + + // output PSR violations which are not coming from the vendor dir + $classMap->clearPsrViolationsByPath($vendorPath); foreach ($classMap->getPsrViolations() as $msg) { $this->io->writeError("$msg"); } @@ -400,14 +419,14 @@ public static function autoload(\$class) // carry over existing autoload.php's suffix if possible and none is configured if (null === $suffix && Filesystem::isReadable($vendorPath.'/autoload.php')) { - $content = file_get_contents($vendorPath.'/autoload.php'); + $content = (string) file_get_contents($vendorPath.'/autoload.php'); if (Preg::isMatch('{ComposerAutoloaderInit([^:\s]+)::}', $content, $match)) { $suffix = $match[1]; } } if (null === $suffix) { - $suffix = $locker !== null && $locker->isLocked() ? $locker->getLockData()['content-hash'] : md5(uniqid('', true)); + $suffix = $locker !== null && $locker->isLocked() ? $locker->getLockData()['content-hash'] : bin2hex(random_bytes(16)); } } @@ -460,12 +479,12 @@ public static function autoload(\$class) } /** - * @param array|null $excluded + * @param array $excluded * @return non-empty-string|null */ - private function buildExclusionRegex(string $dir, ?array $excluded): ?string + private function buildExclusionRegex(string $dir, array $excluded): ?string { - if (null === $excluded) { + if ([] === $excluded) { return null; } @@ -559,12 +578,17 @@ public function parseAutoloads(array $packageMap, PackageInterface $rootPackage, } $sortedPackageMap = $this->sortPackageMap($packageMap); $sortedPackageMap[] = $rootPackageMap; - array_unshift($packageMap, $rootPackageMap); + $reverseSortedMap = array_reverse($sortedPackageMap); + + // reverse-sorted means root first, then dependents, then their dependents, etc. + // which makes sense to allow root to override classmap or psr-0/4 entries with higher precedence rules + $psr0 = $this->parseAutoloadsType($reverseSortedMap, 'psr-0', $rootPackage); + $psr4 = $this->parseAutoloadsType($reverseSortedMap, 'psr-4', $rootPackage); + $classmap = $this->parseAutoloadsType($reverseSortedMap, 'classmap', $rootPackage); - $psr0 = $this->parseAutoloadsType($packageMap, 'psr-0', $rootPackage); - $psr4 = $this->parseAutoloadsType($packageMap, 'psr-4', $rootPackage); - $classmap = $this->parseAutoloadsType(array_reverse($sortedPackageMap), 'classmap', $rootPackage); + // sorted (i.e. dependents first) for files to ensure that dependencies are loaded/available once a file is included $files = $this->parseAutoloadsType($sortedPackageMap, 'files', $rootPackage); + // using sorted here but it does not really matter as all are excluded equally $exclude = $this->parseAutoloadsType($sortedPackageMap, 'exclude-from-classmap', $rootPackage); krsort($psr0); @@ -602,7 +626,7 @@ public function createLoader(array $autoloads, ?string $vendorDir = null) } if (isset($autoloads['classmap'])) { - $excluded = null; + $excluded = []; if (!empty($autoloads['exclude-from-classmap'])) { $excluded = $autoloads['exclude-from-classmap']; } @@ -646,11 +670,11 @@ protected function getIncludePathsFile(array $packageMap, Filesystem $filesystem foreach ($package->getIncludePaths() as $includePath) { $includePath = trim($includePath, '/'); - $includePaths[] = empty($installPath) ? $includePath : $installPath.'/'.$includePath; + $includePaths[] = $installPath === '' ? $includePath : $installPath.'/'.$includePath; } } - if (!$includePaths) { + if (\count($includePaths) === 0) { return null; } @@ -741,7 +765,7 @@ protected function getPathCode(Filesystem $filesystem, string $basePath, string } } - if (strpos($path, '.phar') !== false) { + if (Preg::isMatch('{\.phar([\\\\/]|$)}', $path)) { $baseDir = "'phar://' . " . $baseDir; } @@ -913,9 +937,8 @@ protected function getPlatformCheck(array $packageMap, $checkPlatform, array $de echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, \$issues)) . PHP_EOL.PHP_EOL; } } - trigger_error( - 'Composer detected issues in your platform: ' . implode(' ', \$issues), - E_USER_ERROR + throw new \RuntimeException( + 'Composer detected issues in your platform: ' . implode(' ', \$issues) ); } @@ -951,10 +974,7 @@ protected function getAutoloadFile(string $vendorPathToTargetDirCode, string $su echo \$err; } } - trigger_error( - \$err, - E_USER_ERROR - ); + throw new RuntimeException(\$err); } require_once $vendorPathToTargetDirCode; @@ -1042,7 +1062,7 @@ public static function getLoader() } if ($this->apcu) { - $apcuPrefix = var_export(($this->apcuPrefix !== null ? $this->apcuPrefix : substr(base64_encode(md5(uniqid('', true), true)), 0, -3)), true); + $apcuPrefix = var_export(($this->apcuPrefix !== null ? $this->apcuPrefix : bin2hex(random_bytes(10))), true); $file .= <<setApcuPrefix($apcuPrefix); @@ -1231,6 +1251,10 @@ protected function parseAutoloadsType(array $packageMap, string $type, RootPacka } foreach ($autoload[$type] as $namespace => $paths) { + if (in_array($type, ['psr-4', 'psr-0'], true)) { + // normalize namespaces to ensure "\" becomes "" and others do not have leading separators as they are not needed + $namespace = ltrim($namespace, '\\'); + } foreach ((array) $paths as $path) { if (($type === 'files' || $type === 'classmap' || $type === 'exclude-from-classmap') && $package->getTargetDir() && !Filesystem::isReadable($installPath.'/'.$path)) { // remove target-dir from file paths of the root package @@ -1255,10 +1279,8 @@ protected function parseAutoloadsType(array $packageMap, string $type, RootPacka $path = Preg::replaceCallback( '{^((?:(?:\\\\\\.){1,2}+/)+)}', static function ($matches) use (&$updir): string { - if (isset($matches[1])) { - // undo preg_quote for the matched string - $updir = str_replace('\\.', '.', $matches[1]); - } + // undo preg_quote for the matched string + $updir = str_replace('\\.', '.', $matches[1]); return ''; }, @@ -1300,7 +1322,8 @@ static function ($matches) use (&$updir): string { */ protected function getFileIdentifier(PackageInterface $package, string $path) { - return md5($package->getName() . ':' . $path); + // TODO composer v3 change this to sha1 or xxh3? Possibly not worth the potential breakage though + return hash('md5', $package->getName() . ':' . $path); } /** diff --git a/app/vendor/composer/composer/src/Composer/Cache.php b/app/vendor/composer/composer/src/Composer/Cache.php index 1a216c592..e18715f47 100644 --- a/app/vendor/composer/composer/src/Composer/Cache.php +++ b/app/vendor/composer/composer/src/Composer/Cache.php @@ -53,7 +53,7 @@ public function __construct(IOInterface $io, string $cacheDir, string $allowlist $this->root = rtrim($cacheDir, '/\\') . '/'; $this->allowlist = $allowlist; $this->filesystem = $filesystem ?: new Filesystem(); - $this->readOnly = (bool) $readOnly; + $this->readOnly = $readOnly; if (!self::isUsable($cacheDir)) { $this->enabled = false; @@ -65,7 +65,7 @@ public function __construct(IOInterface $io, string $cacheDir, string $allowlist */ public function setReadOnly(bool $readOnly) { - $this->readOnly = (bool) $readOnly; + $this->readOnly = $readOnly; } /** @@ -144,7 +144,7 @@ public function write(string $file, string $contents) $this->io->writeError('Writing '.$this->root . $file.' into cache', true, IOInterface::DEBUG); - $tempFileName = $this->root . $file . uniqid('.', true) . '.tmp'; + $tempFileName = $this->root . $file . bin2hex(random_bytes(5)) . '.tmp'; try { return file_put_contents($tempFileName, $contents) !== false && rename($tempFileName, $this->root . $file); } catch (\ErrorException $e) { @@ -198,7 +198,7 @@ public function copyFrom(string $file, string $source) $this->io->writeError('Writing '.$this->root . $file.' into cache from '.$source); } - return copy($source, $this->root . $file); + return $this->filesystem->copy($source, $this->root . $file); } return false; @@ -224,7 +224,7 @@ public function copyTo(string $file, string $target) $this->io->writeError('Reading '.$this->root . $file.' from cache', true, IOInterface::DEBUG); - return copy($this->root . $file, $target); + return $this->filesystem->copy($this->root . $file, $target); } } @@ -357,7 +357,7 @@ public function sha1(string $file) if ($this->isEnabled()) { $file = Preg::replace('{[^'.$this->allowlist.']}i', '-', $file); if (file_exists($this->root . $file)) { - return sha1_file($this->root . $file); + return hash_file('sha1', $this->root . $file); } } diff --git a/app/vendor/composer/composer/src/Composer/Command/ArchiveCommand.php b/app/vendor/composer/composer/src/Composer/Command/ArchiveCommand.php index e0189109b..b71f4e241 100644 --- a/app/vendor/composer/composer/src/Composer/Command/ArchiveCommand.php +++ b/app/vendor/composer/composer/src/Composer/Command/ArchiveCommand.php @@ -169,7 +169,7 @@ protected function selectPackage(IOInterface $io, string $packageName, ?string $ } if ($version !== null && Preg::isMatchStrictGroups('{@(stable|RC|beta|alpha|dev)$}i', $version, $match)) { - $minStability = $match[1]; + $minStability = VersionParser::normalizeStability($match[1]); $version = (string) substr($version, 0, -strlen($match[0])); } diff --git a/app/vendor/composer/composer/src/Composer/Command/AuditCommand.php b/app/vendor/composer/composer/src/Composer/Command/AuditCommand.php index 1097bb7af..e4a2094b8 100644 --- a/app/vendor/composer/composer/src/Composer/Command/AuditCommand.php +++ b/app/vendor/composer/composer/src/Composer/Command/AuditCommand.php @@ -33,6 +33,8 @@ protected function configure(): void new InputOption('no-dev', null, InputOption::VALUE_NONE, 'Disables auditing of require-dev packages.'), new InputOption('format', 'f', InputOption::VALUE_REQUIRED, 'Output format. Must be "table", "plain", "json", or "summary".', Auditor::FORMAT_TABLE, Auditor::FORMATS), new InputOption('locked', null, InputOption::VALUE_NONE, 'Audit based on the lock file instead of the installed packages.'), + new InputOption('abandoned', null, InputOption::VALUE_REQUIRED, 'Behavior on abandoned packages. Must be "ignore", "report", or "fail".', null, Auditor::ABANDONEDS), + new InputOption('ignore-severity', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Ignore advisories of a certain severity level.', [], ['low', 'medium', 'high', 'critical']), ]) ->setHelp( <<getConfig()->get('audit'); - return min(255, $auditor->audit($this->getIO(), $repoSet, $packages, $this->getAuditFormat($input, 'format'), false, $auditConfig['ignore'] ?? [], $auditConfig['abandoned'] ?? Auditor::ABANDONED_FAIL)); + $abandoned = $input->getOption('abandoned'); + if ($abandoned !== null && !in_array($abandoned, Auditor::ABANDONEDS, true)) { + throw new \InvalidArgumentException('--audit must be one of '.implode(', ', Auditor::ABANDONEDS).'.'); + } + + $abandoned = $abandoned ?? $auditConfig['abandoned'] ?? Auditor::ABANDONED_FAIL; + + $ignoreSeverities = $input->getOption('ignore-severity') ?? []; + + return min(255, $auditor->audit( + $this->getIO(), + $repoSet, + $packages, + $this->getAuditFormat($input, 'format'), + false, + $auditConfig['ignore'] ?? [], + $abandoned, + $ignoreSeverities + )); + } /** diff --git a/app/vendor/composer/composer/src/Composer/Command/BaseCommand.php b/app/vendor/composer/composer/src/Composer/Command/BaseCommand.php index bdfbb0d05..85c99f74b 100644 --- a/app/vendor/composer/composer/src/Composer/Command/BaseCommand.php +++ b/app/vendor/composer/composer/src/Composer/Command/BaseCommand.php @@ -258,6 +258,8 @@ protected function initialize(InputInterface $input, OutputInterface $output) 'COMPOSER_PREFER_STABLE' => ['prefer-stable'], 'COMPOSER_PREFER_LOWEST' => ['prefer-lowest'], 'COMPOSER_MINIMAL_CHANGES' => ['minimal-changes'], + 'COMPOSER_WITH_DEPENDENCIES' => ['with-dependencies'], + 'COMPOSER_WITH_ALL_DEPENDENCIES' => ['with-all-dependencies'], ]; foreach ($envOptions as $envName => $optionNames) { foreach ($optionNames as $optionName) { diff --git a/app/vendor/composer/composer/src/Composer/Command/BaseDependencyCommand.php b/app/vendor/composer/composer/src/Composer/Command/BaseDependencyCommand.php index 2fb363979..1f67f5bc3 100644 --- a/app/vendor/composer/composer/src/Composer/Command/BaseDependencyCommand.php +++ b/app/vendor/composer/composer/src/Composer/Command/BaseDependencyCommand.php @@ -13,6 +13,7 @@ namespace Composer\Command; use Composer\Package\Link; +use Composer\Package\Package; use Composer\Package\PackageInterface; use Composer\Package\CompletePackageInterface; use Composer\Package\RootPackage; @@ -24,6 +25,8 @@ use Composer\Repository\RepositoryFactory; use Composer\Plugin\CommandEvent; use Composer\Plugin\PluginEvents; +use Composer\Semver\Constraint\Bound; +use Composer\Util\Platform; use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\Console\Formatter\OutputFormatterStyle; use Composer\Package\Version\VersionParser; @@ -102,13 +105,30 @@ protected function doExecute(InputInterface $input, OutputInterface $output, boo // If the version we ask for is not installed then we need to locate it in remote repos and add it. // This is needed for why-not to resolve conflicts from an uninstalled version against installed packages. - if (!$installedRepo->findPackage($needle, $textConstraint)) { + $matchedPackage = $installedRepo->findPackage($needle, $textConstraint); + if (!$matchedPackage) { $defaultRepos = new CompositeRepository(RepositoryFactory::defaultRepos($this->getIO(), $composer->getConfig(), $composer->getRepositoryManager())); if ($match = $defaultRepos->findPackage($needle, $textConstraint)) { $installedRepo->addRepository(new InstalledArrayRepository([clone $match])); + } elseif (PlatformRepository::isPlatformPackage($needle)) { + $parser = new VersionParser(); + $constraint = $parser->parseConstraints($textConstraint); + if ($constraint->getLowerBound() !== Bound::zero()) { + $tempPlatformPkg = new Package($needle, $constraint->getLowerBound()->getVersion(), $constraint->getLowerBound()->getVersion()); + $installedRepo->addRepository(new InstalledArrayRepository([$tempPlatformPkg])); + } } else { $this->getIO()->writeError('Package "'.$needle.'" could not be found with constraint "'.$textConstraint.'", results below will most likely be incomplete.'); } + } elseif (PlatformRepository::isPlatformPackage($needle)) { + $extraNotice = ''; + if (($matchedPackage->getExtra()['config.platform'] ?? false) === true) { + $extraNotice = ' (version provided by config.platform)'; + } + $this->getIO()->writeError('Package "'.$needle.' '.$textConstraint.'" found in version "'.$matchedPackage->getPrettyVersion().'"'.$extraNotice.'.'); + } elseif ($inverted) { + $this->getIO()->write('Package "'.$needle.'" '.$matchedPackage->getPrettyVersion().' is already installed! To find out why, run `composer why '.$needle.'`'); + return 0; } // Include replaced packages for inverted lookups as they are then the actual starting point to consider @@ -154,7 +174,7 @@ protected function doExecute(InputInterface $input, OutputInterface $output, boo $this->printTable($output, $results); } - if ($inverted && $input->hasArgument(self::ARGUMENT_CONSTRAINT)) { + if ($inverted && $input->hasArgument(self::ARGUMENT_CONSTRAINT) && !PlatformRepository::isPlatformPackage($needle)) { $composerCommand = 'update'; foreach ($composer->getPackage()->getRequires() as $rootRequirement) { @@ -180,9 +200,9 @@ protected function doExecute(InputInterface $input, OutputInterface $output, boo /** * Assembles and prints a bottom-up table of the dependencies. * - * @param array{PackageInterface, Link, mixed}[] $results + * @param array{PackageInterface, Link, array|false}[] $results */ - protected function printTable(OutputInterface $output, $results): void + protected function printTable(OutputInterface $output, array $results): void { $table = []; $doubles = []; @@ -204,13 +224,13 @@ protected function printTable(OutputInterface $output, $results): void $packageUrl = PackageInfo::getViewSourceOrHomepageUrl($package); $nameWithLink = $packageUrl !== null ? '' . $package->getPrettyName() . '' : $package->getPrettyName(); $rows[] = [$nameWithLink, $version, $link->getDescription(), sprintf('%s (%s)', $link->getTarget(), $link->getPrettyConstraint())]; - if ($children) { + if (is_array($children)) { $queue = array_merge($queue, $children); } } $results = $queue; $table = array_merge($rows, $table); - } while (!empty($results)); + } while (\count($results) > 0); $this->renderTable($table, $output); } @@ -237,7 +257,7 @@ protected function initStyles(OutputInterface $output): void /** * Recursively prints a tree of the selected results. * - * @param array{PackageInterface, Link, mixed[]|bool}[] $results Results to be printed at this level. + * @param array{PackageInterface, Link, array|false}[] $results Results to be printed at this level. * @param string $prefix Prefix of the current tree level. * @param int $level Current level of recursion. */ @@ -258,7 +278,7 @@ protected function printTree(array $results, string $prefix = '', int $level = 1 $linkText = sprintf('%s <%s>%s %s', $link->getDescription(), $prevColor, $link->getTarget(), $link->getPrettyConstraint()); $circularWarn = $children === false ? '(circular dependency aborted here)' : ''; $this->writeTreeLine(rtrim(sprintf("%s%s%s (%s) %s", $prefix, $isLast ? '└──' : '├──', $packageText, $linkText, $circularWarn))); - if ($children) { + if (is_array($children)) { $this->printTree($children, $prefix . ($isLast ? ' ' : '│ '), $level + 1); } } diff --git a/app/vendor/composer/composer/src/Composer/Command/BumpCommand.php b/app/vendor/composer/composer/src/Composer/Command/BumpCommand.php index db5b9464a..4570ce2a3 100644 --- a/app/vendor/composer/composer/src/Composer/Command/BumpCommand.php +++ b/app/vendor/composer/composer/src/Composer/Command/BumpCommand.php @@ -12,6 +12,7 @@ namespace Composer\Command; +use Composer\IO\IOInterface; use Composer\Package\AliasPackage; use Composer\Package\BasePackage; use Composer\Package\Locker; @@ -72,9 +73,28 @@ protected function configure(): void */ protected function execute(InputInterface $input, OutputInterface $output): int { + return $this->doBump( + $this->getIO(), + $input->getOption('dev-only'), + $input->getOption('no-dev-only'), + $input->getOption('dry-run'), + $input->getArgument('packages') + ); + } + + /** + * @param string[] $packagesFilter + * @throws \Seld\JsonLint\ParsingException + */ + public function doBump( + IOInterface $io, + bool $devOnly, + bool $noDevOnly, + bool $dryRun, + array $packagesFilter + ): int { /** @readonly */ $composerJsonPath = Factory::getComposerFile(); - $io = $this->getIO(); if (!Filesystem::isReadable($composerJsonPath)) { $io->writeError(''.$composerJsonPath.' is not readable.'); @@ -112,7 +132,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $repo = $composer->getRepositoryManager()->getLocalRepository(); } - if ($composer->getPackage()->getType() !== 'project' && !$input->getOption('dev-only')) { + if ($composer->getPackage()->getType() !== 'project' && !$devOnly) { $io->writeError('Warning: Bumping dependency constraints is not recommended for libraries as it will narrow down your dependencies and may cause problems for your users.'); $contents = $composerJson->read(); @@ -125,15 +145,18 @@ protected function execute(InputInterface $input, OutputInterface $output): int $bumper = new VersionBumper(); $tasks = []; - if (!$input->getOption('dev-only')) { + if (!$devOnly) { $tasks['require'] = $composer->getPackage()->getRequires(); } - if (!$input->getOption('no-dev-only')) { + if (!$noDevOnly) { $tasks['require-dev'] = $composer->getPackage()->getDevRequires(); } - $packagesFilter = $input->getArgument('packages'); if (count($packagesFilter) > 0) { + // support proxied args from the update command that contain constraints together with the package names + $packagesFilter = array_map(function ($constraint) { + return Preg::replace('{[:= ].+}', '', $constraint); + }, $packagesFilter); $pattern = BasePackage::packageNamesToRegexp(array_unique(array_map('strtolower', $packagesFilter))); foreach ($tasks as $key => $reqs) { foreach ($reqs as $pkgName => $link) { @@ -171,8 +194,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int } } - $dryRun = $input->getOption('dry-run'); - if (!$dryRun && !$this->updateFileCleanly($composerJson, $updates)) { $composerDefinition = $composerJson->read(); foreach ($updates as $key => $packages) { @@ -199,15 +220,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int $io->write('No requirements to update in '.$composerJsonPath.'.'); } - if (!$dryRun && $composer->getLocker()->isLocked() && $changeCount > 0) { - $contents = file_get_contents($composerJson->getPath()); - if (false === $contents) { - throw new \RuntimeException('Unable to read '.$composerJson->getPath().' contents to update the lock file hash.'); - } - $lock = new JsonFile(Factory::getLockFile($composerJsonPath)); - $lockData = $lock->read(); - $lockData['content-hash'] = Locker::getContentHash($contents); - $lock->write($lockData); + if (!$dryRun && $composer->getLocker()->isLocked() && $composer->getConfig()->get('lock') && $changeCount > 0) { + $composer->getLocker()->updateHash($composerJson); } if ($dryRun && $changeCount > 0) { diff --git a/app/vendor/composer/composer/src/Composer/Command/CompletionTrait.php b/app/vendor/composer/composer/src/Composer/Command/CompletionTrait.php index 89c6b68e5..444d69554 100644 --- a/app/vendor/composer/composer/src/Composer/Command/CompletionTrait.php +++ b/app/vendor/composer/composer/src/Composer/Command/CompletionTrait.php @@ -117,6 +117,36 @@ private function suggestInstalledPackage(bool $includeRootPackage = true, bool $ }; } + /** + * Suggest package names from installed. + */ + private function suggestInstalledPackageTypes(bool $includeRootPackage = true): \Closure + { + return function (CompletionInput $input) use ($includeRootPackage): array { + $composer = $this->requireComposer(); + $installedRepos = []; + + if ($includeRootPackage) { + $installedRepos[] = new RootPackageRepository(clone $composer->getPackage()); + } + + $locker = $composer->getLocker(); + if ($locker->isLocked()) { + $installedRepos[] = $locker->getLockedRepository(true); + } else { + $installedRepos[] = $composer->getRepositoryManager()->getLocalRepository(); + } + + $installedRepo = new InstalledRepository($installedRepos); + + return array_values(array_unique( + array_map(static function (PackageInterface $package) { + return $package->getType(); + }, $installedRepo->getPackages()) + )); + }; + } + /** * Suggest package names available on all configured repositories. */ diff --git a/app/vendor/composer/composer/src/Composer/Command/ConfigCommand.php b/app/vendor/composer/composer/src/Composer/Command/ConfigCommand.php index b625cbf1a..de3bd367e 100644 --- a/app/vendor/composer/composer/src/Composer/Command/ConfigCommand.php +++ b/app/vendor/composer/composer/src/Composer/Command/ConfigCommand.php @@ -291,7 +291,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $source = $this->config->getSourceOfValue($settingKey); if (Preg::isMatch('/^repos?(?:itories)?(?:\.(.+))?/', $settingKey, $matches)) { - if (!isset($matches[1]) || $matches[1] === '') { + if (!isset($matches[1])) { $value = $data['repositories'] ?? []; } else { if (!isset($data['repositories'][$matches[1]])) { @@ -469,6 +469,18 @@ static function ($val) { 'prepend-autoloader' => [$booleanValidator, $booleanNormalizer], 'disable-tls' => [$booleanValidator, $booleanNormalizer], 'secure-http' => [$booleanValidator, $booleanNormalizer], + 'bump-after-update' => [ + static function ($val): bool { + return in_array($val, ['dev', 'no-dev', 'true', 'false', '1', '0'], true); + }, + static function ($val) { + if ('dev' === $val || 'no-dev' === $val) { + return $val; + } + + return $val !== 'false' && (bool) $val; + }, + ], 'cafile' => [ static function ($val): bool { return file_exists($val) && Filesystem::isReadable($val); @@ -664,7 +676,7 @@ static function ($vals) { }], 'minimum-stability' => [ static function ($val): bool { - return isset(BasePackage::$stabilities[VersionParser::normalizeStability($val)]); + return isset(BasePackage::STABILITIES[VersionParser::normalizeStability($val)]); }, static function ($val): string { return VersionParser::normalizeStability($val); @@ -1013,7 +1025,7 @@ private function getAuthConfigFile(InputInterface $input, Config $config): strin } /** - * Suggest setting-keys, while taking given options in acount. + * Suggest setting-keys, while taking given options in account. */ private function suggestSettingKeys(): \Closure { diff --git a/app/vendor/composer/composer/src/Composer/Command/CreateProjectCommand.php b/app/vendor/composer/composer/src/Composer/Command/CreateProjectCommand.php index b7e873684..368516fdb 100644 --- a/app/vendor/composer/composer/src/Composer/Command/CreateProjectCommand.php +++ b/app/vendor/composer/composer/src/Composer/Command/CreateProjectCommand.php @@ -319,14 +319,6 @@ public function installProject(IOInterface $io, Config $config, InputInterface $ $composer->getEventDispatcher()->dispatchScript(ScriptEvents::POST_CREATE_PROJECT_CMD, $installDevPackages); chdir($oldCwd); - $vendorComposerDir = $config->get('vendor-dir').'/composer'; - if (is_dir($vendorComposerDir) && $fs->isDirEmpty($vendorComposerDir)) { - Silencer::call('rmdir', $vendorComposerDir); - $vendorDir = $config->get('vendor-dir'); - if (is_dir($vendorDir) && $fs->isDirEmpty($vendorDir)) { - Silencer::call('rmdir', $vendorDir); - } - } return 0; } @@ -338,10 +330,6 @@ public function installProject(IOInterface $io, Config $config, InputInterface $ */ protected function installRootPackage(InputInterface $input, IOInterface $io, Config $config, string $packageName, PlatformRequirementFilterInterface $platformRequirementFilter, ?string $directory = null, ?string $packageVersion = null, ?string $stability = 'stable', bool $preferSource = false, bool $preferDist = false, bool $installDevPackages = false, ?array $repositories = null, bool $disablePlugins = false, bool $disableScripts = false, bool $noProgress = false, bool $secureHttp = true): bool { - if (!$secureHttp) { - $config->merge(['config' => ['secure-http' => false]], Config::SOURCE_COMMAND); - } - $parser = new VersionParser(); $requirements = $parser->parseNameVersionPairs([$packageName]); $name = strtolower($requirements[0]['name']); @@ -354,12 +342,22 @@ protected function installRootPackage(InputInterface $input, IOInterface $io, Co $parts = explode("/", $name, 2); $directory = Platform::getCwd() . DIRECTORY_SEPARATOR . array_pop($parts); } + $directory = rtrim($directory, '/\\'); $process = new ProcessExecutor($io); $fs = new Filesystem($process); if (!$fs->isAbsolutePath($directory)) { $directory = Platform::getCwd() . DIRECTORY_SEPARATOR . $directory; } + if ('' === $directory) { + throw new \UnexpectedValueException('Got an empty target directory, something went wrong'); + } + + // set the base dir to ensure $config->all() below resolves the correct absolute paths to vendor-dir etc + $config->setBaseDir($directory); + if (!$secureHttp) { + $config->merge(['config' => ['secure-http' => false]], Config::SOURCE_COMMAND); + } $io->writeError('Creating a "' . $packageName . '" project at "' . $fs->findShortestPath(Platform::getCwd(), $directory, true) . '"'); @@ -375,7 +373,7 @@ protected function installRootPackage(InputInterface $input, IOInterface $io, Co if (null === $stability) { if (null === $packageVersion) { $stability = 'stable'; - } elseif (Preg::isMatchStrictGroups('{^[^,\s]*?@('.implode('|', array_keys(BasePackage::$stabilities)).')$}i', $packageVersion, $match)) { + } elseif (Preg::isMatchStrictGroups('{^[^,\s]*?@('.implode('|', array_keys(BasePackage::STABILITIES)).')$}i', $packageVersion, $match)) { $stability = $match[1]; } else { $stability = VersionParser::parseStability($packageVersion); @@ -384,12 +382,14 @@ protected function installRootPackage(InputInterface $input, IOInterface $io, Co $stability = VersionParser::normalizeStability($stability); - if (!isset(BasePackage::$stabilities[$stability])) { - throw new \InvalidArgumentException('Invalid stability provided ('.$stability.'), must be one of: '.implode(', ', array_keys(BasePackage::$stabilities))); + if (!isset(BasePackage::STABILITIES[$stability])) { + throw new \InvalidArgumentException('Invalid stability provided ('.$stability.'), must be one of: '.implode(', ', array_keys(BasePackage::STABILITIES))); } $composer = $this->createComposerInstance($input, $io, $config->all(), $disablePlugins, $disableScripts); $config = $composer->getConfig(); + // set the base dir here again on the new config instance, as otherwise in case the vendor dir is defined in an env var for example it would still override the value set above by $config->all() + $config->setBaseDir($directory); $rm = $composer->getRepositoryManager(); $repositorySet = new RepositorySet($stability); @@ -404,6 +404,12 @@ protected function installRootPackage(InputInterface $input, IOInterface $io, Co ) { continue; } + + // disable symlinking for the root package by default as that most likely makes no sense + if (($repoConfig['type'] ?? null) === 'path' && !isset($repoConfig['options']['symlink'])) { + $repoConfig['options']['symlink'] = false; + } + $repositorySet->addRepository(RepositoryFactory::createRepo($io, $config, $repoConfig, $rm)); } } diff --git a/app/vendor/composer/composer/src/Composer/Command/DiagnoseCommand.php b/app/vendor/composer/composer/src/Composer/Command/DiagnoseCommand.php index fa5e9aa56..8ed8f9433 100644 --- a/app/vendor/composer/composer/src/Composer/Command/DiagnoseCommand.php +++ b/app/vendor/composer/composer/src/Composer/Command/DiagnoseCommand.php @@ -19,6 +19,8 @@ use Composer\Downloader\TransportException; use Composer\IO\BufferIO; use Composer\Json\JsonFile; +use Composer\Json\JsonValidationException; +use Composer\Package\Locker; use Composer\Package\RootPackage; use Composer\Package\Version\VersionParser; use Composer\Pcre\Preg; @@ -89,6 +91,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int $io->write('Checking composer.json: ', false); $this->outputResult($this->checkComposerSchema()); + + if ($composer->getLocker()->isLocked()) { + $io->write('Checking composer.lock: ', false); + $this->outputResult($this->checkComposerLockSchema($composer->getLocker())); + } + $this->process = $composer->getLoop()->getProcessExecutor() ?? new ProcessExecutor($io); } else { $this->process = new ProcessExecutor($io); @@ -117,6 +125,25 @@ protected function execute(InputInterface $input, OutputInterface $output): int $io->write('Checking https connectivity to packagist: ', false); $this->outputResult($this->checkHttp('https', $config)); + foreach ($config->getRepositories() as $repo) { + if (($repo['type'] ?? null) === 'composer' && isset($repo['url'])) { + $composerRepo = new ComposerRepository($repo, $this->getIO(), $config, $this->httpDownloader); + $reflMethod = new \ReflectionMethod($composerRepo, 'getPackagesJsonUrl'); + if (PHP_VERSION_ID < 80100) { + $reflMethod->setAccessible(true); + } + $url = $reflMethod->invoke($composerRepo); + if (!str_starts_with($url, 'http')) { + continue; + } + if (str_starts_with($url, 'https://repo.packagist.org')) { + continue; + } + $io->write('Checking connectivity to ' . $repo['url'].': ', false); + $this->outputResult($this->checkComposerRepo($url, $config)); + } + } + $proxyManager = ProxyManager::getInstance(); $protos = $config->get('disable-tls') === true ? ['http'] : ['http', 'https']; try { @@ -148,7 +175,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } elseif (10 > $rate['remaining']) { $io->write('WARNING'); $io->write(sprintf( - 'Github has a rate limit on their API. ' + 'GitHub has a rate limit on their API. ' . 'You currently have %u ' . 'out of %u requests left.' . PHP_EOL . 'See https://developer.github.com/v3/#rate-limiting and also' . PHP_EOL @@ -248,13 +275,34 @@ private function checkComposerSchema() return true; } + /** + * @return string|true + */ + private function checkComposerLockSchema(Locker $locker) + { + $json = $locker->getJsonFile(); + + try { + $json->validateSchema(JsonFile::LOCK_SCHEMA); + } catch (JsonValidationException $e) { + $output = ''; + foreach ($e->getErrors() as $error) { + $output .= ''.$error.''.PHP_EOL; + } + + return trim($output); + } + + return true; + } + private function checkGit(): string { if (!function_exists('proc_open')) { return 'proc_open is not available, git cannot be used'; } - $this->process->execute('git config color.ui', $output); + $this->process->execute(['git', 'config', 'color.ui'], $output); if (strtolower(trim($output)) === 'always') { return 'Your git color.ui setting is set to always, this is known to create issues. Use "git config --global color.ui true" to set it correctly.'; } @@ -310,6 +358,45 @@ private function checkHttp(string $proto, Config $config) return true; } + /** + * @return string|string[]|true + */ + private function checkComposerRepo(string $url, Config $config) + { + $result = $this->checkConnectivityAndComposerNetworkHttpEnablement(); + if ($result !== true) { + return $result; + } + + $result = []; + if (str_starts_with($url, 'https://') && $config->get('disable-tls') === true) { + $tlsWarning = 'Composer is configured to disable SSL/TLS protection. This will leave remote HTTPS requests vulnerable to Man-In-The-Middle attacks.'; + } + + try { + $this->httpDownloader->get($url); + } catch (TransportException $e) { + $hints = HttpDownloader::getExceptionHints($e); + if (null !== $hints && count($hints) > 0) { + foreach ($hints as $hint) { + $result[] = $hint; + } + } + + $result[] = '[' . get_class($e) . '] ' . $e->getMessage() . ''; + } + + if (isset($tlsWarning)) { + $result[] = $tlsWarning; + } + + if (count($result) > 0) { + return $result; + } + + return true; + } + /** * @return string|\Exception */ @@ -508,11 +595,11 @@ private function checkComposerAudit(Config $config) $io = new BufferIO(); $result = $auditor->audit($io, $repoSet, $packages, Auditor::FORMAT_TABLE, true, [], Auditor::ABANDONED_IGNORE); } catch (\Throwable $e) { - return 'Failed performing audit: '.$e->getMessage().''; + return 'Failed performing audit: '.$e->getMessage().''; } if ($result > 0) { - return 'Audit found some issues:' . PHP_EOL . $io->getOutput(); + return 'Audit found some issues:' . PHP_EOL . $io->getOutput(); } return true; @@ -526,9 +613,12 @@ private function getCurlVersion(): string } $version = curl_version(); + $hasZstd = isset($version['features']) && defined('CURL_VERSION_ZSTD') && 0 !== ($version['features'] & CURL_VERSION_ZSTD); return ''.$version['version'].' '. - 'libz '.(!empty($version['libz_version']) ? $version['libz_version'] : 'missing').' '. + 'libz '.($version['libz_version'] ?? 'missing').' '. + 'brotli '.($version['brotli_version'] ?? 'missing').' '. + 'zstd '.($hasZstd ? 'supported' : 'missing').' '. 'ssl '.($version['ssl_version'] ?? 'missing').''; } @@ -630,7 +720,7 @@ private function checkPlatform() $errors['ioncube'] = ioncube_loader_version(); } - if (PHP_VERSION_ID < 70205) { + if (\PHP_VERSION_ID < 70205) { $errors['php'] = PHP_VERSION; } @@ -678,6 +768,12 @@ private function checkPlatform() $warnings['onedrive'] = PHP_VERSION; } + if (extension_loaded('uopz') + && !(filter_var(ini_get('uopz.disable'), FILTER_VALIDATE_BOOLEAN) + || filter_var(ini_get('uopz.exit'), FILTER_VALIDATE_BOOLEAN))) { + $warnings['uopz'] = true; + } + if (!empty($errors)) { foreach ($errors as $error => $current) { switch ($error) { @@ -791,6 +887,11 @@ private function checkPlatform() $text .= "Upgrade your PHP ({$current}) to use this location with Composer.".PHP_EOL; break; + case 'uopz': + $text = "The uopz extension ignores exit calls and may not work with all Composer commands.".PHP_EOL; + $text .= "Disabling it when using Composer is recommended."; + break; + default: throw new \InvalidArgumentException(sprintf("DiagnoseCommand: Unknown warning type \"%s\". Please report at https://github.com/composer/composer/issues/new.", $warning)); } diff --git a/app/vendor/composer/composer/src/Composer/Command/DumpAutoloadCommand.php b/app/vendor/composer/composer/src/Composer/Command/DumpAutoloadCommand.php index c30fae7a8..cc0d7bf80 100644 --- a/app/vendor/composer/composer/src/Composer/Command/DumpAutoloadCommand.php +++ b/app/vendor/composer/composer/src/Composer/Command/DumpAutoloadCommand.php @@ -12,6 +12,7 @@ namespace Composer\Command; +use Composer\Package\AliasPackage; use Composer\Plugin\CommandEvent; use Composer\Plugin\PluginEvents; use Symfony\Component\Console\Input\InputInterface; @@ -43,6 +44,7 @@ protected function configure() new InputOption('ignore-platform-req', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Ignore a specific platform requirement (php & ext- packages).'), new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore all platform requirements (php & ext- packages).'), new InputOption('strict-psr', null, InputOption::VALUE_NONE, 'Return a failed status code (1) if PSR-4 or PSR-0 mapping errors are present. Requires --optimize to work.'), + new InputOption('strict-ambiguous', null, InputOption::VALUE_NONE, 'Return a failed status code (2) if the same class is found in multiple files. Requires --optimize to work.'), ]) ->setHelp( <<getPackage(); $config = $composer->getConfig(); + $missingDependencies = false; + foreach ($localRepo->getCanonicalPackages() as $localPkg) { + $installPath = $installationManager->getInstallPath($localPkg); + if ($installPath !== null && file_exists($installPath) === false) { + $missingDependencies = true; + $this->getIO()->write('Not all dependencies are installed. Make sure to run a "composer install" to install missing dependencies'); + + break; + } + } + $optimize = $input->getOption('optimize') || $config->get('optimize-autoloader'); $authoritative = $input->getOption('classmap-authoritative') || $config->get('classmap-authoritative'); $apcuPrefix = $input->getOption('apcu-prefix'); @@ -74,6 +87,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int if ($input->getOption('strict-psr') && !$optimize && !$authoritative) { throw new \InvalidArgumentException('--strict-psr mode only works with optimized autoloader, use --optimize or --classmap-authoritative if you want a strict return value.'); } + if ($input->getOption('strict-ambiguous') && !$optimize && !$authoritative) { + throw new \InvalidArgumentException('--strict-ambiguous mode only works with optimized autoloader, use --optimize or --classmap-authoritative if you want a strict return value.'); + } if ($authoritative) { $this->getIO()->write('Generating optimized autoload files (authoritative)'); @@ -108,7 +124,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int 'composer', $optimize, null, - $composer->getLocker() + $composer->getLocker(), + $input->getOption('strict-ambiguous') ); $numberOfClasses = count($classMap); @@ -120,10 +137,14 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->getIO()->write('Generated autoload files'); } - if ($input->getOption('strict-psr') && count($classMap->getPsrViolations()) > 0) { + if ($missingDependencies || ($input->getOption('strict-psr') && count($classMap->getPsrViolations()) > 0)) { return 1; } + if ($input->getOption('strict-ambiguous') && count($classMap->getAmbiguousClasses(false)) > 0) { + return 2; + } + return 0; } } diff --git a/app/vendor/composer/composer/src/Composer/Command/HomeCommand.php b/app/vendor/composer/composer/src/Composer/Command/HomeCommand.php index 5aec6f4c1..3547faec7 100644 --- a/app/vendor/composer/composer/src/Composer/Command/HomeCommand.php +++ b/app/vendor/composer/composer/src/Composer/Command/HomeCommand.php @@ -122,22 +122,20 @@ private function handlePackage(CompletePackageInterface $package, bool $showHome */ private function openBrowser(string $url): void { - $url = ProcessExecutor::escape($url); - $process = new ProcessExecutor($this->getIO()); if (Platform::isWindows()) { - $process->execute('start "web" explorer ' . $url, $output); + $process->execute(['start', '"web"', 'explorer', $url], $output); return; } - $linux = $process->execute('which xdg-open', $output); - $osx = $process->execute('which open', $output); + $linux = $process->execute(['which', 'xdg-open'], $output); + $osx = $process->execute(['which', 'open'], $output); if (0 === $linux) { - $process->execute('xdg-open ' . $url, $output); + $process->execute(['xdg-open', $url], $output); } elseif (0 === $osx) { - $process->execute('open ' . $url, $output); + $process->execute(['open', $url], $output); } else { $this->getIO()->writeError('No suitable browser opening command found, open yourself: ' . $url); } diff --git a/app/vendor/composer/composer/src/Composer/Command/InitCommand.php b/app/vendor/composer/composer/src/Composer/Command/InitCommand.php index 5f6773daf..9a49d595b 100644 --- a/app/vendor/composer/composer/src/Composer/Command/InitCommand.php +++ b/app/vendor/composer/composer/src/Composer/Command/InitCommand.php @@ -21,11 +21,13 @@ use Composer\Repository\CompositeRepository; use Composer\Repository\PlatformRepository; use Composer\Repository\RepositoryFactory; +use Composer\Spdx\SpdxLicenses; use Composer\Util\Filesystem; use Composer\Util\Silencer; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\InputInterface; use Composer\Console\Input\InputOption; +use Composer\Util\ProcessExecutor; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Process\ExecutableFinder; use Symfony\Component\Process\Process; @@ -61,7 +63,7 @@ protected function configure() new InputOption('homepage', null, InputOption::VALUE_REQUIRED, 'Homepage of package'), new InputOption('require', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Package to require with a version constraint, e.g. foo/bar:1.0.0 or foo/bar=1.0.0 or "foo/bar 1.0.0"', null, $this->suggestAvailablePackageInclPlatform()), new InputOption('require-dev', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'Package to require for development with a version constraint, e.g. foo/bar:1.0.0 or foo/bar=1.0.0 or "foo/bar 1.0.0"', null, $this->suggestAvailablePackageInclPlatform()), - new InputOption('stability', 's', InputOption::VALUE_REQUIRED, 'Minimum stability (empty or one of: '.implode(', ', array_keys(BasePackage::$stabilities)).')'), + new InputOption('stability', 's', InputOption::VALUE_REQUIRED, 'Minimum stability (empty or one of: '.implode(', ', array_keys(BasePackage::STABILITIES)).')'), new InputOption('license', 'l', InputOption::VALUE_REQUIRED, 'License of package'), new InputOption('repository', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Add custom repositories, either by URL or using JSON arrays'), new InputOption('autoload', 'a', InputOption::VALUE_REQUIRED, 'Add PSR-4 autoload mapping. Maps your package\'s namespace to the provided directory. (Expects a relative path, e.g. src/)'), @@ -89,7 +91,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $allowlist = ['name', 'description', 'author', 'type', 'homepage', 'require', 'require-dev', 'stability', 'license', 'autoload']; $options = array_filter(array_intersect_key($input->getOptions(), array_flip($allowlist)), function ($val) { return $val !== null && $val !== []; }); - if (isset($options['name']) && !Preg::isMatch('{^[a-z0-9_.-]+/[a-z0-9_.-]+$}D', $options['name'])) { + if (isset($options['name']) && !Preg::isMatch('{^[a-z0-9]([_.-]?[a-z0-9]+)*\/[a-z0-9](([_.]|-{1,2})?[a-z0-9]+)*$}D', $options['name'])) { throw new \InvalidArgumentException( 'The package name '.$options['name'].' is invalid, it should be lowercase and have a vendor name, a forward slash, and a package name, matching: [a-z0-9_.-]+/[a-z0-9_.-]+' ); @@ -272,23 +274,24 @@ protected function interact(InputInterface $input, OutputInterface $output) $name = $input->getOption('name'); if (null === $name) { $name = basename($cwd); - $name = Preg::replace('{(?:([a-z])([A-Z])|([A-Z])([A-Z][a-z]))}', '\\1\\3-\\2\\4', $name); - $name = strtolower($name); + $name = $this->sanitizePackageNameComponent($name); + + $vendor = $name; if (!empty($_SERVER['COMPOSER_DEFAULT_VENDOR'])) { - $name = $_SERVER['COMPOSER_DEFAULT_VENDOR'] . '/' . $name; + $vendor = $_SERVER['COMPOSER_DEFAULT_VENDOR']; } elseif (isset($git['github.user'])) { - $name = $git['github.user'] . '/' . $name; + $vendor = $git['github.user']; } elseif (!empty($_SERVER['USERNAME'])) { - $name = $_SERVER['USERNAME'] . '/' . $name; + $vendor = $_SERVER['USERNAME']; } elseif (!empty($_SERVER['USER'])) { - $name = $_SERVER['USER'] . '/' . $name; + $vendor = $_SERVER['USER']; } elseif (get_current_user()) { - $name = get_current_user() . '/' . $name; - } else { - // package names must be in the format foo/bar - $name .= '/' . $name; + $vendor = get_current_user(); } - $name = strtolower($name); + + $vendor = $this->sanitizePackageNameComponent($vendor); + + $name = $vendor . '/' . $name; } $name = $io->askAndValidate( @@ -298,7 +301,7 @@ static function ($value) use ($name) { return $name; } - if (!Preg::isMatch('{^[a-z0-9_.-]+/[a-z0-9_.-]+$}D', $value)) { + if (!Preg::isMatch('{^[a-z0-9]([_.-]?[a-z0-9]+)*\/[a-z0-9](([_.]|-{1,2})?[a-z0-9]+)*$}D', $value)) { throw new \InvalidArgumentException( 'The package name '.$value.' is invalid, it should be lowercase and have a vendor name, a forward slash, and a package name, matching: [a-z0-9_.-]+/[a-z0-9_.-]+' ); @@ -364,10 +367,10 @@ static function ($value) use ($minimumStability) { return $minimumStability; } - if (!isset(BasePackage::$stabilities[$value])) { + if (!isset(BasePackage::STABILITIES[$value])) { throw new \InvalidArgumentException( 'Invalid minimum stability "'.$value.'". Must be empty or one of: '. - implode(', ', array_keys(BasePackage::$stabilities)) + implode(', ', array_keys(BasePackage::STABILITIES)) ); } @@ -378,11 +381,14 @@ static function ($value) use ($minimumStability) { ); $input->setOption('stability', $minimumStability); - $type = $input->getOption('type') ?: false; + $type = $input->getOption('type'); $type = $io->ask( 'Package Type (e.g. library, project, metapackage, composer-plugin) ['.$type.']: ', $type ); + if ($type === '' || $type === false) { + $type = null; + } $input->setOption('type', $type); if (null === $license = $input->getOption('license')) { @@ -395,6 +401,10 @@ static function ($value) use ($minimumStability) { 'License ['.$license.']: ', $license ); + $spdx = new SpdxLicenses(); + if (null !== $license && !$spdx->validate($license) && $license !== 'proprietary') { + throw new \InvalidArgumentException('Invalid license provided: '.$license.'. Only SPDX license identifiers (https://spdx.org/licenses/) or "proprietary" are accepted.'); + } $input->setOption('license', $license); $io->writeError(['', 'Define your dependencies.', '']); @@ -465,8 +475,6 @@ static function ($value) use ($autoload) { private function parseAuthorString(string $author): array { if (Preg::isMatch('/^(?P[- .,\p{L}\p{N}\p{Mn}\'’"()]+)(?:\s+<(?P.+?)>)?$/u', $author, $match)) { - assert(is_string($match['name'])); - if (null !== $match['email'] && !$this->isValidEmail($match['email'])) { throw new \InvalidArgumentException('Invalid email "'.$match['email'].'"'); } @@ -529,15 +537,11 @@ protected function getGitConfig(): array return $this->gitConfig; } - $finder = new ExecutableFinder(); - $gitBin = $finder->find('git'); + $process = new ProcessExecutor($this->getIO()); - $cmd = new Process([$gitBin, 'config', '-l']); - $cmd->run(); - - if ($cmd->isSuccessful()) { + if (0 === $process->execute(['git', 'config', '-l'], $output)) { $this->gitConfig = []; - Preg::matchAllStrictGroups('{^([^=]+)=(.*)$}m', $cmd->getOutput(), $matches); + Preg::matchAllStrictGroups('{^([^=]+)=(.*)$}m', $output, $matches); foreach ($matches[1] as $key => $match) { $this->gitConfig[$match] = $matches[2][$key]; } @@ -633,4 +637,14 @@ private function hasDependencies(array $options): bool return !empty($requires) || !empty($devRequires); } + + private function sanitizePackageNameComponent(string $name): string + { + $name = Preg::replace('{(?:([a-z])([A-Z])|([A-Z])([A-Z][a-z]))}', '\\1\\3-\\2\\4', $name); + $name = strtolower($name); + $name = Preg::replace('{^[_.-]+|[_.-]+$|[^a-z0-9_.-]}u', '', $name); + $name = Preg::replace('{([_.-]){2,}}u', '$1', $name); + + return $name; + } } diff --git a/app/vendor/composer/composer/src/Composer/Command/OutdatedCommand.php b/app/vendor/composer/composer/src/Composer/Command/OutdatedCommand.php index 139fe45a8..0fea6dc09 100644 --- a/app/vendor/composer/composer/src/Composer/Command/OutdatedCommand.php +++ b/app/vendor/composer/composer/src/Composer/Command/OutdatedCommand.php @@ -71,6 +71,18 @@ protected function execute(InputInterface $input, OutputInterface $output): int 'command' => 'show', '--latest' => true, ]; + if ($input->getOption('no-interaction')) { + $args['--no-interaction'] = true; + } + if ($input->getOption('no-plugins')) { + $args['--no-plugins'] = true; + } + if ($input->getOption('no-scripts')) { + $args['--no-scripts'] = true; + } + if ($input->getOption('no-cache')) { + $args['--no-cache'] = true; + } if (!$input->getOption('all')) { $args['--outdated'] = true; } diff --git a/app/vendor/composer/composer/src/Composer/Command/PackageDiscoveryTrait.php b/app/vendor/composer/composer/src/Composer/Command/PackageDiscoveryTrait.php index d95e06de8..0bbd2a48c 100644 --- a/app/vendor/composer/composer/src/Composer/Command/PackageDiscoveryTrait.php +++ b/app/vendor/composer/composer/src/Composer/Command/PackageDiscoveryTrait.php @@ -16,6 +16,7 @@ use Composer\Filter\PlatformRequirementFilter\IgnoreAllPlatformRequirementFilter; use Composer\Filter\PlatformRequirementFilter\PlatformRequirementFilterFactory; use Composer\IO\IOInterface; +use Composer\Package\BasePackage; use Composer\Package\CompletePackageInterface; use Composer\Package\PackageInterface; use Composer\Package\Version\VersionParser; @@ -52,6 +53,9 @@ protected function getRepos(): CompositeRepository return $this->repos; } + /** + * @param key-of|null $minimumStability + */ private function getRepositorySet(InputInterface $input, ?string $minimumStability = null): RepositorySet { $key = $minimumStability ?? 'default'; @@ -64,6 +68,9 @@ private function getRepositorySet(InputInterface $input, ?string $minimumStabili return $this->repositorySets[$key]; } + /** + * @return key-of + */ private function getMinimumStability(InputInterface $input): string { if ($input->hasOption('stability')) { // @phpstan-ignore-line as InitCommand does have this option but not all classes using this trait do @@ -96,7 +103,7 @@ final protected function determineRequirements(InputInterface $input, OutputInte foreach ($requires as $requirement) { if (isset($requirement['version']) && Preg::isMatch('{^\d+(\.\d+)?$}', $requirement['version'])) { - $io->writeError('The "'.$requirement['version'].'" constraint for "'.$requirement['name'].'" appears too strict and will likely not match what you want. See https://getcomposer.org/constraints'); + $io->writeError('The "'.$requirement['version'].'" constraint for "'.$requirement['name'].'" appears too strict and will likely not match what you want. See https://getcomposer.org/constraints'); } if (!isset($requirement['version'])) { diff --git a/app/vendor/composer/composer/src/Composer/Command/ReinstallCommand.php b/app/vendor/composer/composer/src/Composer/Command/ReinstallCommand.php index 446d9eec1..cb7882a9c 100644 --- a/app/vendor/composer/composer/src/Composer/Command/ReinstallCommand.php +++ b/app/vendor/composer/composer/src/Composer/Command/ReinstallCommand.php @@ -51,7 +51,8 @@ protected function configure(): void new InputOption('apcu-autoloader-prefix', null, InputOption::VALUE_REQUIRED, 'Use a custom prefix for the APCu autoloader cache. Implicitly enables --apcu-autoloader'), new InputOption('ignore-platform-req', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Ignore a specific platform requirement (php & ext- packages).'), new InputOption('ignore-platform-reqs', null, InputOption::VALUE_NONE, 'Ignore all platform requirements (php & ext- packages).'), - new InputArgument('packages', InputArgument::IS_ARRAY | InputArgument::REQUIRED, 'List of package names to reinstall, can include a wildcard (*) to match any substring.', null, $this->suggestInstalledPackage(false)), + new InputOption('type', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Filter packages to reinstall by type(s)', null, $this->suggestInstalledPackageTypes(false)), + new InputArgument('packages', InputArgument::IS_ARRAY, 'List of package names to reinstall, can include a wildcard (*) to match any substring.', null, $this->suggestInstalledPackage(false)), ]) ->setHelp( <<getRepositoryManager()->getLocalRepository(); $packagesToReinstall = []; $packageNamesToReinstall = []; - foreach ($input->getArgument('packages') as $pattern) { - $patternRegexp = BasePackage::packageNameToRegexp($pattern); - $matched = false; + if (\count($input->getOption('type')) > 0) { + if (\count($input->getArgument('packages')) > 0) { + throw new \InvalidArgumentException('You cannot specify package names and filter by type at the same time.'); + } foreach ($localRepo->getCanonicalPackages() as $package) { - if (Preg::isMatch($patternRegexp, $package->getName())) { - $matched = true; + if (in_array($package->getType(), $input->getOption('type'), true)) { $packagesToReinstall[] = $package; $packageNamesToReinstall[] = $package->getName(); } } + } else { + if (\count($input->getArgument('packages')) === 0) { + throw new \InvalidArgumentException('You must pass one or more package names to be reinstalled.'); + } + foreach ($input->getArgument('packages') as $pattern) { + $patternRegexp = BasePackage::packageNameToRegexp($pattern); + $matched = false; + foreach ($localRepo->getCanonicalPackages() as $package) { + if (Preg::isMatch($patternRegexp, $package->getName())) { + $matched = true; + $packagesToReinstall[] = $package; + $packageNamesToReinstall[] = $package->getName(); + } + } - if (!$matched) { - $io->writeError('Pattern "' . $pattern . '" does not match any currently installed packages.'); + if (!$matched) { + $io->writeError('Pattern "' . $pattern . '" does not match any currently installed packages.'); + } } } - if (!$packagesToReinstall) { + if (0 === \count($packagesToReinstall)) { $io->writeError('Found no packages to reinstall, aborting.'); return 1; diff --git a/app/vendor/composer/composer/src/Composer/Command/RemoveCommand.php b/app/vendor/composer/composer/src/Composer/Command/RemoveCommand.php index 9803190a4..a68663567 100644 --- a/app/vendor/composer/composer/src/Composer/Command/RemoveCommand.php +++ b/app/vendor/composer/composer/src/Composer/Command/RemoveCommand.php @@ -55,8 +55,8 @@ protected function configure() new InputOption('no-audit', null, InputOption::VALUE_NONE, 'Skip the audit step after updating the composer.lock file (can also be set via the COMPOSER_NO_AUDIT=1 env var).'), new InputOption('audit-format', null, InputOption::VALUE_REQUIRED, 'Audit output format. Must be "table", "plain", "json", or "summary".', Auditor::FORMAT_SUMMARY, Auditor::FORMATS), new InputOption('update-no-dev', null, InputOption::VALUE_NONE, 'Run the dependency update with the --no-dev option.'), - new InputOption('update-with-dependencies', 'w', InputOption::VALUE_NONE, 'Allows inherited dependencies to be updated with explicit dependencies. (Deprecated, is now default behavior)'), - new InputOption('update-with-all-dependencies', 'W', InputOption::VALUE_NONE, 'Allows all inherited dependencies to be updated, including those that are root requirements.'), + new InputOption('update-with-dependencies', 'w', InputOption::VALUE_NONE, 'Allows inherited dependencies to be updated with explicit dependencies (can also be set via the COMPOSER_WITH_DEPENDENCIES=1 env var). (Deprecated, is now default behavior)'), + new InputOption('update-with-all-dependencies', 'W', InputOption::VALUE_NONE, 'Allows all inherited dependencies to be updated, including those that are root requirements (can also be set via the COMPOSER_WITH_ALL_DEPENDENCIES=1 env var).'), new InputOption('with-all-dependencies', null, InputOption::VALUE_NONE, 'Alias for --update-with-all-dependencies'), new InputOption('no-update-with-dependencies', null, InputOption::VALUE_NONE, 'Does not allow inherited dependencies to be updated with explicit dependencies.'), new InputOption('minimal-changes', 'm', InputOption::VALUE_NONE, 'During an update with -w/-W, only perform absolutely necessary changes to transitive dependencies (can also be set via the COMPOSER_MINIMAL_CHANGES=1 env var).'), diff --git a/app/vendor/composer/composer/src/Composer/Command/RequireCommand.php b/app/vendor/composer/composer/src/Composer/Command/RequireCommand.php index b7ee15681..09eab3e26 100644 --- a/app/vendor/composer/composer/src/Composer/Command/RequireCommand.php +++ b/app/vendor/composer/composer/src/Composer/Command/RequireCommand.php @@ -95,8 +95,8 @@ protected function configure() new InputOption('no-audit', null, InputOption::VALUE_NONE, 'Skip the audit step after updating the composer.lock file (can also be set via the COMPOSER_NO_AUDIT=1 env var).'), new InputOption('audit-format', null, InputOption::VALUE_REQUIRED, 'Audit output format. Must be "table", "plain", "json", or "summary".', Auditor::FORMAT_SUMMARY, Auditor::FORMATS), new InputOption('update-no-dev', null, InputOption::VALUE_NONE, 'Run the dependency update with the --no-dev option.'), - new InputOption('update-with-dependencies', 'w', InputOption::VALUE_NONE, 'Allows inherited dependencies to be updated, except those that are root requirements.'), - new InputOption('update-with-all-dependencies', 'W', InputOption::VALUE_NONE, 'Allows all inherited dependencies to be updated, including those that are root requirements.'), + new InputOption('update-with-dependencies', 'w', InputOption::VALUE_NONE, 'Allows inherited dependencies to be updated, except those that are root requirements (can also be set via the COMPOSER_WITH_DEPENDENCIES=1 env var).'), + new InputOption('update-with-all-dependencies', 'W', InputOption::VALUE_NONE, 'Allows all inherited dependencies to be updated, including those that are root requirements (can also be set via the COMPOSER_WITH_ALL_DEPENDENCIES=1 env var).'), new InputOption('with-dependencies', null, InputOption::VALUE_NONE, 'Alias for --update-with-dependencies'), new InputOption('with-all-dependencies', null, InputOption::VALUE_NONE, 'Alias for --update-with-all-dependencies'), new InputOption('ignore-platform-req', null, InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'Ignore a specific platform requirement (php & ext- packages).'), @@ -231,7 +231,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $requirements = $this->formatRequirements($requirements); - if (!$input->getOption('dev') && $io->isInteractive()) { + if (!$input->getOption('dev') && $io->isInteractive() && !$composer->isGlobal()) { $devPackages = []; $devTags = ['dev', 'testing', 'static analysis']; $currentRequiresByKey = $this->getPackagesByRequireKey(); @@ -402,6 +402,8 @@ private function getPackagesByRequireKey(): array /** * @param array $requirements + * @param 'require'|'require-dev' $requireKey + * @param 'require'|'require-dev' $removeKey * @throws \Exception */ private function doUpdate(InputInterface $input, OutputInterface $output, IOInterface $io, array $requirements, string $requireKey, string $removeKey): int @@ -552,22 +554,15 @@ private function updateRequirementsAfterResolution(array $requirementsToUpdate, if (!$dryRun) { $this->updateFile($this->json, $requirements, $requireKey, $removeKey, $sortPackages); - if ($locker->isLocked()) { - $contents = file_get_contents($this->json->getPath()); - if (false === $contents) { - throw new \RuntimeException('Unable to read '.$this->json->getPath().' contents to update the lock file hash.'); - } - $lockFile = Factory::getLockFile($this->json->getPath()); - if (file_exists($lockFile)) { - $lockMtime = filemtime($lockFile); - $lock = new JsonFile($lockFile); - $lockData = $lock->read(); - $lockData['content-hash'] = Locker::getContentHash($contents); - $lock->write($lockData); - if (is_int($lockMtime)) { - @touch($lockFile, $lockMtime); + if ($locker->isLocked() && $composer->getConfig()->get('lock')) { + $stabilityFlags = RootPackageLoader::extractStabilityFlags($requirements, $composer->getPackage()->getMinimumStability(), []); + $locker->updateHash($this->json, function (array $lockData) use ($stabilityFlags) { + foreach ($stabilityFlags as $packageName => $flag) { + $lockData['stability-flags'][$packageName] = $flag; } - } + + return $lockData; + }); } } diff --git a/app/vendor/composer/composer/src/Composer/Command/SelfUpdateCommand.php b/app/vendor/composer/composer/src/Composer/Command/SelfUpdateCommand.php index 26d9f7546..1bf2e57d4 100644 --- a/app/vendor/composer/composer/src/Composer/Command/SelfUpdateCommand.php +++ b/app/vendor/composer/composer/src/Composer/Command/SelfUpdateCommand.php @@ -23,6 +23,7 @@ use Composer\IO\IOInterface; use Composer\Downloader\FilesystemException; use Composer\Downloader\TransportException; +use Phar; use Symfony\Component\Console\Input\InputInterface; use Composer\Console\Input\InputOption; use Composer\Console\Input\InputArgument; @@ -116,9 +117,9 @@ class_exists('Composer\Downloader\FilesystemException'); $cacheDir = $config->get('cache-dir'); $rollbackDir = $config->get('data-dir'); $home = $config->get('home'); - $localFilename = realpath($_SERVER['argv'][0]); - if (false === $localFilename) { - $localFilename = $_SERVER['argv'][0]; + $localFilename = Phar::running(false); + if ('' === $localFilename) { + throw new \RuntimeException('Could not determine the location of the composer.phar file as it appears you are not running this code from a phar archive.'); } if ($input->getOption('update-keys')) { @@ -146,7 +147,7 @@ class_exists('Composer\Downloader\FilesystemException'); $homeDirOwnerId = fileowner($home); if (is_array($composerUser) && $homeDirOwnerId !== false) { $homeOwner = posix_getpwuid($homeDirOwnerId); - if (is_array($homeOwner) && isset($composerUser['name'], $homeOwner['name']) && $composerUser['name'] !== $homeOwner['name']) { + if (is_array($homeOwner) && $composerUser['name'] !== $homeOwner['name']) { $io->writeError('You are running Composer as "'.$composerUser['name'].'", while "'.$home.'" is owned by "'.$homeOwner['name'].'"'); } } @@ -328,8 +329,8 @@ class_exists('Composer\Downloader\FilesystemException'); $verified = 1 === openssl_verify((string) file_get_contents($tempFilename), $signatureSha384, $pubkeyid, $algo); // PHP 8 automatically frees the key instance and deprecates the function - if (PHP_VERSION_ID < 80000) { - // @phpstan-ignore-next-line + if (\PHP_VERSION_ID < 80000) { + // @phpstan-ignore function.deprecated openssl_free_key($pubkeyid); } diff --git a/app/vendor/composer/composer/src/Composer/Command/ShowCommand.php b/app/vendor/composer/composer/src/Composer/Command/ShowCommand.php index a1e7eb059..14c9a4c32 100644 --- a/app/vendor/composer/composer/src/Composer/Command/ShowCommand.php +++ b/app/vendor/composer/composer/src/Composer/Command/ShowCommand.php @@ -43,6 +43,7 @@ use Composer\Semver\Semver; use Composer\Spdx\SpdxLicenses; use Composer\Util\PackageInfo; +use DateTimeInterface; use Symfony\Component\Console\Completion\CompletionInput; use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\Console\Formatter\OutputFormatterStyle; @@ -493,7 +494,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $writeVersion = !$input->getOption('name-only') && !$input->getOption('path') && $showVersion; $writeLatest = $writeVersion && $showLatest; $writeDescription = !$input->getOption('name-only') && !$input->getOption('path'); - $writeReleaseDate = $writeLatest && $input->getOption('sort-by-age'); + $writeReleaseDate = $writeLatest && ($input->getOption('sort-by-age') || $format === 'json'); $hasOutdatedPackages = false; @@ -550,8 +551,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int $packageViewData['release-age'] = 'from '.$packageViewData['release-age']; } $releaseDateLength = max($releaseDateLength, strlen($packageViewData['release-age'])); + $packageViewData['release-date'] = $package->getReleaseDate()->format(DateTimeInterface::ATOM); } else { $packageViewData['release-age'] = ''; + $packageViewData['release-date'] = ''; } } if ($writeLatest && $latestPackage) { @@ -561,6 +564,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int } $packageViewData['latest-status'] = $this->getUpdateStatus($latestPackage, $package); $latestLength = max($latestLength, strlen($packageViewData['latest'])); + + if ($latestPackage->getReleaseDate() !== null) { + $packageViewData['latest-release-date'] = $latestPackage->getReleaseDate()->format(DateTimeInterface::ATOM); + } else { + $packageViewData['latest-release-date'] = ''; + } } elseif ($writeLatest) { $packageViewData['latest'] = '[none matched]'; $packageViewData['latest-status'] = 'up-to-date'; @@ -808,7 +817,8 @@ protected function getPackage(InstalledRepository $installedRepo, RepositoryInte $pool = $repositorySet->createPoolForPackage($name); } $matches = $pool->whatProvides($name, $constraint); - foreach ($matches as $index => $package) { + $literals = []; + foreach ($matches as $package) { // avoid showing the 9999999-dev alias if the default branch has no branch-alias set if ($package instanceof AliasPackage && $package->getVersion() === VersionParser::DEFAULT_BRANCH_ALIAS) { $package = $package->getAliasOf(); @@ -820,11 +830,12 @@ protected function getPackage(InstalledRepository $installedRepo, RepositoryInte } $versions[$package->getPrettyVersion()] = $package->getVersion(); - $matches[$index] = $package->getId(); + $literals[] = $package->getId(); } // select preferred package according to policy rules - if (null === $matchedPackage && $matches && $preferred = $policy->selectPreferredPackages($pool, $matches)) { + if (null === $matchedPackage && \count($literals) > 0) { + $preferred = $policy->selectPreferredPackages($pool, $literals); $matchedPackage = $pool->literalToPackage($preferred[0]); } @@ -1454,7 +1465,7 @@ private function findLatestPackage(PackageInterface $package, Composer $composer $stability = $composer->getPackage()->getMinimumStability(); $flags = $composer->getPackage()->getStabilityFlags(); if (isset($flags[$name])) { - $stability = array_search($flags[$name], BasePackage::$stabilities, true); + $stability = array_search($flags[$name], BasePackage::STABILITIES, true); } $bestStability = $stability; diff --git a/app/vendor/composer/composer/src/Composer/Command/StatusCommand.php b/app/vendor/composer/composer/src/Composer/Command/StatusCommand.php index 780f70031..5d90b3105 100644 --- a/app/vendor/composer/composer/src/Composer/Command/StatusCommand.php +++ b/app/vendor/composer/composer/src/Composer/Command/StatusCommand.php @@ -92,7 +92,7 @@ private function doExecute(InputInterface $input): int $vcsVersionChanges = []; $parser = new VersionParser; - $guesser = new VersionGuesser($composer->getConfig(), $composer->getLoop()->getProcessExecutor() ?? new ProcessExecutor($io), $parser); + $guesser = new VersionGuesser($composer->getConfig(), $composer->getLoop()->getProcessExecutor() ?? new ProcessExecutor($io), $parser, $io); $dumper = new ArrayDumper; // list packages diff --git a/app/vendor/composer/composer/src/Composer/Command/UpdateCommand.php b/app/vendor/composer/composer/src/Composer/Command/UpdateCommand.php index b4478cd04..21d6c3f19 100644 --- a/app/vendor/composer/composer/src/Composer/Command/UpdateCommand.php +++ b/app/vendor/composer/composer/src/Composer/Command/UpdateCommand.php @@ -16,20 +16,28 @@ use Composer\DependencyResolver\Request; use Composer\Installer; use Composer\IO\IOInterface; +use Composer\Package\BasePackage; use Composer\Package\Loader\RootPackageLoader; +use Composer\Package\PackageInterface; +use Composer\Package\Version\VersionSelector; use Composer\Pcre\Preg; use Composer\Plugin\CommandEvent; use Composer\Plugin\PluginEvents; use Composer\Package\Version\VersionParser; +use Composer\Repository\CompositeRepository; +use Composer\Repository\PlatformRepository; +use Composer\Repository\RepositoryInterface; +use Composer\Repository\RepositorySet; +use Composer\Semver\Constraint\MultiConstraint; use Composer\Semver\Intervals; use Composer\Util\HttpDownloader; use Composer\Advisory\Auditor; +use Composer\Util\Platform; use Symfony\Component\Console\Helper\Table; use Symfony\Component\Console\Input\InputInterface; use Composer\Console\Input\InputOption; use Composer\Console\Input\InputArgument; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Question\Question; /** * @author Jordi Boggiano @@ -64,8 +72,8 @@ protected function configure() new InputOption('no-autoloader', null, InputOption::VALUE_NONE, 'Skips autoloader generation'), new InputOption('no-suggest', null, InputOption::VALUE_NONE, 'DEPRECATED: This flag does not exist anymore.'), new InputOption('no-progress', null, InputOption::VALUE_NONE, 'Do not output download progress.'), - new InputOption('with-dependencies', 'w', InputOption::VALUE_NONE, 'Update also dependencies of packages in the argument list, except those which are root requirements.'), - new InputOption('with-all-dependencies', 'W', InputOption::VALUE_NONE, 'Update also dependencies of packages in the argument list, including those which are root requirements.'), + new InputOption('with-dependencies', 'w', InputOption::VALUE_NONE, 'Update also dependencies of packages in the argument list, except those which are root requirements (can also be set via the COMPOSER_WITH_DEPENDENCIES=1 env var).'), + new InputOption('with-all-dependencies', 'W', InputOption::VALUE_NONE, 'Update also dependencies of packages in the argument list, including those which are root requirements (can also be set via the COMPOSER_WITH_ALL_DEPENDENCIES=1 env var).'), new InputOption('verbose', 'v|vv|vvv', InputOption::VALUE_NONE, 'Shows more details including new commits pulled in when updating packages.'), new InputOption('optimize-autoloader', 'o', InputOption::VALUE_NONE, 'Optimize autoloader during autoloader dump.'), new InputOption('classmap-authoritative', 'a', InputOption::VALUE_NONE, 'Autoload classes from the classmap only. Implicitly enables `--optimize-autoloader`.'), @@ -76,8 +84,10 @@ protected function configure() new InputOption('prefer-stable', null, InputOption::VALUE_NONE, 'Prefer stable versions of dependencies (can also be set via the COMPOSER_PREFER_STABLE=1 env var).'), new InputOption('prefer-lowest', null, InputOption::VALUE_NONE, 'Prefer lowest versions of dependencies (can also be set via the COMPOSER_PREFER_LOWEST=1 env var).'), new InputOption('minimal-changes', 'm', InputOption::VALUE_NONE, 'During a partial update with -w/-W, only perform absolutely necessary changes to transitive dependencies (can also be set via the COMPOSER_MINIMAL_CHANGES=1 env var).'), + new InputOption('patch-only', null, InputOption::VALUE_NONE, 'Only allow patch version updates for currently installed dependencies.'), new InputOption('interactive', 'i', InputOption::VALUE_NONE, 'Interactive interface with autocompletion to select the packages to update.'), new InputOption('root-reqs', null, InputOption::VALUE_NONE, 'Restricts the update to your first degree dependencies.'), + new InputOption('bump-after-update', null, InputOption::VALUE_OPTIONAL, 'Runs bump after performing the update.', false, ['dev', 'no-dev', 'all']), ]) ->setHelp( <<getOption('patch-only')) { + if (!$composer->getLocker()->isLocked()) { + throw new \InvalidArgumentException('patch-only can only be used with a lock file present'); + } + foreach ($composer->getLocker()->getLockedRepository(true)->getCanonicalPackages() as $package) { + if ($package->isDev()) { + continue; + } + if (!Preg::isMatch('{^(\d+\.\d+\.\d+)}', $package->getVersion(), $match)) { + continue; + } + $constraint = $parser->parseConstraints('~'.$match[1]); + if (isset($temporaryConstraints[$package->getName()])) { + $temporaryConstraints[$package->getName()] = MultiConstraint::create([$temporaryConstraints[$package->getName()], $constraint], true); + } else { + $temporaryConstraints[$package->getName()] = $constraint; + } + } + } + if ($input->getOption('interactive')) { $packages = $this->getPackagesInteractively($io, $input, $output, $composer, $packages); } @@ -248,7 +278,28 @@ protected function execute(InputInterface $input, OutputInterface $output): int $install->disablePlugins(); } - return $install->run(); + $result = $install->run(); + + if ($result === 0 && !$input->getOption('lock')) { + $bumpAfterUpdate = $input->getOption('bump-after-update'); + if (false === $bumpAfterUpdate) { + $bumpAfterUpdate = $composer->getConfig()->get('bump-after-update'); + } + + if (false !== $bumpAfterUpdate) { + $io->writeError('Bumping dependencies'); + $bumpCommand = new BumpCommand(); + $bumpCommand->setComposer($composer); + $result = $bumpCommand->doBump( + $io, + $bumpAfterUpdate === 'dev', + $bumpAfterUpdate === 'no-dev', + $input->getOption('dry-run'), + $input->getArgument('packages') + ); + } + } + return $result; } /** @@ -261,48 +312,53 @@ private function getPackagesInteractively(IOInterface $io, InputInterface $input throw new \InvalidArgumentException('--interactive cannot be used in non-interactive terminals.'); } + $platformReqFilter = $this->getPlatformRequirementFilter($input); + $stabilityFlags = $composer->getPackage()->getStabilityFlags(); $requires = array_merge( $composer->getPackage()->getRequires(), $composer->getPackage()->getDevRequires() ); - $autocompleterValues = []; - foreach ($requires as $require) { - $target = $require->getTarget(); - $autocompleterValues[strtolower($target)] = $target; - } - - $installedPackages = $composer->getRepositoryManager()->getLocalRepository()->getPackages(); - foreach ($installedPackages as $package) { - $autocompleterValues[$package->getName()] = $package->getPrettyName(); - } - - $helper = $this->getHelper('question'); - $question = new Question('Enter package name: ', null); - $io->writeError('Press enter without value to end submission'); + $filter = \count($packages) > 0 ? BasePackage::packageNamesToRegexp($packages) : null; - do { - $autocompleterValues = array_diff($autocompleterValues, $packages); - $question->setAutocompleterValues($autocompleterValues); - $addedPackage = $helper->ask($input, $output, $question); - - if (!is_string($addedPackage) || empty($addedPackage)) { - break; + $io->writeError('Loading packages that can be updated...'); + $autocompleterValues = []; + $installedPackages = $composer->getLocker()->isLocked() ? $composer->getLocker()->getLockedRepository(true)->getPackages() : $composer->getRepositoryManager()->getLocalRepository()->getPackages(); + $versionSelector = $this->createVersionSelector($composer); + foreach ($installedPackages as $package) { + if ($filter !== null && !Preg::isMatch($filter, $package->getName())) { + continue; } - - $addedPackage = strtolower($addedPackage); - if (!in_array($addedPackage, $packages)) { - $packages[] = $addedPackage; + $currentVersion = $package->getPrettyVersion(); + $constraint = isset($requires[$package->getName()]) ? $requires[$package->getName()]->getPrettyConstraint() : null; + $stability = isset($stabilityFlags[$package->getName()]) ? (string) array_search($stabilityFlags[$package->getName()], BasePackage::STABILITIES, true) : $composer->getPackage()->getMinimumStability(); + $latestVersion = $versionSelector->findBestCandidate($package->getName(), $constraint, $stability, $platformReqFilter); + if ($latestVersion !== false && ($package->getVersion() !== $latestVersion->getVersion() || $latestVersion->isDev())) { + $autocompleterValues[$package->getName()] = '' . $currentVersion . ' => ' . $latestVersion->getPrettyVersion() . ''; } - } while (true); + } + if (0 === \count($installedPackages)) { + foreach ($requires as $req => $constraint) { + if (PlatformRepository::isPlatformPackage($req)) { + continue; + } + $autocompleterValues[$req] = ''; + } + } - $packages = array_filter($packages, function (string $pkg) { - return $pkg !== ''; - }); - if (!$packages) { - throw new \InvalidArgumentException('You must enter minimum one package.'); + if (0 === \count($autocompleterValues)) { + throw new \RuntimeException('Could not find any package with new versions available'); } + $packages = $io->select( + 'Select packages: (Select more than one value separated by comma) ', + $autocompleterValues, + false, + 1, + 'No package named "%s" is installed.', + true + ); + $table = new Table($output); $table->setHeaders(['Selected packages']); foreach ($packages as $package) { @@ -319,4 +375,14 @@ private function getPackagesInteractively(IOInterface $io, InputInterface $input throw new \RuntimeException('Installation aborted.'); } + + private function createVersionSelector(Composer $composer): VersionSelector + { + $repositorySet = new RepositorySet(); + $repositorySet->addRepository(new CompositeRepository(array_filter($composer->getRepositoryManager()->getRepositories(), function (RepositoryInterface $repository) { + return !$repository instanceof PlatformRepository; + }))); + + return new VersionSelector($repositorySet); + } } diff --git a/app/vendor/composer/composer/src/Composer/Command/ValidateCommand.php b/app/vendor/composer/composer/src/Composer/Command/ValidateCommand.php index d9d8c7510..fb71081d4 100644 --- a/app/vendor/composer/composer/src/Composer/Command/ValidateCommand.php +++ b/app/vendor/composer/composer/src/Composer/Command/ValidateCommand.php @@ -68,7 +68,7 @@ protected function configure(): void protected function execute(InputInterface $input, OutputInterface $output): int { - $file = $input->getArgument('file') ?: Factory::getComposerFile(); + $file = $input->getArgument('file') ?? Factory::getComposerFile(); $io = $this->getIO(); if (!file_exists($file)) { @@ -144,16 +144,16 @@ private function outputResult(IOInterface $io, string $name, array &$errors, arr { $doPrintSchemaUrl = false; - if ($errors) { + if (\count($errors) > 0) { $io->writeError('' . $name . ' is invalid, the following errors/warnings were found:'); - } elseif ($publishErrors) { + } elseif (\count($publishErrors) > 0 && $checkPublish) { $io->writeError('' . $name . ' is valid for simple usage with Composer but has'); $io->writeError('strict errors that make it unable to be published as a package'); $doPrintSchemaUrl = $printSchemaUrl; - } elseif ($warnings) { + } elseif (\count($warnings) > 0) { $io->writeError('' . $name . ' is valid, but with a few warnings'); $doPrintSchemaUrl = $printSchemaUrl; - } elseif ($lockErrors) { + } elseif (\count($lockErrors) > 0) { $io->write('' . $name . ' is valid but your composer.lock has some '.($checkLock ? 'errors' : 'warnings').''); } else { $io->write('' . $name . ' is valid'); @@ -163,13 +163,13 @@ private function outputResult(IOInterface $io, string $name, array &$errors, arr $io->writeError('See https://getcomposer.org/doc/04-schema.md for details on the schema'); } - if ($errors) { + if (\count($errors) > 0) { $errors = array_map(static function ($err): string { return '- ' . $err; }, $errors); array_unshift($errors, '# General errors'); } - if ($warnings) { + if (\count($warnings) > 0) { $warnings = array_map(static function ($err): string { return '- ' . $err; }, $warnings); @@ -180,22 +180,17 @@ private function outputResult(IOInterface $io, string $name, array &$errors, arr $extraWarnings = []; // If checking publish errors, display them as errors, otherwise just show them as warnings - if ($publishErrors) { + if (\count($publishErrors) > 0 && $checkPublish) { $publishErrors = array_map(static function ($err): string { return '- ' . $err; }, $publishErrors); - if ($checkPublish) { - array_unshift($publishErrors, '# Publish errors'); - $errors = array_merge($errors, $publishErrors); - } else { - array_unshift($publishErrors, '# Publish warnings'); - $extraWarnings = array_merge($extraWarnings, $publishErrors); - } + array_unshift($publishErrors, '# Publish errors'); + $errors = array_merge($errors, $publishErrors); } // If checking lock errors, display them as errors, otherwise just show them as warnings - if ($lockErrors) { + if (\count($lockErrors) > 0) { if ($checkLock) { array_unshift($lockErrors, '# Lock file errors'); $errors = array_merge($errors, $lockErrors); diff --git a/app/vendor/composer/composer/src/Composer/Compiler.php b/app/vendor/composer/composer/src/Composer/Compiler.php index 9a2e27f5b..ed5d3ad04 100644 --- a/app/vendor/composer/composer/src/Composer/Compiler.php +++ b/app/vendor/composer/composer/src/Composer/Compiler.php @@ -15,6 +15,7 @@ use Composer\Json\JsonFile; use Composer\CaBundle\CaBundle; use Composer\Pcre\Preg; +use Composer\Util\ProcessExecutor; use Symfony\Component\Finder\Finder; use Symfony\Component\Process\Process; use Seld\PharUtils\Timestamps; @@ -48,23 +49,22 @@ public function compile(string $pharFile = 'composer.phar'): void unlink($pharFile); } - $process = new Process(['git', 'log', '--pretty=%H', '-n1', 'HEAD'], __DIR__); - if ($process->run() !== 0) { + $process = new ProcessExecutor(); + + if (0 !== $process->execute(['git', 'log', '--pretty=%H', '-n1', 'HEAD'], $output, dirname(dirname(__DIR__)))) { throw new \RuntimeException('Can\'t run git log. You must ensure to run compile from composer git repository clone and that git binary is available.'); } - $this->version = trim($process->getOutput()); + $this->version = trim($output); - $process = new Process(['git', 'log', '-n1', '--pretty=%ci', 'HEAD'], __DIR__); - if ($process->run() !== 0) { + if (0 !== $process->execute(['git', 'log', '-n1', '--pretty=%ci', 'HEAD'], $output, dirname(dirname(__DIR__)))) { throw new \RuntimeException('Can\'t run git log. You must ensure to run compile from composer git repository clone and that git binary is available.'); } - $this->versionDate = new \DateTime(trim($process->getOutput())); + $this->versionDate = new \DateTime(trim($output)); $this->versionDate->setTimezone(new \DateTimeZone('UTC')); - $process = new Process(['git', 'describe', '--tags', '--exact-match', 'HEAD'], __DIR__); - if ($process->run() === 0) { - $this->version = trim($process->getOutput()); + if (0 === $process->execute(['git', 'describe', '--tags', '--exact-match', 'HEAD'], $output, dirname(dirname(__DIR__)))) { + $this->version = trim($output); } else { // get branch-alias defined in composer.json for dev-main (if any) $localConfig = __DIR__.'/../../composer.json'; @@ -75,6 +75,10 @@ public function compile(string $pharFile = 'composer.phar'): void } } + if ('' === $this->version) { + throw new \UnexpectedValueException('Version detection failed'); + } + $phar = new \Phar($pharFile, 0, 'composer.phar'); $phar->setSignatureAlgorithm(\Phar::SHA512); @@ -116,10 +120,11 @@ public function compile(string $pharFile = 'composer.phar'): void $finder = new Finder(); $finder->files() ->ignoreVCS(true) - ->notPath('/\/(composer\.(json|lock)|[A-Z]+\.md(?:own)?|\.gitignore|appveyor.yml|phpunit\.xml\.dist|phpstan\.neon\.dist|phpstan-config\.neon|phpstan-baseline\.neon)$/') + ->notPath('/\/(composer\.(?:json|lock)|[A-Z]+\.md(?:own)?|\.gitignore|appveyor.yml|phpunit\.xml\.dist|phpstan\.neon\.dist|phpstan-config\.neon|phpstan-baseline\.neon|UPGRADE.*\.(?:md|txt))$/') ->notPath('/bin\/(jsonlint|validate-json|simple-phpunit|phpstan|phpstan\.phar)(\.bat)?$/') ->notPath('justinrainbow/json-schema/demo/') ->notPath('justinrainbow/json-schema/dist/') + ->notPath('composer/pcre/extension.neon') ->notPath('composer/LICENSE') ->exclude('Tests') ->exclude('tests') @@ -147,7 +152,7 @@ public function compile(string $pharFile = 'composer.phar'): void foreach ($finder as $file) { if (false !== ($index = array_search($file->getRealPath(), $extraFiles, true))) { unset($extraFiles[$index]); - } elseif (!Preg::isMatch('{(^LICENSE$|\.php$)}', $file->getFilename())) { + } elseif (!Preg::isMatch('{(^LICENSE(?:\.txt)?$|\.php$)}', $file->getFilename())) { $unexpectedFiles[] = (string) $file; } diff --git a/app/vendor/composer/composer/src/Composer/Composer.php b/app/vendor/composer/composer/src/Composer/Composer.php index 8d87940c3..d9e0ccf1a 100644 --- a/app/vendor/composer/composer/src/Composer/Composer.php +++ b/app/vendor/composer/composer/src/Composer/Composer.php @@ -51,9 +51,9 @@ class Composer extends PartialComposer * * @see getVersion() */ - public const VERSION = '2.7.6'; + public const VERSION = '2.8.10'; public const BRANCH_ALIAS_VERSION = ''; - public const RELEASE_DATE = '2024-05-04 23:03:15'; + public const RELEASE_DATE = '2025-07-10 19:08:33'; public const SOURCE_VERSION = ''; /** diff --git a/app/vendor/composer/composer/src/Composer/Config.php b/app/vendor/composer/composer/src/Composer/Config.php index 8d2885a3c..f39579e06 100644 --- a/app/vendor/composer/composer/src/Composer/Config.php +++ b/app/vendor/composer/composer/src/Composer/Config.php @@ -84,6 +84,8 @@ class Config 'gitlab-token' => [], 'http-basic' => [], 'bearer' => [], + 'bump-after-update' => false, + 'allow-missing-requirements' => false, ]; /** @var array */ @@ -96,7 +98,7 @@ class Config /** @var array */ private $config; - /** @var ?string */ + /** @var ?non-empty-string */ private $baseDir; /** @var array */ private $repositories; @@ -125,7 +127,7 @@ public function __construct(bool $useEnvironment = true, ?string $baseDir = null $this->config = static::$defaultConfig; $this->repositories = static::$defaultRepositories; - $this->useEnvironment = (bool) $useEnvironment; + $this->useEnvironment = $useEnvironment; $this->baseDir = is_string($baseDir) && '' !== $baseDir ? $baseDir : null; foreach ($this->config as $configKey => $configValue) { @@ -137,6 +139,18 @@ public function __construct(bool $useEnvironment = true, ?string $baseDir = null } } + /** + * Changing this can break path resolution for relative config paths so do not call this without knowing what you are doing + * + * The $baseDir should be an absolute path and without trailing slash + * + * @param non-empty-string|null $baseDir + */ + public function setBaseDir(?string $baseDir): void + { + $this->baseDir = $baseDir; + } + public function setConfigSource(ConfigSourceInterface $source): void { $this->configSource = $source; @@ -440,9 +454,9 @@ public function get(string $key, int $flags = 0) $result = $this->config[$key]; $abandonedEnv = $this->getComposerEnv('COMPOSER_AUDIT_ABANDONED'); if (false !== $abandonedEnv) { - if (!in_array($abandonedEnv, $validChoices = [Auditor::ABANDONED_IGNORE, Auditor::ABANDONED_REPORT, Auditor::ABANDONED_FAIL], true)) { + if (!in_array($abandonedEnv, $validChoices = Auditor::ABANDONEDS, true)) { throw new \RuntimeException( - "Invalid value for COMPOSER_AUDIT_ABANDONED: {$abandonedEnv}. Expected ".Auditor::ABANDONED_IGNORE.", ".Auditor::ABANDONED_REPORT." or ".Auditor::ABANDONED_FAIL + "Invalid value for COMPOSER_AUDIT_ABANDONED: {$abandonedEnv}. Expected one of ".implode(', ', Auditor::ABANDONEDS)."." ); } $result['abandoned'] = $abandonedEnv; @@ -529,7 +543,6 @@ private function process($value, int $flags) } return Preg::replaceCallback('#\{\$(.+)\}#', function ($match) use ($flags) { - assert(is_string($match[1])); return $this->get($match[1], $flags); }, $value); } @@ -545,7 +558,7 @@ private function realpath(string $path): string return $path; } - return $this->baseDir ? $this->baseDir . '/' . $path : $path; + return $this->baseDir !== null ? $this->baseDir . '/' . $path : $path; } /** @@ -584,8 +597,8 @@ private function disableRepoByName(string $name): void */ public function prohibitUrlByConfig(string $url, ?IOInterface $io = null, array $repoOptions = []): void { - // Return right away if the URL is malformed or custom (see issue #5173) - if (false === filter_var($url, FILTER_VALIDATE_URL)) { + // Return right away if the URL is malformed or custom (see issue #5173), but only for non-HTTP(S) URLs + if (false === filter_var($url, FILTER_VALIDATE_URL) && !Preg::isMatch('{^https?://}', $url)) { return; } diff --git a/app/vendor/composer/composer/src/Composer/Config/JsonConfigSource.php b/app/vendor/composer/composer/src/Composer/Config/JsonConfigSource.php index db3d36dc4..596d14f52 100644 --- a/app/vendor/composer/composer/src/Composer/Config/JsonConfigSource.php +++ b/app/vendor/composer/composer/src/Composer/Config/JsonConfigSource.php @@ -162,7 +162,7 @@ public function addProperty(string $name, $value): void public function removeProperty(string $name): void { $this->manipulateJson('removeProperty', static function (&$config, $key): void { - if (strpos($key, 'extra.') === 0 || strpos($key, 'scripts.') === 0) { + if (strpos($key, 'extra.') === 0 || strpos($key, 'scripts.') === 0 || stripos($key, 'autoload.') === 0 || stripos($key, 'autoload-dev.') === 0) { $bits = explode('.', $key); $last = array_pop($bits); $arr = &$config[reset($bits)]; diff --git a/app/vendor/composer/composer/src/Composer/Console/Application.php b/app/vendor/composer/composer/src/Composer/Console/Application.php index 7919c29d9..3e46b970a 100644 --- a/app/vendor/composer/composer/src/Composer/Console/Application.php +++ b/app/vendor/composer/composer/src/Composer/Console/Application.php @@ -19,9 +19,9 @@ use Composer\Util\Silencer; use LogicException; use RuntimeException; -use Seld\Signal\SignalHandler; use Symfony\Component\Console\Application as BaseApplication; use Symfony\Component\Console\Exception\CommandNotFoundException; +use Symfony\Component\Console\Exception\ExceptionInterface; use Symfony\Component\Console\Helper\HelperSet; use Symfony\Component\Console\Helper\QuestionHelper; use Symfony\Component\Console\Input\InputDefinition; @@ -43,7 +43,6 @@ use Composer\Exception\NoSslException; use Composer\XdebugHandler\XdebugHandler; use Symfony\Component\Process\Exception\ProcessTimedOutException; -use Composer\Util\Http\ProxyManager; /** * The console application that handles the commands @@ -85,9 +84,6 @@ class Application extends BaseApplication */ private $initialWorkingDirectory; - /** @var SignalHandler */ - private $signalHandler; - public function __construct(string $name = 'Composer', string $version = '') { if (method_exists($this, 'setCatchErrors')) { @@ -109,12 +105,6 @@ public function __construct(string $name = 'Composer', string $version = '') $this->io = new NullIO(); - $this->signalHandler = SignalHandler::create([SignalHandler::SIGINT, SignalHandler::SIGTERM, SignalHandler::SIGHUP], function (string $signal, SignalHandler $handler) { - $this->io->writeError('Received '.$signal.', aborting', true, IOInterface::DEBUG); - - $handler->exitWithLastSignal(); - }); - if (!$shutdownRegistered) { $shutdownRegistered = true; @@ -136,7 +126,6 @@ public function __construct(string $name = 'Composer', string $version = '') public function __destruct() { - $this->signalHandler->unregister(); } public function run(?InputInterface $input = null, ?OutputInterface $output = null): int @@ -153,7 +142,10 @@ public function doRun(InputInterface $input, OutputInterface $output): int $this->disablePluginsByDefault = $input->hasParameterOption('--no-plugins'); $this->disableScriptsByDefault = $input->hasParameterOption('--no-scripts'); - $stdin = defined('STDIN') ? STDIN : fopen('php://stdin', 'r'); + static $stdin = null; + if (null === $stdin) { + $stdin = defined('STDIN') ? STDIN : fopen('php://stdin', 'r'); + } if (Platform::getEnv('COMPOSER_TESTS_ARE_RUNNING') !== '1' && (Platform::getEnv('COMPOSER_NO_INTERACTION') || $stdin === false || !Platform::isTty($stdin))) { $input->setInteractive(false); } @@ -182,7 +174,7 @@ public function doRun(InputInterface $input, OutputInterface $output): int // determine command name to be executed without including plugin commands $commandName = ''; - if ($name = $this->getCommandName($input)) { + if ($name = $this->getCommandNameBeforeBinding($input)) { try { $commandName = $this->find($name)->getName(); } catch (CommandNotFoundException $e) { @@ -193,13 +185,29 @@ public function doRun(InputInterface $input, OutputInterface $output): int } // prompt user for dir change if no composer.json is present in current dir - if ($io->isInteractive() && null === $newWorkDir && !in_array($commandName, ['', 'list', 'init', 'about', 'help', 'diagnose', 'self-update', 'global', 'create-project', 'outdated'], true) && !file_exists(Factory::getComposerFile()) && ($useParentDirIfNoJsonAvailable = $this->getUseParentDirConfigValue()) !== false) { + if ( + null === $newWorkDir + // do not prompt for commands that can function without composer.json + && !in_array($commandName, ['', 'list', 'init', 'about', 'help', 'diagnose', 'self-update', 'global', 'create-project', 'outdated'], true) + && !file_exists(Factory::getComposerFile()) + // if use-parent-dir is disabled we should not prompt + && ($useParentDirIfNoJsonAvailable = $this->getUseParentDirConfigValue()) !== false + // config --file ... should not prompt + && ($commandName !== 'config' || ($input->hasParameterOption('--file', true) === false && $input->hasParameterOption('-f', true) === false)) + // calling a command's help should not prompt + && $input->hasParameterOption('--help', true) === false + && $input->hasParameterOption('-h', true) === false + ) { $dir = dirname(Platform::getCwd(true)); $home = realpath(Platform::getEnv('HOME') ?: Platform::getEnv('USERPROFILE') ?: '/'); // abort when we reach the home dir or top of the filesystem while (dirname($dir) !== $dir && $dir !== $home) { if (file_exists($dir.'/'.Factory::getComposerFile())) { + if ($useParentDirIfNoJsonAvailable !== true && !$io->isInteractive()) { + $io->writeError('No composer.json in current directory, to use the one at '.$dir.' run interactively or set config.use-parent-dir to true'); + break; + } if ($useParentDirIfNoJsonAvailable === true || $io->askConfirmation('No composer.json in current directory, do you want to use the one at '.$dir.'? [Y,n]? ')) { if ($useParentDirIfNoJsonAvailable === true) { $io->writeError('No composer.json in current directory, changing working directory to '.$dir.''); @@ -213,16 +221,13 @@ public function doRun(InputInterface $input, OutputInterface $output): int } $dir = dirname($dir); } + unset($dir, $home); } $needsSudoCheck = !Platform::isWindows() && function_exists('exec') && !Platform::getEnv('COMPOSER_ALLOW_SUPERUSER') - && (ini_get('open_basedir') || ( - !file_exists('/.dockerenv') - && !file_exists('/run/.containerenv') - && !file_exists('/var/run/.containerenv') - )); + && !Platform::isDocker(); $isNonAllowedRoot = false; // Clobber sudo credentials if COMPOSER_ALLOW_SUPERUSER is not set before loading plugins @@ -275,7 +280,8 @@ public function doRun(InputInterface $input, OutputInterface $output): int if ($this->has($command->getName())) { $io->writeError('Plugin command '.$command->getName().' ('.get_class($command).') would override a Composer command and has been skipped'); } else { - $this->add($command); + // Compatibility layer for symfony/console <7.4 + method_exists($this, 'addCommand') ? $this->addCommand($command) : $this->add($command); } } } catch (NoSslException $e) { @@ -307,7 +313,7 @@ public function doRun(InputInterface $input, OutputInterface $output): int // determine command name to be executed incl plugin commands, and check if it's a proxy command $isProxyCommand = false; - if ($name = $this->getCommandName($input)) { + if ($name = $this->getCommandNameBeforeBinding($input)) { try { $command = $this->find($name); $commandName = $command->getName(); @@ -325,7 +331,7 @@ public function doRun(InputInterface $input, OutputInterface $output): int function_exists('php_uname') ? php_uname('s') . ' / ' . php_uname('r') : 'Unknown OS' ), true, IOInterface::DEBUG); - if (PHP_VERSION_ID < 70205) { + if (\PHP_VERSION_ID < 70205) { $io->writeError('Composer supports PHP 7.2.5 and above, you will most likely encounter problems with your PHP '.PHP_VERSION.'. Upgrading is strongly recommended but you can use Composer 2.2.x LTS as a fallback.'); } @@ -352,7 +358,7 @@ function_exists('php_uname') ? php_uname('s') . ' / ' . php_uname('r') : 'Unknow // Check system temp folder for usability as it can cause weird runtime issues otherwise Silencer::call(static function () use ($io): void { $pid = function_exists('getmypid') ? getmypid() . '-' : ''; - $tempfile = sys_get_temp_dir() . '/temp-' . $pid . md5(microtime()); + $tempfile = sys_get_temp_dir() . '/temp-' . $pid . bin2hex(random_bytes(5)); if (!(file_put_contents($tempfile, __FILE__) && (file_get_contents($tempfile) === __FILE__) && unlink($tempfile) && !file_exists($tempfile))) { $io->writeError(sprintf('PHP temp directory (%s) does not exist or is not writable to Composer. Set sys_temp_dir in your php.ini', sys_get_temp_dir())); } @@ -375,7 +381,9 @@ function_exists('php_uname') ? php_uname('s') . ' / ' . php_uname('r') : 'Unknow $aliases = $composer['scripts-aliases'][$script] ?? []; - $this->add(new Command\ScriptAliasCommand($script, $description, $aliases)); + $scriptAlias = new Command\ScriptAliasCommand($script, $description, $aliases); + // Compatibility layer for symfony/console <7.4 + method_exists($this, 'addCommand') ? $this->addCommand($scriptAlias) : $this->add($scriptAlias); } } } @@ -384,8 +392,6 @@ function_exists('php_uname') ? php_uname('s') . ' / ' . php_uname('r') : 'Unknow } try { - $proxyManager = ProxyManager::getInstance(); - if ($input->hasParameterOption('--profile')) { $startTime = microtime(true); $this->io->enableDebugging($startTime); @@ -404,15 +410,7 @@ function_exists('php_uname') ? php_uname('s') . ' / ' . php_uname('r') : 'Unknow } if (isset($startTime)) { - $io->writeError('Memory usage: '.round(memory_get_usage() / 1024 / 1024, 2).'MiB (peak: '.round(memory_get_peak_usage() / 1024 / 1024, 2).'MiB), time: '.round(microtime(true) - $startTime, 2).'s'); - } - - if ($proxyManager->needsTransitionWarning()) { - $io->writeError(''); - $io->writeError('Composer now requires separate proxy environment variables for HTTP and HTTPS requests.'); - $io->writeError('Please set `https_proxy` in addition to your existing proxy environment variables.'); - $io->writeError('This fallback (and warning) will be removed in Composer 2.8.0.'); - $io->writeError('https://getcomposer.org/doc/faqs/how-to-use-composer-behind-a-proxy.md'); + $io->writeError('Memory usage: '.round(memory_get_usage() / 1024 / 1024, 2).'MiB (peak: '.round(memory_get_peak_usage() / 1024 / 1024, 2).'MiB), time: '.round(microtime(true) - $startTime, 2).'s'); } return $result; @@ -446,6 +444,7 @@ function_exists('php_uname') ? php_uname('s') . ' / ' . php_uname('r') : 'Unknow // as http error codes are all beyond the 255 range of permitted exit codes if ($e instanceof TransportException) { $reflProp = new \ReflectionProperty($e, 'code'); + $reflProp->setAccessible(true); $reflProp->setValue($e, Installer::ERROR_TRANSPORT_EXCEPTION); } @@ -501,6 +500,17 @@ private function hintCommonErrors(\Throwable $exception, OutputInterface $output $io->writeError('Check https://getcomposer.org/doc/faqs/how-to-use-composer-behind-a-proxy.md for details', true, IOInterface::QUIET); } + if (Platform::isWindows() && $exception instanceof TransportException && str_contains($exception->getMessage(), 'unable to get local issuer certificate')) { + $avastDetect = glob('C:\Program Files\Avast*'); + if (is_array($avastDetect) && count($avastDetect) !== 0) { + $io->writeError('The following exception indicates a possible issue with the Avast Firewall', true, IOInterface::QUIET); + $io->writeError('Check https://getcomposer.org/local-issuer for details', true, IOInterface::QUIET); + } else { + $io->writeError('The following exception indicates a possible issue with a Firewall/Antivirus', true, IOInterface::QUIET); + $io->writeError('Check https://getcomposer.org/local-issuer for details', true, IOInterface::QUIET); + } + } + if (Platform::isWindows() && false !== strpos($exception->getMessage(), 'The system cannot find the path specified')) { $io->writeError('The following exception may be caused by a stale entry in your cmd.exe AutoRun', true, IOInterface::QUIET); $io->writeError('Check https://getcomposer.org/doc/articles/troubleshooting.md#-the-system-cannot-find-the-path-specified-windows- for details', true, IOInterface::QUIET); @@ -636,6 +646,24 @@ protected function getDefaultCommands(): array return $commands; } + /** + * This ensures we can find the correct command name even if a global input option is present before it + * + * e.g. "composer -d foo bar" should detect bar as the command name, and not foo + */ + private function getCommandNameBeforeBinding(InputInterface $input): ?string + { + $input = clone $input; + try { + // Makes ArgvInput::getFirstArgument() able to distinguish an option from an argument. + $input->bind($this->getDefinition()); + } catch (ExceptionInterface $e) { + // Errors must be ignored, full binding/validation happens later when the command is known. + } + + return $input->getFirstArgument(); + } + public function getLongVersion(): string { $branchAliasString = ''; diff --git a/app/vendor/composer/composer/src/Composer/Console/Input/InputArgument.php b/app/vendor/composer/composer/src/Composer/Console/Input/InputArgument.php index b6d064fc8..19aff8c33 100644 --- a/app/vendor/composer/composer/src/Composer/Console/Input/InputArgument.php +++ b/app/vendor/composer/composer/src/Composer/Console/Input/InputArgument.php @@ -26,7 +26,7 @@ * * @internal * - * TODO drop when PHP 8.1 / symfony 6.1+ can be required + * TODO symfony/console:6.1 drop when PHP 8.1 / symfony 6.1+ can be required */ class InputArgument extends BaseInputArgument { @@ -59,7 +59,7 @@ public function __construct(string $name, ?int $mode = null, string $description public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void { $values = $this->suggestedValues; - if ($values instanceof \Closure && !\is_array($values = $values($input, $suggestions))) { // @phpstan-ignore-line + if ($values instanceof \Closure && !\is_array($values = $values($input, $suggestions))) { // @phpstan-ignore function.impossibleType throw new LogicException(sprintf('Closure for option "%s" must return an array. Got "%s".', $this->getName(), get_debug_type($values))); } if ([] !== $values) { diff --git a/app/vendor/composer/composer/src/Composer/Console/Input/InputOption.php b/app/vendor/composer/composer/src/Composer/Console/Input/InputOption.php index 75bfe90d9..b5ff333cd 100644 --- a/app/vendor/composer/composer/src/Composer/Console/Input/InputOption.php +++ b/app/vendor/composer/composer/src/Composer/Console/Input/InputOption.php @@ -26,7 +26,7 @@ * * @internal * - * TODO drop when PHP 8.1 / symfony 6.1+ can be required + * TODO symfony/console:6.1 drop when PHP 8.1 / symfony 6.1+ can be required */ class InputOption extends BaseInputOption { @@ -62,7 +62,7 @@ public function __construct(string $name, $shortcut = null, ?int $mode = null, s public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void { $values = $this->suggestedValues; - if ($values instanceof \Closure && !\is_array($values = $values($input, $suggestions))) { // @phpstan-ignore-line + if ($values instanceof \Closure && !\is_array($values = $values($input, $suggestions))) { // @phpstan-ignore function.impossibleType throw new LogicException(sprintf('Closure for argument "%s" must return an array. Got "%s".', $this->getName(), get_debug_type($values))); } if ([] !== $values) { diff --git a/app/vendor/composer/composer/src/Composer/DependencyResolver/Decisions.php b/app/vendor/composer/composer/src/Composer/DependencyResolver/Decisions.php index 9a5c9c235..599110750 100644 --- a/app/vendor/composer/composer/src/Composer/DependencyResolver/Decisions.php +++ b/app/vendor/composer/composer/src/Composer/DependencyResolver/Decisions.php @@ -28,7 +28,7 @@ class Decisions implements \Iterator, \Countable /** @var array */ protected $decisionMap; /** - * @var array + * @var array */ protected $decisionQueue = []; @@ -69,12 +69,12 @@ public function conflict(int $literal): bool public function decided(int $literalOrPackageId): bool { - return !empty($this->decisionMap[abs($literalOrPackageId)]); + return ($this->decisionMap[abs($literalOrPackageId)] ?? 0) !== 0; } public function undecided(int $literalOrPackageId): bool { - return empty($this->decisionMap[abs($literalOrPackageId)]); + return ($this->decisionMap[abs($literalOrPackageId)] ?? 0) === 0; } public function decidedInstall(int $literalOrPackageId): bool @@ -94,7 +94,7 @@ public function decisionLevel(int $literalOrPackageId): int return 0; } - public function decisionRule(int $literalOrPackageId): ?Rule + public function decisionRule(int $literalOrPackageId): Rule { $packageId = abs($literalOrPackageId); @@ -104,7 +104,7 @@ public function decisionRule(int $literalOrPackageId): ?Rule } } - return null; + throw new \LogicException('Did not find a decision rule using '.$literalOrPackageId); } /** @@ -219,7 +219,7 @@ public function toString(?Pool $pool = null): string ksort($decisionMap); $str = '['; foreach ($decisionMap as $packageId => $level) { - $str .= (($pool) ? $pool->literalToPackage($packageId) : $packageId).':'.$level.','; + $str .= ($pool !== null ? $pool->literalToPackage($packageId) : $packageId).':'.$level.','; } $str .= ']'; diff --git a/app/vendor/composer/composer/src/Composer/DependencyResolver/DefaultPolicy.php b/app/vendor/composer/composer/src/Composer/DependencyResolver/DefaultPolicy.php index f8176ae72..590187026 100644 --- a/app/vendor/composer/composer/src/Composer/DependencyResolver/DefaultPolicy.php +++ b/app/vendor/composer/composer/src/Composer/DependencyResolver/DefaultPolicy.php @@ -30,7 +30,7 @@ class DefaultPolicy implements PolicyInterface private $preferLowest; /** @var array|null */ private $preferredVersions; - /** @var array>> */ + /** @var array>> */ private $preferredPackageResultCachePerPool; /** @var array> */ private $sortingCachePerPool; @@ -53,11 +53,11 @@ public function __construct(bool $preferStable = false, bool $preferLowest = fal public function versionCompare(PackageInterface $a, PackageInterface $b, string $operator): bool { if ($this->preferStable && ($stabA = $a->getStability()) !== ($stabB = $b->getStability())) { - return BasePackage::$stabilities[$stabA] < BasePackage::$stabilities[$stabB]; + return BasePackage::STABILITIES[$stabA] < BasePackage::STABILITIES[$stabB]; } // dev versions need to be compared as branches via matchSpecific's special treatment, the rest can be optimized with compiling matcher - if (strpos($a->getVersion(), 'dev-') === 0 || strpos($b->getVersion(), 'dev-') === 0) { + if (($a->isDev() && str_starts_with($a->getVersion(), 'dev-')) || ($b->isDev() && str_starts_with($b->getVersion(), 'dev-'))) { $constraint = new Constraint($operator, $b->getVersion()); $version = new Constraint('==', $a->getVersion()); @@ -68,9 +68,8 @@ public function versionCompare(PackageInterface $a, PackageInterface $b, string } /** - * @param int[] $literals - * @param string $requiredPackage - * @return int[] + * @param non-empty-list $literals + * @return non-empty-list */ public function selectPreferredPackages(Pool $pool, array $literals, ?string $requiredPackage = null): array { @@ -118,8 +117,8 @@ public function selectPreferredPackages(Pool $pool, array $literals, ?string $re } /** - * @param int[] $literals - * @return array + * @param non-empty-list $literals + * @return non-empty-array> */ protected function groupLiteralsByName(Pool $pool, array $literals): array { @@ -164,7 +163,7 @@ public function compareByPriority(Pool $pool, BasePackage $a, BasePackage $b, ?s // for replacers not replacing each other, put a higher prio on replacing // packages with the same vendor as the required package - if ($requiredPackage && false !== ($pos = strpos($requiredPackage, '/'))) { + if ($requiredPackage !== null && false !== ($pos = strpos($requiredPackage, '/'))) { $requiredVendor = substr($requiredPackage, 0, $pos); $aIsSameVendor = strpos($a->getName(), $requiredVendor) === 0; @@ -205,8 +204,8 @@ protected function replaces(BasePackage $source, BasePackage $target): bool } /** - * @param int[] $literals - * @return int[] + * @param list $literals + * @return list */ protected function pruneToBestVersion(Pool $pool, array $literals): array { @@ -252,8 +251,8 @@ protected function pruneToBestVersion(Pool $pool, array $literals): array * * If no package is a local alias, nothing happens * - * @param int[] $literals - * @return int[] + * @param list $literals + * @return list */ protected function pruneRemoteAliases(Pool $pool, array $literals): array { diff --git a/app/vendor/composer/composer/src/Composer/DependencyResolver/GenericRule.php b/app/vendor/composer/composer/src/Composer/DependencyResolver/GenericRule.php index f7cf7f23c..64dd7a215 100644 --- a/app/vendor/composer/composer/src/Composer/DependencyResolver/GenericRule.php +++ b/app/vendor/composer/composer/src/Composer/DependencyResolver/GenericRule.php @@ -46,7 +46,10 @@ public function getLiterals(): array */ public function getHash() { - $data = unpack('ihash', md5(implode(',', $this->literals), true)); + $data = unpack('ihash', (string) hash(\PHP_VERSION_ID > 80100 ? 'xxh3' : 'sha1', implode(',', $this->literals), true)); + if (false === $data) { + throw new \RuntimeException('Failed unpacking: '.implode(', ', $this->literals)); + } return $data['hash']; } diff --git a/app/vendor/composer/composer/src/Composer/DependencyResolver/MultiConflictRule.php b/app/vendor/composer/composer/src/Composer/DependencyResolver/MultiConflictRule.php index 4826489d2..a61094755 100644 --- a/app/vendor/composer/composer/src/Composer/DependencyResolver/MultiConflictRule.php +++ b/app/vendor/composer/composer/src/Composer/DependencyResolver/MultiConflictRule.php @@ -19,11 +19,11 @@ */ class MultiConflictRule extends Rule { - /** @var list */ + /** @var non-empty-list */ protected $literals; /** - * @param list $literals + * @param non-empty-list $literals */ public function __construct(array $literals, $reason, $reasonData) { @@ -40,7 +40,7 @@ public function __construct(array $literals, $reason, $reasonData) } /** - * @return list + * @return non-empty-list */ public function getLiterals(): array { @@ -52,7 +52,10 @@ public function getLiterals(): array */ public function getHash() { - $data = unpack('ihash', md5('c:'.implode(',', $this->literals), true)); + $data = unpack('ihash', (string) hash(\PHP_VERSION_ID > 80100 ? 'xxh3' : 'sha1', 'c:'.implode(',', $this->literals), true)); + if (false === $data) { + throw new \RuntimeException('Failed unpacking: '.implode(', ', $this->literals)); + } return $data['hash']; } diff --git a/app/vendor/composer/composer/src/Composer/DependencyResolver/PolicyInterface.php b/app/vendor/composer/composer/src/Composer/DependencyResolver/PolicyInterface.php index 928e7e0a9..b4511d091 100644 --- a/app/vendor/composer/composer/src/Composer/DependencyResolver/PolicyInterface.php +++ b/app/vendor/composer/composer/src/Composer/DependencyResolver/PolicyInterface.php @@ -26,8 +26,8 @@ interface PolicyInterface public function versionCompare(PackageInterface $a, PackageInterface $b, string $operator): bool; /** - * @param int[] $literals - * @return int[] + * @param non-empty-list $literals + * @return non-empty-list */ public function selectPreferredPackages(Pool $pool, array $literals, ?string $requiredPackage = null): array; } diff --git a/app/vendor/composer/composer/src/Composer/DependencyResolver/PoolBuilder.php b/app/vendor/composer/composer/src/Composer/DependencyResolver/PoolBuilder.php index 52aefa251..68689ed20 100644 --- a/app/vendor/composer/composer/src/Composer/DependencyResolver/PoolBuilder.php +++ b/app/vendor/composer/composer/src/Composer/DependencyResolver/PoolBuilder.php @@ -40,7 +40,7 @@ class PoolBuilder { /** * @var int[] - * @phpstan-var array + * @phpstan-var array, BasePackage::STABILITY_*> */ private $acceptableStabilities; /** @@ -95,7 +95,7 @@ class PoolBuilder */ private $loadedPerRepo = []; /** - * @var BasePackage[] + * @var array */ private $packages = []; /** @@ -153,7 +153,7 @@ class PoolBuilder /** * @param int[] $acceptableStabilities array of stability => BasePackage::STABILITY_* value - * @phpstan-param array $acceptableStabilities + * @phpstan-param array, BasePackage::STABILITY_*> $acceptableStabilities * @param int[] $stabilityFlags an array of package name => BasePackage::STABILITY_* value * @phpstan-param array $stabilityFlags * @param array[] $rootAliases @@ -201,10 +201,14 @@ public function buildPool(array $repositories, Request $request): Pool { $this->restrictedPackagesList = $request->getRestrictedPackages() !== null ? array_flip($request->getRestrictedPackages()) : null; - if ($request->getUpdateAllowList()) { + if (\count($request->getUpdateAllowList()) > 0) { $this->updateAllowList = $request->getUpdateAllowList(); $this->warnAboutNonMatchingUpdateAllowList($request); + if (null === $request->getLockedRepository()) { + throw new \LogicException('No lock repo present and yet a partial update was requested.'); + } + foreach ($request->getLockedRepository()->getPackages() as $lockedPackage) { if (!$this->isUpdateAllowed($lockedPackage)) { // remember which packages we skipped loading remote content for in this partial update @@ -271,39 +275,45 @@ public function buildPool(array $repositories, Request $request): Pool } } - while (!empty($this->packagesToLoad)) { + while (\count($this->packagesToLoad) > 0) { $this->loadPackagesMarkedForLoading($request, $repositories); } if (\count($this->temporaryConstraints) > 0) { foreach ($this->packages as $i => $package) { // we check all alias related packages at once, so no need to check individual aliases - if (!isset($this->temporaryConstraints[$package->getName()]) || $package instanceof AliasPackage) { + if ($package instanceof AliasPackage) { continue; } - $constraint = $this->temporaryConstraints[$package->getName()]; - $packageAndAliases = [$i => $package]; - if (isset($this->aliasMap[spl_object_hash($package)])) { - $packageAndAliases += $this->aliasMap[spl_object_hash($package)]; - } + foreach ($package->getNames() as $packageName) { + if (!isset($this->temporaryConstraints[$packageName])) { + continue; + } - $found = false; - foreach ($packageAndAliases as $packageOrAlias) { - if (CompilingMatcher::match($constraint, Constraint::OP_EQ, $packageOrAlias->getVersion())) { - $found = true; + $constraint = $this->temporaryConstraints[$packageName]; + $packageAndAliases = [$i => $package]; + if (isset($this->aliasMap[spl_object_hash($package)])) { + $packageAndAliases += $this->aliasMap[spl_object_hash($package)]; } - } - if (!$found) { - foreach ($packageAndAliases as $index => $packageOrAlias) { - unset($this->packages[$index]); + $found = false; + foreach ($packageAndAliases as $packageOrAlias) { + if (CompilingMatcher::match($constraint, Constraint::OP_EQ, $packageOrAlias->getVersion())) { + $found = true; + } + } + + if (!$found) { + foreach ($packageAndAliases as $index => $packageOrAlias) { + unset($this->packages[$index]); + } } } } } - if ($this->eventDispatcher) { + if ($this->eventDispatcher !== null) { $prePoolCreateEvent = new PrePoolCreateEvent( PluginEvents::PRE_POOL_CREATE, $repositories, @@ -413,7 +423,7 @@ private function loadPackagesMarkedForLoading(Request $request, array $repositor $this->packagesToLoad = []; foreach ($repositories as $repoIndex => $repository) { - if (empty($packageBatch)) { + if (0 === \count($packageBatch)) { break; } @@ -499,7 +509,7 @@ private function loadPackage(Request $request, array $repositories, BasePackage if ($propagateUpdate && $request->getUpdateAllowTransitiveDependencies()) { $skippedRootRequires = $this->getSkippedRootRequires($request, $require); - if ($request->getUpdateAllowTransitiveRootDependencies() || !$skippedRootRequires) { + if ($request->getUpdateAllowTransitiveRootDependencies() || 0 === \count($skippedRootRequires)) { $this->unlockPackage($request, $repositories, $require); $this->markPackageNameForLoading($request, $require, $linkConstraint); } else { @@ -528,7 +538,7 @@ private function loadPackage(Request $request, array $repositories, BasePackage if (isset($this->loadedPackages[$replace], $this->skippedLoad[$replace])) { $skippedRootRequires = $this->getSkippedRootRequires($request, $replace); - if ($request->getUpdateAllowTransitiveRootDependencies() || !$skippedRootRequires) { + if ($request->getUpdateAllowTransitiveRootDependencies() || 0 === \count($skippedRootRequires)) { $this->unlockPackage($request, $repositories, $replace); // the replaced package only needs to be loaded if something else requires it $this->markPackageNameForLoadingIfRequired($request, $replace); @@ -615,7 +625,13 @@ private function isUpdateAllowed(BasePackage $package): bool private function warnAboutNonMatchingUpdateAllowList(Request $request): void { + if (null === $request->getLockedRepository()) { + throw new \LogicException('No lock repo present and yet a partial update was requested.'); + } + foreach ($this->updateAllowList as $pattern) { + $matchedPlatformPackage = false; + $patternRegexp = BasePackage::packageNameToRegexp($pattern); // update pattern matches a locked package? => all good foreach ($request->getLockedRepository()->getPackages() as $package) { @@ -626,10 +642,16 @@ private function warnAboutNonMatchingUpdateAllowList(Request $request): void // update pattern matches a root require? => all good, probably a new package foreach ($request->getRequires() as $packageName => $constraint) { if (Preg::isMatch($patternRegexp, $packageName)) { + if (PlatformRepository::isPlatformPackage($packageName)) { + $matchedPlatformPackage = true; + continue; + } continue 2; } } - if (strpos($pattern, '*') !== false) { + if ($matchedPlatformPackage) { + $this->io->writeError('Pattern "' . $pattern . '" listed for update matches platform packages, but these cannot be updated by Composer.'); + } elseif (strpos($pattern, '*') !== false) { $this->io->writeError('Pattern "' . $pattern . '" listed for update does not match any locked packages.'); } else { $this->io->writeError('Package "' . $pattern . '" listed for update is not locked.'); diff --git a/app/vendor/composer/composer/src/Composer/DependencyResolver/PoolOptimizer.php b/app/vendor/composer/composer/src/Composer/DependencyResolver/PoolOptimizer.php index c53891fb6..3de9e037b 100644 --- a/app/vendor/composer/composer/src/Composer/DependencyResolver/PoolOptimizer.php +++ b/app/vendor/composer/composer/src/Composer/DependencyResolver/PoolOptimizer.php @@ -207,7 +207,7 @@ private function optimizeByIdenticalDependencies(Request $request, Pool $pool): $groupHashParts[] = 'require:' . (string) $requireConstraint; } - if ($package->getReplaces()) { + if (\count($package->getReplaces()) > 0) { foreach ($package->getReplaces() as $link) { if (CompilingMatcher::match($link->getConstraint(), Constraint::OP_EQ, $package->getVersion())) { // Use the same hash part as the regular require hash because that's what the replacement does @@ -224,7 +224,7 @@ private function optimizeByIdenticalDependencies(Request $request, Pool $pool): } } - if (!$groupHashParts) { + if (0 === \count($groupHashParts)) { continue; } @@ -371,7 +371,7 @@ private function keepPackage(BasePackage $package, array $identicalDefinitionsPe */ private function optimizeImpossiblePackagesAway(Request $request, Pool $pool): void { - if (count($request->getLockedPackages()) === 0) { + if (\count($request->getLockedPackages()) === 0) { return; } diff --git a/app/vendor/composer/composer/src/Composer/DependencyResolver/Problem.php b/app/vendor/composer/composer/src/Composer/DependencyResolver/Problem.php index cf2cb381e..b107dcbb9 100644 --- a/app/vendor/composer/composer/src/Composer/DependencyResolver/Problem.php +++ b/app/vendor/composer/composer/src/Composer/DependencyResolver/Problem.php @@ -25,6 +25,7 @@ use Composer\Semver\Constraint\ConstraintInterface; use Composer\Package\Version\VersionParser; use Composer\Repository\PlatformRepository; +use Composer\Semver\Constraint\MultiConstraint; /** * Represents a problem detected while solving dependencies @@ -79,7 +80,7 @@ public function getPrettyString(RepositorySet $repositorySet, Request $request, // TODO doesn't this entirely defeat the purpose of the problem sections? what's the point of sections? $reasons = array_merge(...array_reverse($this->reasons)); - if (count($reasons) === 1) { + if (\count($reasons) === 1) { reset($reasons); $rule = current($reasons); @@ -92,14 +93,67 @@ public function getPrettyString(RepositorySet $repositorySet, Request $request, $constraint = $reasonData['constraint']; $packages = $pool->whatProvides($packageName, $constraint); - if (count($packages) === 0) { + if (\count($packages) === 0) { return "\n ".implode(self::getMissingPackageReason($repositorySet, $request, $pool, $isVerbose, $packageName, $constraint)); } } + usort($reasons, function (Rule $rule1, Rule $rule2) use ($pool) { + $rule1Prio = $this->getRulePriority($rule1); + $rule2Prio = $this->getRulePriority($rule2); + if ($rule1Prio !== $rule2Prio) { + return $rule2Prio - $rule1Prio; + } + + return $this->getSortableString($pool, $rule1) <=> $this->getSortableString($pool, $rule2); + }); + return self::formatDeduplicatedRules($reasons, ' ', $repositorySet, $request, $pool, $isVerbose, $installedMap, $learnedPool); } + private function getSortableString(Pool $pool, Rule $rule): string + { + switch ($rule->getReason()) { + case Rule::RULE_ROOT_REQUIRE: + return $rule->getReasonData()['packageName']; + case Rule::RULE_FIXED: + return (string) $rule->getReasonData()['package']; + case Rule::RULE_PACKAGE_CONFLICT: + case Rule::RULE_PACKAGE_REQUIRES: + return $rule->getSourcePackage($pool) . '//' . $rule->getReasonData()->getPrettyString($rule->getSourcePackage($pool)); + case Rule::RULE_PACKAGE_SAME_NAME: + case Rule::RULE_PACKAGE_ALIAS: + case Rule::RULE_PACKAGE_INVERSE_ALIAS: + return (string) $rule->getReasonData(); + case Rule::RULE_LEARNED: + return implode('-', $rule->getLiterals()); + } + + // @phpstan-ignore deadCode.unreachable + throw new \LogicException('Unknown rule type: '.$rule->getReason()); + } + + private function getRulePriority(Rule $rule): int + { + switch ($rule->getReason()) { + case Rule::RULE_FIXED: + return 3; + case Rule::RULE_ROOT_REQUIRE: + return 2; + case Rule::RULE_PACKAGE_CONFLICT: + case Rule::RULE_PACKAGE_REQUIRES: + return 1; + case Rule::RULE_PACKAGE_SAME_NAME: + case Rule::RULE_LEARNED: + case Rule::RULE_PACKAGE_ALIAS: + case Rule::RULE_PACKAGE_INVERSE_ALIAS: + return 0; + } + + // @phpstan-ignore deadCode.unreachable + throw new \LogicException('Unknown rule type: '.$rule->getReason()); + } + /** * @param Rule[] $rules * @param array $installedMap A map of all present packages @@ -136,7 +190,7 @@ public static function formatDeduplicatedRules(array $rules, string $indent, Rep if (!$isVerbose) { $versions = self::condenseVersionList($versions, 1); } - if (count($versions) > 1) { + if (\count($versions) > 1) { // remove the s from requires/conflicts to correct grammar $message = Preg::replace('{^(%s%s (?:require|conflict))s}', '$1', $message); $result[] = sprintf($message, $package, '['.implode(', ', $versions).']'); @@ -224,16 +278,22 @@ public static function getMissingPackageReason(RepositorySet $repositorySet, Req $ext = substr($packageName, 4); $msg = "- Root composer.json requires PHP extension ".$packageName.self::constraintToText($constraint).' but '; - $version = self::getPlatformPackageVersion($pool, $packageName, phpversion($ext) ?: '0'); + $version = self::getPlatformPackageVersion($pool, $packageName, phpversion($ext) === false ? '0' : phpversion($ext)); if (null === $version) { + $providersStr = self::getProvidersList($repositorySet, $packageName, 5); + if ($providersStr !== null) { + $providersStr = "\n\n Alternatively you can require one of these packages that provide the extension (or parts of it):\n". + " Keep in mind that the suggestions are automated and may not be valid or safe to use\n$providersStr"; + } + if (extension_loaded($ext)) { return [ $msg, - 'the '.$packageName.' package is disabled by your platform config. Enable it again with "composer config platform.'.$packageName.' --unset".', + 'the '.$packageName.' package is disabled by your platform config. Enable it again with "composer config platform.'.$packageName.' --unset".' . $providersStr, ]; } - return [$msg, 'it is missing from your system. Install or enable PHP\'s '.$ext.' extension.']; + return [$msg, 'it is missing from your system. Install or enable PHP\'s '.$ext.' extension.' . $providersStr]; } return [$msg, 'it has the wrong version installed ('.$version.').']; @@ -247,7 +307,13 @@ public static function getMissingPackageReason(RepositorySet $repositorySet, Req return ["- Root composer.json requires linked library ".$packageName.self::constraintToText($constraint).' but ', $error]; } - return ["- Root composer.json requires linked library ".$packageName.self::constraintToText($constraint).' but ', 'it has the wrong version installed or is missing from your system, make sure to load the extension providing it.']; + $providersStr = self::getProvidersList($repositorySet, $packageName, 5); + if ($providersStr !== null) { + $providersStr = "\n\n Alternatively you can require one of these packages that provide the library (or parts of it):\n". + " Keep in mind that the suggestions are automated and may not be valid or safe to use\n$providersStr"; + } + + return ["- Root composer.json requires linked library ".$packageName.self::constraintToText($constraint).' but ', 'it has the wrong version installed or is missing from your system, make sure to load the extension providing it.'.$providersStr]; } } @@ -262,9 +328,21 @@ public static function getMissingPackageReason(RepositorySet $repositorySet, Req } } + if ($constraint instanceof Constraint && $constraint->getOperator() === Constraint::STR_OP_EQ && Preg::isMatch('{^dev-.*#.*}', $constraint->getPrettyString())) { + $newConstraint = Preg::replace('{ +as +([^,\s|]+)$}', '', $constraint->getPrettyString()); + $packages = $repositorySet->findPackages($packageName, new MultiConstraint([ + new Constraint(Constraint::STR_OP_EQ, $newConstraint), + new Constraint(Constraint::STR_OP_EQ, str_replace('#', '+', $newConstraint)) + ], false)); + if (\count($packages) > 0) { + return ["- Root composer.json requires $packageName".self::constraintToText($constraint) . ', ', 'found '.self::getPackageList($packages, $isVerbose, $pool, $constraint).'. The # character in branch names is replaced by a + character. Make sure to require it as "'.str_replace('#', '+', $constraint->getPrettyString()).'".']; + } + } + // first check if the actual requested package is found in normal conditions // if so it must mean it is rejected by another constraint than the one given here - if ($packages = $repositorySet->findPackages($packageName, $constraint)) { + $packages = $repositorySet->findPackages($packageName, $constraint); + if (\count($packages) > 0) { $rootReqs = $repositorySet->getRootRequires(); if (isset($rootReqs[$packageName])) { $filtered = array_filter($packages, static function ($p) use ($rootReqs, $packageName): bool { @@ -276,16 +354,18 @@ public static function getMissingPackageReason(RepositorySet $repositorySet, Req } $tempReqs = $repositorySet->getTemporaryConstraints(); - if (isset($tempReqs[$packageName])) { - $filtered = array_filter($packages, static function ($p) use ($tempReqs, $packageName): bool { - return $tempReqs[$packageName]->matches(new Constraint('==', $p->getVersion())); - }); - if (0 === count($filtered)) { - return ["- Root composer.json requires $packageName".self::constraintToText($constraint) . ', ', 'found '.self::getPackageList($packages, $isVerbose, $pool, $constraint).' but '.(self::hasMultipleNames($packages) ? 'these conflict' : 'it conflicts').' with your temporary update constraint ('.$packageName.':'.$tempReqs[$packageName]->getPrettyString().').']; + foreach (reset($packages)->getNames() as $name) { + if (isset($tempReqs[$name])) { + $filtered = array_filter($packages, static function ($p) use ($tempReqs, $name): bool { + return $tempReqs[$name]->matches(new Constraint('==', $p->getVersion())); + }); + if (0 === count($filtered)) { + return ["- Root composer.json requires $name".self::constraintToText($constraint) . ', ', 'found '.self::getPackageList($packages, $isVerbose, $pool, $constraint).' but '.(self::hasMultipleNames($packages) ? 'these conflict' : 'it conflicts').' with your temporary update constraint ('.$name.':'.$tempReqs[$name]->getPrettyString().').']; + } } } - if ($lockedPackage) { + if ($lockedPackage !== null) { $fixedConstraint = new Constraint('==', $lockedPackage->getVersion()); $filtered = array_filter($packages, static function ($p) use ($fixedConstraint): bool { return $fixedConstraint->matches(new Constraint('==', $p->getVersion())); @@ -299,7 +379,7 @@ public static function getMissingPackageReason(RepositorySet $repositorySet, Req return !$p->getRepository() instanceof LockArrayRepository; }); - if (!$nonLockedPackages) { + if (0 === \count($nonLockedPackages)) { return ["- Root composer.json requires $packageName".self::constraintToText($constraint) . ', ', 'found '.self::getPackageList($packages, $isVerbose, $pool, $constraint).' in the lock file but not in remote repositories, make sure you avoid updating this package to keep the one from the lock file.']; } @@ -307,9 +387,11 @@ public static function getMissingPackageReason(RepositorySet $repositorySet, Req } // check if the package is found when bypassing stability checks - if ($packages = $repositorySet->findPackages($packageName, $constraint, RepositorySet::ALLOW_UNACCEPTABLE_STABILITIES)) { + $packages = $repositorySet->findPackages($packageName, $constraint, RepositorySet::ALLOW_UNACCEPTABLE_STABILITIES); + if (\count($packages) > 0) { // we must first verify if a valid package would be found in a lower priority repository - if ($allReposPackages = $repositorySet->findPackages($packageName, $constraint, RepositorySet::ALLOW_SHADOWED_REPOSITORIES)) { + $allReposPackages = $repositorySet->findPackages($packageName, $constraint, RepositorySet::ALLOW_SHADOWED_REPOSITORIES); + if (\count($allReposPackages) > 0) { return self::computeCheckForLowerPrioRepo($pool, $isVerbose, $packageName, $packages, $allReposPackages, 'minimum-stability', $constraint); } @@ -317,9 +399,11 @@ public static function getMissingPackageReason(RepositorySet $repositorySet, Req } // check if the package is found when bypassing the constraint and stability checks - if ($packages = $repositorySet->findPackages($packageName, null, RepositorySet::ALLOW_UNACCEPTABLE_STABILITIES)) { + $packages = $repositorySet->findPackages($packageName, null, RepositorySet::ALLOW_UNACCEPTABLE_STABILITIES); + if (\count($packages) > 0) { // we must first verify if a valid package would be found in a lower priority repository - if ($allReposPackages = $repositorySet->findPackages($packageName, $constraint, RepositorySet::ALLOW_SHADOWED_REPOSITORIES)) { + $allReposPackages = $repositorySet->findPackages($packageName, $constraint, RepositorySet::ALLOW_SHADOWED_REPOSITORIES); + if (\count($allReposPackages) > 0) { return self::computeCheckForLowerPrioRepo($pool, $isVerbose, $packageName, $packages, $allReposPackages, 'constraint', $constraint); } @@ -349,17 +433,8 @@ public static function getMissingPackageReason(RepositorySet $repositorySet, Req return ["- Root composer.json requires $packageName, it ", 'could not be found, it looks like its name is invalid, "'.$illegalChars.'" is not allowed in package names.']; } - if ($providers = $repositorySet->getProviders($packageName)) { - $maxProviders = 20; - $providersStr = implode(array_map(static function ($p): string { - $description = $p['description'] ? ' '.substr($p['description'], 0, 100) : ''; - - return ' - '.$p['name'].$description."\n"; - }, count($providers) > $maxProviders + 1 ? array_slice($providers, 0, $maxProviders) : $providers)); - if (count($providers) > $maxProviders + 1) { - $providersStr .= ' ... and '.(count($providers) - $maxProviders).' more.'."\n"; - } - + $providersStr = self::getProvidersList($repositorySet, $packageName, 15); + if ($providersStr !== null) { return ["- Root composer.json requires $packageName".self::constraintToText($constraint).", it ", "could not be found in any version, but the following packages provide it:\n".$providersStr." Consider requiring one of these to satisfy the $packageName requirement."]; } @@ -377,12 +452,12 @@ public static function getPackageList(array $packages, bool $isVerbose, ?Pool $p foreach ($packages as $package) { $prepared[$package->getName()]['name'] = $package->getPrettyName(); $prepared[$package->getName()]['versions'][$package->getVersion()] = $package->getPrettyVersion().($package instanceof AliasPackage ? ' (alias of '.$package->getAliasOf()->getPrettyVersion().')' : ''); - if ($pool && $constraint) { + if ($pool !== null && $constraint !== null) { foreach ($pool->getRemovedVersions($package->getName(), $constraint) as $version => $prettyVersion) { $prepared[$package->getName()]['versions'][$version] = $prettyVersion; } } - if ($pool && $useRemovedVersionGroup) { + if ($pool !== null && $useRemovedVersionGroup) { foreach ($pool->getRemovedVersionsByPackage(spl_object_hash($package)) as $version => $prettyVersion) { $prepared[$package->getName()]['versions'][$version] = $prettyVersion; } @@ -418,7 +493,7 @@ private static function getPlatformPackageVersion(Pool $pool, string $packageNam { $available = $pool->whatProvides($packageName); - if (count($available)) { + if (\count($available) > 0) { $selected = null; foreach ($available as $pkg) { if ($pkg->getRepository() instanceof PlatformRepository) { @@ -443,7 +518,7 @@ private static function getPlatformPackageVersion(Pool $pool, string $packageNam $version = $selected->getPrettyVersion(); $extra = $selected->getExtra(); if ($selected instanceof CompletePackageInterface && isset($extra['config.platform']) && $extra['config.platform'] === true) { - $version .= '; ' . str_replace('Package ', '', $selected->getDescription()); + $version .= '; ' . str_replace('Package ', '', (string) $selected->getDescription()); } } else { return null; @@ -504,8 +579,8 @@ private static function hasMultipleNames(array $packages): bool } /** - * @param PackageInterface[] $higherRepoPackages - * @param PackageInterface[] $allReposPackages + * @param non-empty-array $higherRepoPackages + * @param non-empty-array $allReposPackages * @return array{0: string, 1: string} */ private static function computeCheckForLowerPrioRepo(Pool $pool, bool $isVerbose, string $packageName, array $higherRepoPackages, array $allReposPackages, string $reason, ?ConstraintInterface $constraint = null): array @@ -522,12 +597,14 @@ private static function computeCheckForLowerPrioRepo(Pool $pool, bool $isVerbose } } - if ($higherRepoPackages) { + assert(null !== $nextRepo); + + if (\count($higherRepoPackages) > 0) { $topPackage = reset($higherRepoPackages); if ($topPackage instanceof RootPackageInterface) { return [ "- Root composer.json requires $packageName".self::constraintToText($constraint).', it is ', - 'satisfiable by '.self::getPackageList($nextRepoPackages, $isVerbose, $pool, $constraint).' from '.$nextRepo->getRepoName().' but '.$topPackage->getPrettyName().' is the root package and cannot be modified. See https://getcomposer.org/dep-on-root for details and assistance.', + 'satisfiable by '.self::getPackageList($nextRepoPackages, $isVerbose, $pool, $constraint).' from '.$nextRepo->getRepoName().' but '.$topPackage->getPrettyName().' '.$topPackage->getPrettyVersion().' is the root package and cannot be modified. See https://getcomposer.org/dep-on-root for details and assistance.', ]; } } @@ -570,6 +647,25 @@ protected static function constraintToText(?ConstraintInterface $constraint = nu return ' ' . $constraint->getPrettyString() . ' (exact version match: ' . (count($versions) > 1 ? implode(', ', array_slice($versions, 0, -1)) . ' or ' . end($versions) : $versions[0]) . ')'; } - return $constraint ? ' '.$constraint->getPrettyString() : ''; + return $constraint !== null ? ' '.$constraint->getPrettyString() : ''; + } + + private static function getProvidersList(RepositorySet $repositorySet, string $packageName, int $maxProviders): ?string + { + $providers = $repositorySet->getProviders($packageName); + if (\count($providers) > 0) { + $providersStr = implode(array_map(static function ($p): string { + $description = $p['description'] !== '' && $p['description'] !== null ? ' '.substr($p['description'], 0, 100) : ''; + + return ' - '.$p['name'].$description."\n"; + }, count($providers) > $maxProviders + 1 ? array_slice($providers, 0, $maxProviders) : $providers)); + if (count($providers) > $maxProviders + 1) { + $providersStr .= ' ... and '.(count($providers) - $maxProviders).' more.'."\n"; + } + + return $providersStr; + } + + return null; } } diff --git a/app/vendor/composer/composer/src/Composer/DependencyResolver/Request.php b/app/vendor/composer/composer/src/Composer/DependencyResolver/Request.php index 300093f04..b11f4e1f2 100644 --- a/app/vendor/composer/composer/src/Composer/DependencyResolver/Request.php +++ b/app/vendor/composer/composer/src/Composer/DependencyResolver/Request.php @@ -190,7 +190,7 @@ public function getFixedOrLockedPackages(): array } /** - * @return array + * @return ($packageIds is true ? array : array) * * @TODO look into removing the packageIds option, the only place true is used * is for the installed map in the solver problems. @@ -201,7 +201,7 @@ public function getPresentMap(bool $packageIds = false): array { $presentMap = []; - if ($this->lockedRepository) { + if ($this->lockedRepository !== null) { foreach ($this->lockedRepository->getPackages() as $package) { $presentMap[$packageIds ? $package->getId() : spl_object_hash($package)] = $package; } @@ -215,7 +215,7 @@ public function getPresentMap(bool $packageIds = false): array } /** - * @return BasePackage[] + * @return array */ public function getFixedPackagesMap(): array { diff --git a/app/vendor/composer/composer/src/Composer/DependencyResolver/Rule.php b/app/vendor/composer/composer/src/Composer/DependencyResolver/Rule.php index 1b2f1aa95..8dde02b37 100644 --- a/app/vendor/composer/composer/src/Composer/DependencyResolver/Rule.php +++ b/app/vendor/composer/composer/src/Composer/DependencyResolver/Rule.php @@ -137,12 +137,12 @@ public function enable(): void public function isDisabled(): bool { - return (bool) (($this->bitfield & (255 << self::BITFIELD_DISABLED)) >> self::BITFIELD_DISABLED); + return 0 !== (($this->bitfield & (255 << self::BITFIELD_DISABLED)) >> self::BITFIELD_DISABLED); } public function isEnabled(): bool { - return !(($this->bitfield & (255 << self::BITFIELD_DISABLED)) >> self::BITFIELD_DISABLED); + return 0 === (($this->bitfield & (255 << self::BITFIELD_DISABLED)) >> self::BITFIELD_DISABLED); } abstract public function isAssertion(): bool; @@ -153,7 +153,7 @@ public function isCausedByLock(RepositorySet $repositorySet, Request $request, P if (PlatformRepository::isPlatformPackage($this->getReasonData()->getTarget())) { return false; } - if ($request->getLockedRepository()) { + if ($request->getLockedRepository() !== null) { foreach ($request->getLockedRepository()->getPackages() as $package) { if ($package->getName() === $this->getReasonData()->getTarget()) { if ($pool->isUnacceptableFixedOrLockedPackage($package)) { @@ -176,7 +176,7 @@ public function isCausedByLock(RepositorySet $repositorySet, Request $request, P if (PlatformRepository::isPlatformPackage($this->getReasonData()['packageName'])) { return false; } - if ($request->getLockedRepository()) { + if ($request->getLockedRepository() !== null) { foreach ($request->getLockedRepository()->getPackages() as $package) { if ($package->getName() === $this->getReasonData()['packageName']) { if ($pool->isUnacceptableFixedOrLockedPackage($package)) { @@ -215,7 +215,7 @@ public function getSourcePackage(Pool $pool): BasePackage return $package2; case self::RULE_PACKAGE_REQUIRES: - $sourceLiteral = array_shift($literals); + $sourceLiteral = $literals[0]; $sourcePackage = $this->deduplicateDefaultBranchAlias($pool->literalToPackage($sourceLiteral)); return $sourcePackage; @@ -240,14 +240,14 @@ public function getPrettyString(RepositorySet $repositorySet, Request $request, $constraint = $reasonData['constraint']; $packages = $pool->whatProvides($packageName, $constraint); - if (!$packages) { + if (0 === \count($packages)) { return 'No package found to satisfy root composer.json require '.$packageName.' '.$constraint->getPrettyString(); } $packagesNonAlias = array_values(array_filter($packages, static function ($p): bool { return !($p instanceof AliasPackage); })); - if (count($packagesNonAlias) === 1) { + if (\count($packagesNonAlias) === 1) { $package = $packagesNonAlias[0]; if ($request->isLockedPackage($package)) { return $package->getPrettyName().' is locked to version '.$package->getPrettyVersion()." and an update of this package was not requested."; @@ -305,6 +305,7 @@ public function getPrettyString(RepositorySet $repositorySet, Request $request, return $package2->getPrettyString().' conflicts with '.$conflictTarget.'.'; case self::RULE_PACKAGE_REQUIRES: + assert(\count($literals) > 0); $sourceLiteral = array_shift($literals); $sourcePackage = $this->deduplicateDefaultBranchAlias($pool->literalToPackage($sourceLiteral)); $reasonData = $this->getReasonData(); @@ -315,7 +316,7 @@ public function getPrettyString(RepositorySet $repositorySet, Request $request, } $text = $reasonData->getPrettyString($sourcePackage); - if ($requires) { + if (\count($requires) > 0) { $text .= ' -> satisfiable by ' . $this->formatPackagesUnique($pool, $requires, $isVerbose, $reasonData->getConstraint()) . '.'; } else { $targetName = $reasonData->getTarget(); @@ -333,19 +334,18 @@ public function getPrettyString(RepositorySet $repositorySet, Request $request, $package = $pool->literalToPackage($literal); $packageNames[$package->getName()] = true; } + unset($literal); $replacedName = $this->getReasonData(); - if (count($packageNames) > 1) { - $reason = null; - + if (\count($packageNames) > 1) { if (!isset($packageNames[$replacedName])) { - $reason = 'They '.(count($literals) === 2 ? 'both' : 'all').' replace '.$replacedName.' and thus cannot coexist.'; + $reason = 'They '.(\count($literals) === 2 ? 'both' : 'all').' replace '.$replacedName.' and thus cannot coexist.'; } else { $replacerNames = $packageNames; unset($replacerNames[$replacedName]); $replacerNames = array_keys($replacerNames); - if (count($replacerNames) === 1) { + if (\count($replacerNames) === 1) { $reason = $replacerNames[0] . ' replaces '; } else { $reason = '['.implode(', ', $replacerNames).'] replace '; @@ -363,7 +363,7 @@ public function getPrettyString(RepositorySet $repositorySet, Request $request, } } - if ($installedPackages && $removablePackages) { + if (\count($installedPackages) > 0 && \count($removablePackages) > 0) { return $this->formatPackagesUnique($pool, $removablePackages, $isVerbose, null, true).' cannot be installed as that would require removing '.$this->formatPackagesUnique($pool, $installedPackages, $isVerbose, null, true).'. '.$reason; } @@ -381,7 +381,7 @@ public function getPrettyString(RepositorySet $repositorySet, Request $request, // } $learnedString = ' (conflict analysis result)'; - if (count($literals) === 1) { + if (\count($literals) === 1) { $ruleText = $pool->literalToPrettyString($literals[0], $installedMap); } else { $groups = []; @@ -397,7 +397,7 @@ public function getPrettyString(RepositorySet $repositorySet, Request $request, } $ruleTexts = []; foreach ($groups as $group => $packages) { - $ruleTexts[] = $group . (count($packages) > 1 ? ' one of' : '').' ' . $this->formatPackagesUnique($pool, $packages, $isVerbose); + $ruleTexts[] = $group . (\count($packages) > 1 ? ' one of' : '').' ' . $this->formatPackagesUnique($pool, $packages, $isVerbose); } $ruleText = implode(' | ', $ruleTexts); @@ -439,14 +439,13 @@ public function getPrettyString(RepositorySet $repositorySet, Request $request, } /** - * @param array $packages An array containing packages or literals + * @param array $literalsOrPackages An array containing packages or literals */ - protected function formatPackagesUnique(Pool $pool, array $packages, bool $isVerbose, ?ConstraintInterface $constraint = null, bool $useRemovedVersionGroup = false): string + protected function formatPackagesUnique(Pool $pool, array $literalsOrPackages, bool $isVerbose, ?ConstraintInterface $constraint = null, bool $useRemovedVersionGroup = false): string { - foreach ($packages as $index => $package) { - if (!\is_object($package)) { - $packages[$index] = $pool->literalToPackage($package); - } + $packages = []; + foreach ($literalsOrPackages as $package) { + $packages[] = \is_object($package) ? $package : $pool->literalToPackage($package); } return Problem::getPackageList($packages, $isVerbose, $pool, $constraint, $useRemovedVersionGroup); diff --git a/app/vendor/composer/composer/src/Composer/DependencyResolver/Rule2Literals.php b/app/vendor/composer/composer/src/Composer/DependencyResolver/Rule2Literals.php index 17bfaf8ce..33d0ed0be 100644 --- a/app/vendor/composer/composer/src/Composer/DependencyResolver/Rule2Literals.php +++ b/app/vendor/composer/composer/src/Composer/DependencyResolver/Rule2Literals.php @@ -43,7 +43,7 @@ public function __construct(int $literal1, int $literal2, $reason, $reasonData) } /** - * @return list + * @return non-empty-list */ public function getLiterals(): array { diff --git a/app/vendor/composer/composer/src/Composer/DependencyResolver/RuleSet.php b/app/vendor/composer/composer/src/Composer/DependencyResolver/RuleSet.php index 4a406238a..cca9eb123 100644 --- a/app/vendor/composer/composer/src/Composer/DependencyResolver/RuleSet.php +++ b/app/vendor/composer/composer/src/Composer/DependencyResolver/RuleSet.php @@ -179,7 +179,7 @@ public function getPrettyString(?RepositorySet $repositorySet = null, ?Request $ foreach ($this->rules as $type => $rules) { $string .= str_pad(self::TYPES[$type], 8, ' ') . ": "; foreach ($rules as $rule) { - $string .= ($repositorySet && $request && $pool ? $rule->getPrettyString($repositorySet, $request, $pool, $isVerbose) : $rule)."\n"; + $string .= ($repositorySet !== null && $request !== null && $pool !== null ? $rule->getPrettyString($repositorySet, $request, $pool, $isVerbose) : $rule)."\n"; } $string .= "\n\n"; } diff --git a/app/vendor/composer/composer/src/Composer/DependencyResolver/RuleSetGenerator.php b/app/vendor/composer/composer/src/Composer/DependencyResolver/RuleSetGenerator.php index 69d119134..08c874ff7 100644 --- a/app/vendor/composer/composer/src/Composer/DependencyResolver/RuleSetGenerator.php +++ b/app/vendor/composer/composer/src/Composer/DependencyResolver/RuleSetGenerator.php @@ -56,7 +56,7 @@ public function __construct(PolicyInterface $policy, Pool $pool) * * @phpstan-param ReasonData $reasonData */ - protected function createRequireRule(BasePackage $package, array $providers, $reason, $reasonData = null): ?Rule + protected function createRequireRule(BasePackage $package, array $providers, $reason, $reasonData): ?Rule { $literals = [-$package->id]; @@ -77,7 +77,7 @@ protected function createRequireRule(BasePackage $package, array $providers, $re * The rule is (A|B|C) with A, B and C different packages. If the given * set of packages is empty an impossible rule is generated. * - * @param BasePackage[] $packages The set of packages to choose from + * @param non-empty-array $packages The set of packages to choose from * @param Rule::RULE_* $reason A RULE_* constant describing the reason for * generating this rule * @param mixed $reasonData Additional data like the root require or fix request info @@ -109,7 +109,7 @@ protected function createInstallOneOfRule(array $packages, $reason, $reasonData) * * @phpstan-param ReasonData $reasonData */ - protected function createRule2Literals(BasePackage $issuer, BasePackage $provider, $reason, $reasonData = null): ?Rule + protected function createRule2Literals(BasePackage $issuer, BasePackage $provider, $reason, $reasonData): ?Rule { // ignore self conflict if ($issuer === $provider) { @@ -120,7 +120,7 @@ protected function createRule2Literals(BasePackage $issuer, BasePackage $provide } /** - * @param BasePackage[] $packages + * @param non-empty-array $packages * @param Rule::RULE_* $reason A RULE_* constant * @param mixed $reasonData * @@ -151,7 +151,7 @@ protected function createMultiConflictRule(array $packages, $reason, $reasonData */ private function addRule($type, ?Rule $newRule = null): void { - if (!$newRule) { + if (null === $newRule) { return; } @@ -276,7 +276,7 @@ protected function addRulesForRequest(Request $request, PlatformRequirementFilte } $packages = $this->pool->whatProvides($packageName, $constraint); - if ($packages) { + if (\count($packages) > 0) { foreach ($packages as $package) { $this->addRulesForPackage($package, $platformRequirementFilter); } @@ -307,7 +307,7 @@ protected function addRulesForRootAliases(PlatformRequirementFilterInterface $pl public function getRulesFor(Request $request, ?PlatformRequirementFilterInterface $platformRequirementFilter = null): RuleSet { - $platformRequirementFilter = $platformRequirementFilter ?: PlatformRequirementFilterFactory::ignoreNothing(); + $platformRequirementFilter = $platformRequirementFilter ?? PlatformRequirementFilterFactory::ignoreNothing(); $this->addRulesForRequest($request, $platformRequirementFilter); diff --git a/app/vendor/composer/composer/src/Composer/DependencyResolver/RuleSetIterator.php b/app/vendor/composer/composer/src/Composer/DependencyResolver/RuleSetIterator.php index 2bf67f55b..3b8383d47 100644 --- a/app/vendor/composer/composer/src/Composer/DependencyResolver/RuleSetIterator.php +++ b/app/vendor/composer/composer/src/Composer/DependencyResolver/RuleSetIterator.php @@ -14,7 +14,7 @@ /** * @author Nils Adermann - * @implements \Iterator + * @implements \Iterator */ class RuleSetIterator implements \Iterator { diff --git a/app/vendor/composer/composer/src/Composer/DependencyResolver/Solver.php b/app/vendor/composer/composer/src/Composer/DependencyResolver/Solver.php index 373e8325d..b8aa847d1 100644 --- a/app/vendor/composer/composer/src/Composer/DependencyResolver/Solver.php +++ b/app/vendor/composer/composer/src/Composer/DependencyResolver/Solver.php @@ -43,7 +43,7 @@ class Solver /** @var int */ protected $propagateIndex; - /** @var mixed[] */ + /** @var array, int}> */ protected $branches = []; /** @var Problem[] */ protected $problems = []; @@ -109,7 +109,7 @@ private function makeAssertionRuleDecisions(): void $conflict = $this->decisions->decisionRule($literal); - if ($conflict && RuleSet::TYPE_PACKAGE === $conflict->getType()) { + if (RuleSet::TYPE_PACKAGE === $conflict->getType()) { $problem = new Problem(); $problem->addRule($rule); @@ -164,7 +164,7 @@ protected function checkForRootRequireProblems(Request $request, PlatformRequire $constraint = $platformRequirementFilter->filterConstraint($packageName, $constraint); } - if (!$this->pool->whatProvides($packageName, $constraint)) { + if (0 === \count($this->pool->whatProvides($packageName, $constraint))) { $problem = new Problem(); $problem->addRule(new GenericRule([], Rule::RULE_ROOT_REQUIRE, ['packageName' => $packageName, 'constraint' => $constraint])); $this->problems[] = $problem; @@ -174,7 +174,7 @@ protected function checkForRootRequireProblems(Request $request, PlatformRequire public function solve(Request $request, ?PlatformRequirementFilterInterface $platformRequirementFilter = null): LockTransaction { - $platformRequirementFilter = $platformRequirementFilter ?: PlatformRequirementFilterFactory::ignoreNothing(); + $platformRequirementFilter = $platformRequirementFilter ?? PlatformRequirementFilterFactory::ignoreNothing(); $this->setupFixedMap($request); @@ -199,7 +199,7 @@ public function solve(Request $request, ?PlatformRequirementFilterInterface $pla $this->io->writeError('', true, IOInterface::DEBUG); $this->io->writeError(sprintf('Dependency resolution completed in %.3f seconds', microtime(true) - $before), true, IOInterface::VERBOSE); - if ($this->problems) { + if (\count($this->problems) > 0) { throw new SolverProblemsException($this->problems, $this->learnedPool); } @@ -227,7 +227,7 @@ protected function propagate(int $level): ?Rule $this->propagateIndex++; - if ($conflict) { + if ($conflict !== null) { return $conflict; } } @@ -257,7 +257,7 @@ private function revert(int $level): void $this->propagateIndex = \count($this->decisions); } - while (!empty($this->branches) && $this->branches[\count($this->branches) - 1][self::BRANCH_LEVEL] >= $level) { + while (\count($this->branches) > 0 && $this->branches[\count($this->branches) - 1][self::BRANCH_LEVEL] >= $level) { array_pop($this->branches); } } @@ -274,10 +274,8 @@ private function revert(int $level): void * rule (always unit) and re-propagate. * * returns the new solver level or 0 if unsolvable - * - * @param string|int $literal */ - private function setPropagateLearn(int $level, $literal, Rule $rule): int + private function setPropagateLearn(int $level, int $literal, Rule $rule): int { $level++; @@ -291,7 +289,9 @@ private function setPropagateLearn(int $level, $literal, Rule $rule): int } if ($level === 1) { - return $this->analyzeUnsolvable($rule); + $this->analyzeUnsolvable($rule); + + return 0; } // conflict @@ -322,7 +322,7 @@ private function setPropagateLearn(int $level, $literal, Rule $rule): int } /** - * @param int[] $decisionQueue + * @param non-empty-list $decisionQueue */ private function selectAndInstall(int $level, array $decisionQueue, Rule $rule): int { @@ -332,7 +332,7 @@ private function selectAndInstall(int $level, array $decisionQueue, Rule $rule): $selectedLiteral = array_shift($literals); // if there are multiple candidates, then branch - if (\count($literals)) { + if (\count($literals) > 0) { $this->branches[] = [$literals, $level]; } @@ -349,7 +349,8 @@ protected function analyze(int $level, Rule $rule): array $num = 0; $l1num = 0; $seen = []; - $learnedLiterals = [null]; + $learnedLiteral = null; + $otherLearnedLiterals = []; $decisionId = \count($this->decisions); @@ -382,7 +383,7 @@ protected function analyze(int $level, Rule $rule): array $num++; } else { // not level1 or conflict level, add to new rule - $learnedLiterals[] = $literal; + $otherLearnedLiterals[] = $literal; if ($l > $ruleLevel) { $ruleLevel = $l; @@ -423,16 +424,14 @@ protected function analyze(int $level, Rule $rule): array if ($literal < 0) { $this->testFlagLearnedPositiveLiteral = true; } - $learnedLiterals[0] = -$literal; + $learnedLiteral = -$literal; - if (!$l1num) { + if (0 === $l1num) { break 2; } - foreach ($learnedLiterals as $i => $learnedLiteral) { - if ($i !== 0) { - unset($seen[abs($learnedLiteral)]); - } + foreach ($otherLearnedLiterals as $otherLiteral) { + unset($seen[abs($otherLiteral)]); } // only level 1 marks left $l1num++; @@ -442,24 +441,24 @@ protected function analyze(int $level, Rule $rule): array $rule = $decision[Decisions::DECISION_REASON]; if ($rule instanceof MultiConflictRule) { - // there is only ever exactly one positive decision in a multiconflict rule - foreach ($rule->getLiterals() as $literal) { - if (!isset($seen[abs($literal)]) && $this->decisions->satisfy(-$literal)) { + // there is only ever exactly one positive decision in a MultiConflictRule + foreach ($rule->getLiterals() as $ruleLiteral) { + if (!isset($seen[abs($ruleLiteral)]) && $this->decisions->satisfy(-$ruleLiteral)) { $this->learnedPool[\count($this->learnedPool) - 1][] = $rule; - $l = $this->decisions->decisionLevel($literal); + $l = $this->decisions->decisionLevel($ruleLiteral); if (1 === $l) { $l1num++; } elseif ($level === $l) { $num++; } else { // not level1 or conflict level, add to new rule - $learnedLiterals[] = $literal; + $otherLearnedLiterals[] = $ruleLiteral; if ($l > $ruleLevel) { $ruleLevel = $l; } } - $seen[abs($literal)] = true; + $seen[abs($ruleLiteral)] = true; break; } } @@ -475,15 +474,16 @@ protected function analyze(int $level, Rule $rule): array $why = \count($this->learnedPool) - 1; - if (null === $learnedLiterals[0]) { + if (null === $learnedLiteral) { throw new SolverBugException( "Did not find a learnable literal in analyzed rule $analyzedRule." ); } - $newRule = new GenericRule($learnedLiterals, Rule::RULE_LEARNED, $why); + array_unshift($otherLearnedLiterals, $learnedLiteral); + $newRule = new GenericRule($otherLearnedLiterals, Rule::RULE_LEARNED, $why); - return [$learnedLiterals[0], $ruleLevel, $newRule, $why]; + return [$learnedLiteral, $ruleLevel, $newRule, $why]; } /** @@ -516,7 +516,7 @@ private function analyzeUnsolvableRule(Problem $problem, Rule $conflictRule, arr $problem->addRule($conflictRule); } - private function analyzeUnsolvable(Rule $conflictRule): int + private function analyzeUnsolvable(Rule $conflictRule): void { $problem = new Problem(); $problem->addRule($conflictRule); @@ -539,10 +539,10 @@ private function analyzeUnsolvable(Rule $conflictRule): int } foreach ($this->decisions as $decision) { - $literal = $decision[Decisions::DECISION_LITERAL]; + $decisionLiteral = $decision[Decisions::DECISION_LITERAL]; // skip literals that are not in this rule - if (!isset($seen[abs($literal)])) { + if (!isset($seen[abs($decisionLiteral)])) { continue; } @@ -552,7 +552,6 @@ private function analyzeUnsolvable(Rule $conflictRule): int $this->analyzeUnsolvableRule($problem, $why, $ruleSeen); $literals = $why->getLiterals(); - foreach ($literals as $literal) { // skip the one true literal if ($this->decisions->satisfy($literal)) { @@ -561,8 +560,6 @@ private function analyzeUnsolvable(Rule $conflictRule): int $seen[abs($literal)] = true; } } - - return 0; } private function runSat(): void @@ -586,9 +583,7 @@ private function runSat(): void if (1 === $level) { $conflictRule = $this->propagate($level); if (null !== $conflictRule) { - if ($this->analyzeUnsolvable($conflictRule)) { - continue; - } + $this->analyzeUnsolvable($conflictRule); return; } @@ -612,7 +607,7 @@ private function runSat(): void } } - if ($noneSatisfied && \count($decisionQueue)) { + if ($noneSatisfied && \count($decisionQueue) > 0) { // if any of the options in the decision queue are fixed, only use those $prunedQueue = []; foreach ($decisionQueue as $literal) { @@ -620,12 +615,12 @@ private function runSat(): void $prunedQueue[] = $literal; } } - if (!empty($prunedQueue)) { + if (\count($prunedQueue) > 0) { $decisionQueue = $prunedQueue; } } - if ($noneSatisfied && \count($decisionQueue)) { + if ($noneSatisfied && \count($decisionQueue) > 0) { $oLevel = $level; $level = $this->selectAndInstall($level, $decisionQueue, $rule); @@ -719,7 +714,7 @@ private function runSat(): void } // minimization step - if (\count($this->branches)) { + if (\count($this->branches) > 0) { $lastLiteral = null; $lastLevel = null; $lastBranchIndex = 0; @@ -729,7 +724,7 @@ private function runSat(): void [$literals, $l] = $this->branches[$i]; foreach ($literals as $offset => $literal) { - if ($literal && $literal > 0 && $this->decisions->decisionLevel($literal) > $l + 1) { + if ($literal > 0 && $this->decisions->decisionLevel($literal) > $l + 1) { $lastLiteral = $literal; $lastBranchIndex = $i; $lastBranchOffset = $offset; @@ -738,7 +733,8 @@ private function runSat(): void } } - if ($lastLiteral) { + if ($lastLiteral !== null) { + assert($lastLevel !== null); unset($this->branches[$lastBranchIndex][self::BRANCH_LITERALS][$lastBranchOffset]); $level = $lastLevel; diff --git a/app/vendor/composer/composer/src/Composer/DependencyResolver/SolverProblemsException.php b/app/vendor/composer/composer/src/Composer/DependencyResolver/SolverProblemsException.php index 5870c0cae..bd76e4fa3 100644 --- a/app/vendor/composer/composer/src/Composer/DependencyResolver/SolverProblemsException.php +++ b/app/vendor/composer/composer/src/Composer/DependencyResolver/SolverProblemsException.php @@ -38,7 +38,7 @@ public function __construct(array $problems, array $learnedPool) $this->problems = $problems; $this->learnedPool = $learnedPool; - parent::__construct('Failed resolving dependencies with '.count($problems).' problems, call getPrettyString to get formatted details', self::ERROR_DEPENDENCY_RESOLUTION_FAILED); + parent::__construct('Failed resolving dependencies with '.\count($problems).' problems, call getPrettyString to get formatted details', self::ERROR_DEPENDENCY_RESOLUTION_FAILED); } public function getPrettyString(RepositorySet $repositorySet, Request $request, Pool $pool, bool $isVerbose, bool $isDevExtraction = false): string @@ -63,11 +63,11 @@ public function getPrettyString(RepositorySet $repositorySet, Request $request, } $hints = []; - if (!$isDevExtraction && (strpos($text, 'could not be found') || strpos($text, 'no matching package found'))) { + if (!$isDevExtraction && (str_contains($text, 'could not be found') || str_contains($text, 'no matching package found'))) { $hints[] = "Potential causes:\n - A typo in the package name\n - The package is not available in a stable-enough version according to your minimum-stability setting\n see for more details.\n - It's a private package and you forgot to add a custom repository to find it\n\nRead for further common problems."; } - if (!empty($missingExtensions)) { + if (\count($missingExtensions) > 0) { $hints[] = $this->createExtensionHint($missingExtensions); } @@ -75,17 +75,17 @@ public function getPrettyString(RepositorySet $repositorySet, Request $request, $hints[] = "Use the option --with-all-dependencies (-W) to allow upgrades, downgrades and removals for packages currently locked to specific versions."; } - if (strpos($text, 'found composer-plugin-api[2.0.0] but it does not match') && strpos($text, '- ocramius/package-versions')) { + if (str_contains($text, 'found composer-plugin-api[2.0.0] but it does not match') && str_contains($text, '- ocramius/package-versions')) { $hints[] = "ocramius/package-versions only provides support for Composer 2 in 1.8+, which requires PHP 7.4.\nIf you can not upgrade PHP you can require composer/package-versions-deprecated to resolve this with PHP 7.0+."; } if (!class_exists('PHPUnit\Framework\TestCase', false)) { - if (strpos($text, 'found composer-plugin-api[2.0.0] but it does not match')) { + if (str_contains($text, 'found composer-plugin-api[2.0.0] but it does not match')) { $hints[] = "You are using Composer 2, which some of your plugins seem to be incompatible with. Make sure you update your plugins or report a plugin-issue to ask them to support Composer 2."; } } - if ($hints) { + if (\count($hints) > 0) { $text .= "\n" . implode("\n\n", $hints); } diff --git a/app/vendor/composer/composer/src/Composer/DependencyResolver/Transaction.php b/app/vendor/composer/composer/src/Composer/DependencyResolver/Transaction.php index ef6860c11..3443dd768 100644 --- a/app/vendor/composer/composer/src/Composer/DependencyResolver/Transaction.php +++ b/app/vendor/composer/composer/src/Composer/DependencyResolver/Transaction.php @@ -123,7 +123,7 @@ protected function calculateOperations(): array $visited = []; $processed = []; - while (!empty($stack)) { + while (\count($stack) > 0) { $package = array_pop($stack); if (isset($processed[spl_object_hash($package)])) { @@ -283,17 +283,18 @@ private function movePluginsToFront(array $operations): array continue; } - $isDownloadsModifyingPlugin = $package->getType() === 'composer-plugin' && ($extra = $package->getExtra()) && isset($extra['plugin-modifies-downloads']) && $extra['plugin-modifies-downloads'] === true; + $extra = $package->getExtra(); + $isDownloadsModifyingPlugin = $package->getType() === 'composer-plugin' && isset($extra['plugin-modifies-downloads']) && $extra['plugin-modifies-downloads'] === true; // is this a downloads modifying plugin or a dependency of one? - if ($isDownloadsModifyingPlugin || count(array_intersect($package->getNames(), $dlModifyingPluginRequires))) { + if ($isDownloadsModifyingPlugin || \count(array_intersect($package->getNames(), $dlModifyingPluginRequires)) > 0) { // get the package's requires, but filter out any platform requirements $requires = array_filter(array_keys($package->getRequires()), static function ($req): bool { return !PlatformRepository::isPlatformPackage($req); }); // is this a plugin with no meaningful dependencies? - if ($isDownloadsModifyingPlugin && !count($requires)) { + if ($isDownloadsModifyingPlugin && 0 === \count($requires)) { // plugins with no dependencies go to the very front array_unshift($dlModifyingPluginsNoDeps, $op); } else { @@ -311,14 +312,14 @@ private function movePluginsToFront(array $operations): array $isPlugin = $package->getType() === 'composer-plugin' || $package->getType() === 'composer-installer'; // is this a plugin or a dependency of a plugin? - if ($isPlugin || count(array_intersect($package->getNames(), $pluginRequires))) { + if ($isPlugin || \count(array_intersect($package->getNames(), $pluginRequires)) > 0) { // get the package's requires, but filter out any platform requirements $requires = array_filter(array_keys($package->getRequires()), static function ($req): bool { return !PlatformRepository::isPlatformPackage($req); }); // is this a plugin with no meaningful dependencies? - if ($isPlugin && !count($requires)) { + if ($isPlugin && 0 === \count($requires)) { // plugins with no dependencies go to the very front array_unshift($pluginsNoDeps, $op); } else { diff --git a/app/vendor/composer/composer/src/Composer/Downloader/ArchiveDownloader.php b/app/vendor/composer/composer/src/Composer/Downloader/ArchiveDownloader.php index 6de51ee58..ff132e28b 100644 --- a/app/vendor/composer/composer/src/Composer/Downloader/ArchiveDownloader.php +++ b/app/vendor/composer/composer/src/Composer/Downloader/ArchiveDownloader.php @@ -68,7 +68,7 @@ public function install(PackageInterface $package, string $path, bool $output = } do { - $temporaryDir = $vendorDir.'/composer/'.substr(md5(uniqid('', true)), 0, 8); + $temporaryDir = $vendorDir.'/composer/'.bin2hex(random_bytes(4)); } while (is_dir($temporaryDir)); $this->addCleanupPath($package, $temporaryDir); diff --git a/app/vendor/composer/composer/src/Composer/Downloader/FileDownloader.php b/app/vendor/composer/composer/src/Composer/Downloader/FileDownloader.php index adf26785c..5f3b24279 100644 --- a/app/vendor/composer/composer/src/Composer/Downloader/FileDownloader.php +++ b/app/vendor/composer/composer/src/Composer/Downloader/FileDownloader.php @@ -126,7 +126,7 @@ public function download(PackageInterface $package, string $path, ?PackageInterf } $cacheKeyGenerator = static function (PackageInterface $package, $key): string { - $cacheKey = sha1($key); + $cacheKey = hash('sha1', $key); return $package->getName().'/'.$cacheKey.'.'.$package->getDistType(); }; @@ -350,7 +350,14 @@ public function install(PackageInterface $package, string $path, bool $output = $this->io->writeError(" - " . InstallOperation::format($package)); } - $this->filesystem->emptyDirectory($path); + $vendorDir = $this->config->get('vendor-dir'); + + // clean up the target directory, unless it contains the vendor dir, as the vendor dir contains + // the file to be installed. This is the case when installing with create-project in the current directory + // but in that case we ensure the directory is empty already in ProjectInstaller so no need to empty it here. + if (false === strpos($this->filesystem->normalizePath($vendorDir), $this->filesystem->normalizePath($path.DIRECTORY_SEPARATOR))) { + $this->filesystem->emptyDirectory($path); + } $this->filesystem->ensureDirectoryExists($path); $this->filesystem->rename($this->getFileName($package, $path), $path . '/' . $this->getDistPath($package, PATHINFO_BASENAME)); @@ -441,7 +448,7 @@ protected function getFileName(PackageInterface $package, string $path): string $extension = $package->getDistType(); } - return rtrim($this->config->get('vendor-dir') . '/composer/tmp-' . md5($package . spl_object_hash($package)) . '.' . $extension, '.'); + return rtrim($this->config->get('vendor-dir') . '/composer/tmp-' . hash('md5', $package . spl_object_hash($package)) . '.' . $extension, '.'); } /** diff --git a/app/vendor/composer/composer/src/Composer/Downloader/FossilDownloader.php b/app/vendor/composer/composer/src/Composer/Downloader/FossilDownloader.php index 6634771dc..60c6ed49d 100644 --- a/app/vendor/composer/composer/src/Composer/Downloader/FossilDownloader.php +++ b/app/vendor/composer/composer/src/Composer/Downloader/FossilDownloader.php @@ -12,10 +12,12 @@ namespace Composer\Downloader; +use Composer\Util\Platform; use React\Promise\PromiseInterface; use Composer\Package\PackageInterface; use Composer\Pcre\Preg; use Composer\Util\ProcessExecutor; +use RuntimeException; /** * @author BohwaZ @@ -38,22 +40,13 @@ protected function doInstall(PackageInterface $package, string $path, string $ur // Ensure we are allowed to use this URL by config $this->config->prohibitUrlByConfig($url, $this->io); - $url = ProcessExecutor::escape($url); - $ref = ProcessExecutor::escape($package->getSourceReference()); $repoFile = $path . '.fossil'; + $realPath = Platform::realpath($path); + $this->io->writeError("Cloning ".$package->getSourceReference()); - $command = sprintf('fossil clone -- %s %s', $url, ProcessExecutor::escape($repoFile)); - if (0 !== $this->process->execute($command, $ignoredOutput)) { - throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()); - } - $command = sprintf('fossil open --nested -- %s', ProcessExecutor::escape($repoFile)); - if (0 !== $this->process->execute($command, $ignoredOutput, realpath($path))) { - throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()); - } - $command = sprintf('fossil update -- %s', $ref); - if (0 !== $this->process->execute($command, $ignoredOutput, realpath($path))) { - throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()); - } + $this->execute(['fossil', 'clone', '--', $url, $repoFile]); + $this->execute(['fossil', 'open', '--nested', '--', $repoFile], $realPath); + $this->execute(['fossil', 'update', '--', (string) $package->getSourceReference()], $realPath); return \React\Promise\resolve(null); } @@ -66,17 +59,15 @@ protected function doUpdate(PackageInterface $initial, PackageInterface $target, // Ensure we are allowed to use this URL by config $this->config->prohibitUrlByConfig($url, $this->io); - $ref = ProcessExecutor::escape($target->getSourceReference()); $this->io->writeError(" Updating to ".$target->getSourceReference()); if (!$this->hasMetadataRepository($path)) { throw new \RuntimeException('The .fslckout file is missing from '.$path.', see https://getcomposer.org/commit-deps for more information'); } - $command = sprintf('fossil pull && fossil up %s', $ref); - if (0 !== $this->process->execute($command, $ignoredOutput, realpath($path))) { - throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()); - } + $realPath = Platform::realpath($path); + $this->execute(['fossil', 'pull'], $realPath); + $this->execute(['fossil', 'up', (string) $target->getSourceReference()], $realPath); return \React\Promise\resolve(null); } @@ -90,7 +81,7 @@ public function getLocalChanges(PackageInterface $package, string $path): ?strin return null; } - $this->process->execute('fossil changes', $output, realpath($path)); + $this->process->execute(['fossil', 'changes'], $output, Platform::realpath($path)); $output = trim($output); @@ -102,11 +93,7 @@ public function getLocalChanges(PackageInterface $package, string $path): ?strin */ protected function getCommitLogs(string $fromReference, string $toReference, string $path): string { - $command = sprintf('fossil timeline -t ci -W 0 -n 0 before %s', ProcessExecutor::escape($toReference)); - - if (0 !== $this->process->execute($command, $output, realpath($path))) { - throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()); - } + $this->execute(['fossil', 'timeline', '-t', 'ci', '-W', '0', '-n', '0', 'before', $toReference], Platform::realpath($path), $output); $log = ''; $match = '/\d\d:\d\d:\d\d\s+\[' . $toReference . '\]/'; @@ -121,6 +108,17 @@ protected function getCommitLogs(string $fromReference, string $toReference, str return $log; } + /** + * @param non-empty-list $command + * @throws \RuntimeException + */ + private function execute(array $command, ?string $cwd = null, ?string &$output = null): void + { + if (0 !== $this->process->execute($command, $output, $cwd)) { + throw new \RuntimeException('Failed to execute ' . implode(' ', $command) . "\n\n" . $this->process->getErrorOutput()); + } + } + /** * @inheritDoc */ diff --git a/app/vendor/composer/composer/src/Composer/Downloader/GitDownloader.php b/app/vendor/composer/composer/src/Composer/Downloader/GitDownloader.php index 0840219d0..e54d95473 100644 --- a/app/vendor/composer/composer/src/Composer/Downloader/GitDownloader.php +++ b/app/vendor/composer/composer/src/Composer/Downloader/GitDownloader.php @@ -67,13 +67,13 @@ protected function doDownload(PackageInterface $package, string $path, string $u GitUtil::cleanEnv(); - $cachePath = $this->config->get('cache-vcs-dir').'/'.Preg::replace('{[^a-z0-9.]}i', '-', $url).'/'; + $cachePath = $this->config->get('cache-vcs-dir').'/'.Preg::replace('{[^a-z0-9.]}i', '-', Url::sanitize($url)).'/'; $gitVersion = GitUtil::getVersion($this->process); // --dissociate option is only available since git 2.3.0-rc0 if ($gitVersion && version_compare($gitVersion, '2.3.0-rc0', '>=') && Cache::isUsable($cachePath)) { $this->io->writeError(" - Syncing " . $package->getName() . " (" . $package->getFullPrettyVersion() . ") into cache"); - $this->io->writeError(sprintf(' Cloning to cache at %s', ProcessExecutor::escape($cachePath)), true, IOInterface::DEBUG); + $this->io->writeError(sprintf(' Cloning to cache at %s', $cachePath), true, IOInterface::DEBUG); $ref = $package->getSourceReference(); if ($this->gitUtil->fetchRefOrSyncMirror($url, $cachePath, $ref, $package->getPrettyVersion()) && is_dir($cachePath)) { $this->cachedPackages[$package->getId()][$ref] = true; @@ -92,26 +92,32 @@ protected function doInstall(PackageInterface $package, string $path, string $ur { GitUtil::cleanEnv(); $path = $this->normalizePath($path); - $cachePath = $this->config->get('cache-vcs-dir').'/'.Preg::replace('{[^a-z0-9.]}i', '-', $url).'/'; + $cachePath = $this->config->get('cache-vcs-dir').'/'.Preg::replace('{[^a-z0-9.]}i', '-', Url::sanitize($url)).'/'; $ref = $package->getSourceReference(); - $flag = Platform::isWindows() ? '/D ' : ''; if (!empty($this->cachedPackages[$package->getId()][$ref])) { $msg = "Cloning ".$this->getShortHash($ref).' from cache'; - $cloneFlags = '--dissociate --reference %cachePath% '; + $cloneFlags = ['--dissociate', '--reference', $cachePath]; $transportOptions = $package->getTransportOptions(); if (isset($transportOptions['git']['single_use_clone']) && $transportOptions['git']['single_use_clone']) { - $cloneFlags = ''; + $cloneFlags = []; } - $command = - 'git clone --no-checkout %cachePath% %path% ' . $cloneFlags - . '&& cd '.$flag.'%path% ' - . '&& git remote set-url origin -- %sanitizedUrl% && git remote add composer -- %sanitizedUrl%'; + $commands = [ + array_merge(['git', 'clone', '--no-checkout', $cachePath, $path], $cloneFlags), + ['git', 'remote', 'set-url', 'origin', '--', '%sanitizedUrl%'], + ['git', 'remote', 'add', 'composer', '--', '%sanitizedUrl%'], + ]; } else { $msg = "Cloning ".$this->getShortHash($ref); - $command = 'git clone --no-checkout -- %url% %path% && cd '.$flag.'%path% && git remote add composer -- %url% && git fetch composer && git remote set-url origin -- %sanitizedUrl% && git remote set-url composer -- %sanitizedUrl%'; + $commands = [ + array_merge(['git', 'clone', '--no-checkout', '--', '%url%', $path]), + ['git', 'remote', 'add', 'composer', '--', '%url%'], + ['git', 'fetch', 'composer'], + ['git', 'remote', 'set-url', 'origin', '--', '%sanitizedUrl%'], + ['git', 'remote', 'set-url', 'composer', '--', '%sanitizedUrl%'], + ]; if (Platform::getEnv('COMPOSER_DISABLE_NETWORK')) { throw new \RuntimeException('The required git reference for '.$package->getName().' is not in cache and network is disabled, aborting'); } @@ -119,20 +125,8 @@ protected function doInstall(PackageInterface $package, string $path, string $ur $this->io->writeError($msg); - $commandCallable = static function (string $url) use ($path, $command, $cachePath): string { - return str_replace( - ['%url%', '%path%', '%cachePath%', '%sanitizedUrl%'], - [ - ProcessExecutor::escape($url), - ProcessExecutor::escape($path), - ProcessExecutor::escape($cachePath), - ProcessExecutor::escape(Preg::replace('{://([^@]+?):(.+?)@}', '://', $url)), - ], - $command - ); - }; + $this->gitUtil->runCommands($commands, $url, $path, true); - $this->gitUtil->runCommand($commandCallable, $url, $path, true); $sourceUrl = $package->getSourceUrl(); if ($url !== $sourceUrl && $sourceUrl !== null) { $this->updateOriginUrl($path, $sourceUrl); @@ -161,15 +155,15 @@ protected function doUpdate(PackageInterface $initial, PackageInterface $target, throw new \RuntimeException('The .git directory is missing from '.$path.', see https://getcomposer.org/commit-deps for more information'); } - $cachePath = $this->config->get('cache-vcs-dir').'/'.Preg::replace('{[^a-z0-9.]}i', '-', $url).'/'; + $cachePath = $this->config->get('cache-vcs-dir').'/'.Preg::replace('{[^a-z0-9.]}i', '-', Url::sanitize($url)).'/'; $ref = $target->getSourceReference(); if (!empty($this->cachedPackages[$target->getId()][$ref])) { $msg = "Checking out ".$this->getShortHash($ref).' from cache'; - $command = '(git rev-parse --quiet --verify %ref% || (git remote set-url composer -- %cachePath% && git fetch composer && git fetch --tags composer)) && git remote set-url composer -- %sanitizedUrl%'; + $remoteUrl = $cachePath; } else { $msg = "Checking out ".$this->getShortHash($ref); - $command = '(git remote set-url composer -- %url% && git rev-parse --quiet --verify %ref% || (git fetch composer && git fetch --tags composer)) && git remote set-url composer -- %sanitizedUrl%'; + $remoteUrl = '%url%'; if (Platform::getEnv('COMPOSER_DISABLE_NETWORK')) { throw new \RuntimeException('The required git reference for '.$target->getName().' is not in cache and network is disabled, aborting'); } @@ -177,20 +171,19 @@ protected function doUpdate(PackageInterface $initial, PackageInterface $target, $this->io->writeError($msg); - $commandCallable = static function ($url) use ($ref, $command, $cachePath): string { - return str_replace( - ['%url%', '%ref%', '%cachePath%', '%sanitizedUrl%'], - [ - ProcessExecutor::escape($url), - ProcessExecutor::escape($ref.'^{commit}'), - ProcessExecutor::escape($cachePath), - ProcessExecutor::escape(Preg::replace('{://([^@]+?):(.+?)@}', '://', $url)), - ], - $command - ); - }; + if (0 !== $this->process->execute(['git', 'rev-parse', '--quiet', '--verify', $ref.'^{commit}'], $output, $path)) { + $commands = [ + ['git', 'remote', 'set-url', 'composer', '--', $remoteUrl], + ['git', 'fetch', 'composer'], + ['git', 'fetch', '--tags', 'composer'], + ]; + + $this->gitUtil->runCommands($commands, $url, $path); + } + + $command = ['git', 'remote', 'set-url', 'composer', '--', '%sanitizedUrl%']; + $this->gitUtil->runCommands([$command], $url, $path); - $this->gitUtil->runCommand($commandCallable, $url, $path); if ($newRef = $this->updateToCommit($target, $path, (string) $ref, $target->getPrettyVersion())) { if ($target->getDistReference() === $target->getSourceReference()) { $target->setDistReference($newRef); @@ -200,7 +193,7 @@ protected function doUpdate(PackageInterface $initial, PackageInterface $target, $updateOriginUrl = false; if ( - 0 === $this->process->execute('git remote -v', $output, $path) + 0 === $this->process->execute(['git', 'remote', '-v'], $output, $path) && Preg::isMatch('{^origin\s+(?P\S+)}m', $output, $originMatch) && Preg::isMatch('{^composer\s+(?P\S+)}m', $output, $composerMatch) ) { @@ -225,9 +218,9 @@ public function getLocalChanges(PackageInterface $package, string $path): ?strin return null; } - $command = 'git status --porcelain --untracked-files=no'; + $command = ['git', 'status', '--porcelain', '--untracked-files=no']; if (0 !== $this->process->execute($command, $output, $path)) { - throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()); + throw new \RuntimeException('Failed to execute ' . implode(' ', $command) . "\n\n" . $this->process->getErrorOutput()); } $output = trim($output); @@ -243,9 +236,9 @@ public function getUnpushedChanges(PackageInterface $package, string $path): ?st return null; } - $command = 'git show-ref --head -d'; + $command = ['git', 'show-ref', '--head', '-d']; if (0 !== $this->process->execute($command, $output, $path)) { - throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()); + throw new \RuntimeException('Failed to execute ' . implode(' ', $command) . "\n\n" . $this->process->getErrorOutput()); } $refs = trim($output); @@ -255,7 +248,7 @@ public function getUnpushedChanges(PackageInterface $package, string $path): ?st } $headRef = $match[1]; - if (!Preg::isMatchAllStrictGroups('{^'.$headRef.' refs/heads/(.+)$}mi', $refs, $matches)) { + if (!Preg::isMatchAllStrictGroups('{^'.preg_quote($headRef).' refs/heads/(.+)$}mi', $refs, $matches)) { // not on a branch, we are either on a not-modified tag or some sort of detached head, so skip this return null; } @@ -294,9 +287,9 @@ public function getUnpushedChanges(PackageInterface $package, string $path): ?st $unpushedChanges = null; } foreach ($remoteBranches as $remoteBranch) { - $command = sprintf('git diff --name-status %s...%s --', $remoteBranch, $branch); + $command = ['git', 'diff', '--name-status', $remoteBranch.'...'.$branch, '--']; if (0 !== $this->process->execute($command, $output, $path)) { - throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()); + throw new \RuntimeException('Failed to execute ' . implode(' ', $command) . "\n\n" . $this->process->getErrorOutput()); } $output = trim($output); @@ -310,12 +303,12 @@ public function getUnpushedChanges(PackageInterface $package, string $path): ?st // first pass and we found unpushed changes, fetch from all remotes to make sure we have up to date // remotes and then try again as outdated remotes can sometimes cause false-positives if ($unpushedChanges && $i === 0) { - $this->process->execute('git fetch --all', $output, $path); + $this->process->execute(['git', 'fetch', '--all'], $output, $path); // update list of refs after fetching - $command = 'git show-ref --head -d'; + $command = ['git', 'show-ref', '--head', '-d']; if (0 !== $this->process->execute($command, $output, $path)) { - throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()); + throw new \RuntimeException('Failed to execute ' . implode(' ', $command) . "\n\n" . $this->process->getErrorOutput()); } $refs = trim($output); } @@ -425,7 +418,7 @@ protected function reapplyChanges(string $path): void if (!empty($this->hasStashedChanges[$path])) { unset($this->hasStashedChanges[$path]); $this->io->writeError(' Re-applying stashed changes'); - if (0 !== $this->process->execute('git stash pop', $output, $path)) { + if (0 !== $this->process->execute(['git', 'stash', 'pop'], $output, $path)) { throw new \RuntimeException("Failed to apply stashed changes:\n\n".$this->process->getErrorOutput()); } } @@ -441,18 +434,29 @@ protected function reapplyChanges(string $path): void */ protected function updateToCommit(PackageInterface $package, string $path, string $reference, string $prettyVersion): ?string { - $force = !empty($this->hasDiscardedChanges[$path]) || !empty($this->hasStashedChanges[$path]) ? '-f ' : ''; + $force = !empty($this->hasDiscardedChanges[$path]) || !empty($this->hasStashedChanges[$path]) ? ['-f'] : []; // This uses the "--" sequence to separate branch from file parameters. // // Otherwise git tries the branch name as well as file name. // If the non-existent branch is actually the name of a file, the file // is checked out. - $template = 'git checkout '.$force.'%s -- && git reset --hard %1$s --'; + $branch = Preg::replace('{(?:^dev-|(?:\.x)?-dev$)}i', '', $prettyVersion); + /** + * @var \Closure(non-empty-list): bool $execute + * @phpstan-ignore varTag.nativeType + */ + $execute = function (array $command) use (&$output, $path) { + /** @var non-empty-list $command */ + $output = ''; + + return 0 === $this->process->execute($command, $output, $path); + }; + $branches = null; - if (0 === $this->process->execute('git branch -r', $output, $path)) { + if ($execute(['git', 'branch', '-r'])) { $branches = $output; } @@ -462,8 +466,10 @@ protected function updateToCommit(PackageInterface $package, string $path, strin && null !== $branches && Preg::isMatch('{^\s+composer/'.preg_quote($reference).'$}m', $branches) ) { - $command = sprintf('git checkout '.$force.'-B %s %s -- && git reset --hard %2$s --', ProcessExecutor::escape($branch), ProcessExecutor::escape('composer/'.$reference)); - if (0 === $this->process->execute($command, $output, $path)) { + $command1 = array_merge(['git', 'checkout'], $force, ['-B', $branch, 'composer/'.$reference, '--']); + $command2 = ['git', 'reset', '--hard', 'composer/'.$reference, '--']; + + if ($execute($command1) && $execute($command2)) { return null; } } @@ -475,17 +481,18 @@ protected function updateToCommit(PackageInterface $package, string $path, strin $branch = 'v' . $branch; } - $command = sprintf('git checkout %s --', ProcessExecutor::escape($branch)); - $fallbackCommand = sprintf('git checkout '.$force.'-B %s %s --', ProcessExecutor::escape($branch), ProcessExecutor::escape('composer/'.$branch)); - $resetCommand = sprintf('git reset --hard %s --', ProcessExecutor::escape($reference)); + $command = ['git', 'checkout', $branch, '--']; + $fallbackCommand = array_merge(['git', 'checkout'], $force, ['-B', $branch, 'composer/'.$branch, '--']); + $resetCommand = ['git', 'reset', '--hard', $reference, '--']; - if (0 === $this->process->execute("($command || $fallbackCommand) && $resetCommand", $output, $path)) { + if (($execute($command) || $execute($fallbackCommand)) && $execute($resetCommand)) { return null; } } - $command = sprintf($template, ProcessExecutor::escape($gitRef)); - if (0 === $this->process->execute($command, $output, $path)) { + $command1 = array_merge(['git', 'checkout'], $force, [$gitRef, '--']); + $command2 = ['git', 'reset', '--hard', $gitRef, '--']; + if ($execute($command1) && $execute($command2)) { return null; } @@ -497,12 +504,14 @@ protected function updateToCommit(PackageInterface $package, string $path, strin $exceptionExtra = "\nIt looks like the commit hash is not available in the repository, maybe ".($package->isDev() ? 'the commit was removed from the branch' : 'the tag was recreated').'? Run "composer update '.$package->getPrettyName().'" to resolve this.'; } + $command = implode(' ', $command1). ' && '.implode(' ', $command2); + throw new \RuntimeException(Url::sanitize('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput() . $exceptionExtra)); } protected function updateOriginUrl(string $path, string $url): void { - $this->process->execute(sprintf('git remote set-url origin -- %s', ProcessExecutor::escape($url)), $output, $path); + $this->process->execute(['git', 'remote', 'set-url', 'origin', '--', $url], $output, $path); $this->setPushUrl($path, $url); } @@ -515,7 +524,7 @@ protected function setPushUrl(string $path, string $url): void if (!in_array('ssh', $protocols, true)) { $pushUrl = 'https://' . $match[1] . '/'.$match[2].'/'.$match[3].'.git'; } - $cmd = sprintf('git remote set-url --push origin -- %s', ProcessExecutor::escape($pushUrl)); + $cmd = ['git', 'remote', 'set-url', '--push', 'origin', '--', $pushUrl]; $this->process->execute($cmd, $ignoredOutput, $path); } } @@ -526,10 +535,10 @@ protected function setPushUrl(string $path, string $url): void protected function getCommitLogs(string $fromReference, string $toReference, string $path): string { $path = $this->normalizePath($path); - $command = sprintf('git log %s..%s --pretty=format:"%%h - %%an: %%s"'.GitUtil::getNoShowSignatureFlag($this->process), ProcessExecutor::escape($fromReference), ProcessExecutor::escape($toReference)); + $command = array_merge(['git', 'log', $fromReference.'..'.$toReference, '--pretty=format:%h - %an: %s'], GitUtil::getNoShowSignatureFlags($this->process)); if (0 !== $this->process->execute($command, $output, $path)) { - throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()); + throw new \RuntimeException('Failed to execute ' . implode(' ', $command) . "\n\n" . $this->process->getErrorOutput()); } return $output; @@ -542,7 +551,10 @@ protected function getCommitLogs(string $fromReference, string $toReference, str protected function discardChanges(string $path): PromiseInterface { $path = $this->normalizePath($path); - if (0 !== $this->process->execute('git clean -df && git reset --hard', $output, $path)) { + if (0 !== $this->process->execute(['git', 'clean', '-df'], $output, $path)) { + throw new \RuntimeException("Could not reset changes\n\n:".$output); + } + if (0 !== $this->process->execute(['git', 'reset', '--hard'], $output, $path)) { throw new \RuntimeException("Could not reset changes\n\n:".$output); } @@ -558,7 +570,7 @@ protected function discardChanges(string $path): PromiseInterface protected function stashChanges(string $path): PromiseInterface { $path = $this->normalizePath($path); - if (0 !== $this->process->execute('git stash --include-untracked', $output, $path)) { + if (0 !== $this->process->execute(['git', 'stash', '--include-untracked'], $output, $path)) { throw new \RuntimeException("Could not stash changes\n\n:".$output); } @@ -573,7 +585,7 @@ protected function stashChanges(string $path): PromiseInterface protected function viewDiff(string $path): void { $path = $this->normalizePath($path); - if (0 !== $this->process->execute('git diff HEAD', $output, $path)) { + if (0 !== $this->process->execute(['git', 'diff', 'HEAD'], $output, $path)) { throw new \RuntimeException("Could not view diff\n\n:".$output); } diff --git a/app/vendor/composer/composer/src/Composer/Downloader/GzipDownloader.php b/app/vendor/composer/composer/src/Composer/Downloader/GzipDownloader.php index 9037f5226..010219822 100644 --- a/app/vendor/composer/composer/src/Composer/Downloader/GzipDownloader.php +++ b/app/vendor/composer/composer/src/Composer/Downloader/GzipDownloader.php @@ -31,7 +31,7 @@ protected function extract(PackageInterface $package, string $file, string $path // Try to use gunzip on *nix if (!Platform::isWindows()) { - $command = 'gzip -cd -- ' . ProcessExecutor::escape($file) . ' > ' . ProcessExecutor::escape($targetFilepath); + $command = ['sh', '-c', 'gzip -cd -- "$0" > "$1"', $file, $targetFilepath]; if (0 === $this->process->execute($command, $ignoredOutput)) { return \React\Promise\resolve(null); @@ -44,7 +44,7 @@ protected function extract(PackageInterface $package, string $file, string $path return \React\Promise\resolve(null); } - $processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput(); + $processError = 'Failed to execute ' . implode(' ', $command) . "\n\n" . $this->process->getErrorOutput(); throw new \RuntimeException($processError); } diff --git a/app/vendor/composer/composer/src/Composer/Downloader/HgDownloader.php b/app/vendor/composer/composer/src/Composer/Downloader/HgDownloader.php index b0cc9cd7d..4709ae35e 100644 --- a/app/vendor/composer/composer/src/Composer/Downloader/HgDownloader.php +++ b/app/vendor/composer/composer/src/Composer/Downloader/HgDownloader.php @@ -41,16 +41,15 @@ protected function doInstall(PackageInterface $package, string $path, string $ur { $hgUtils = new HgUtils($this->io, $this->config, $this->process); - $cloneCommand = static function (string $url) use ($path): string { - return sprintf('hg clone -- %s %s', ProcessExecutor::escape($url), ProcessExecutor::escape($path)); + $cloneCommand = static function (string $url) use ($path): array { + return ['hg', 'clone', '--', $url, $path]; }; $hgUtils->runCommand($cloneCommand, $url, $path); - $ref = ProcessExecutor::escape($package->getSourceReference()); - $command = sprintf('hg up -- %s', $ref); + $command = ['hg', 'up', '--', (string) $package->getSourceReference()]; if (0 !== $this->process->execute($command, $ignoredOutput, realpath($path))) { - throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()); + throw new \RuntimeException('Failed to execute ' . implode(' ', $command) . "\n\n" . $this->process->getErrorOutput()); } return \React\Promise\resolve(null); @@ -70,10 +69,14 @@ protected function doUpdate(PackageInterface $initial, PackageInterface $target, throw new \RuntimeException('The .hg directory is missing from '.$path.', see https://getcomposer.org/commit-deps for more information'); } - $command = static function ($url) use ($ref): string { - return sprintf('hg pull -- %s && hg up -- %s', ProcessExecutor::escape($url), ProcessExecutor::escape($ref)); + $command = static function ($url): array { + return ['hg', 'pull', '--', $url]; }; + $hgUtils->runCommand($command, $url, $path); + $command = static function () use ($ref): array { + return ['hg', 'up', '--', $ref]; + }; $hgUtils->runCommand($command, $url, $path); return \React\Promise\resolve(null); @@ -88,7 +91,7 @@ public function getLocalChanges(PackageInterface $package, string $path): ?strin return null; } - $this->process->execute('hg st', $output, realpath($path)); + $this->process->execute(['hg', 'st'], $output, realpath($path)); $output = trim($output); @@ -100,10 +103,10 @@ public function getLocalChanges(PackageInterface $package, string $path): ?strin */ protected function getCommitLogs(string $fromReference, string $toReference, string $path): string { - $command = sprintf('hg log -r %s:%s --style compact', ProcessExecutor::escape($fromReference), ProcessExecutor::escape($toReference)); + $command = ['hg', 'log', '-r', $fromReference.':'.$toReference, '--style', 'compact']; if (0 !== $this->process->execute($command, $output, realpath($path))) { - throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()); + throw new \RuntimeException('Failed to execute ' . implode(' ', $command) . "\n\n" . $this->process->getErrorOutput()); } return $output; diff --git a/app/vendor/composer/composer/src/Composer/Downloader/PathDownloader.php b/app/vendor/composer/composer/src/Composer/Downloader/PathDownloader.php index 791521bd6..f71ea2568 100644 --- a/app/vendor/composer/composer/src/Composer/Downloader/PathDownloader.php +++ b/app/vendor/composer/composer/src/Composer/Downloader/PathDownloader.php @@ -43,6 +43,9 @@ public function download(PackageInterface $package, string $path, ?PackageInterf { $path = Filesystem::trimTrailingSlash($path); $url = $package->getDistUrl(); + if (null === $url) { + throw new \RuntimeException('The package '.$package->getPrettyName().' has no dist url configured, cannot download.'); + } $realUrl = realpath($url); if (false === $realUrl || !file_exists($realUrl) || !is_dir($realUrl)) { throw new \RuntimeException(sprintf( @@ -79,7 +82,13 @@ public function install(PackageInterface $package, string $path, bool $output = { $path = Filesystem::trimTrailingSlash($path); $url = $package->getDistUrl(); + if (null === $url) { + throw new \RuntimeException('The package '.$package->getPrettyName().' has no dist url configured, cannot install.'); + } $realUrl = realpath($url); + if (false === $realUrl) { + throw new \RuntimeException('Failed to realpath '.$url); + } if (realpath($path) === $realUrl) { if ($output) { @@ -111,16 +120,16 @@ public function install(PackageInterface $package, string $path, bool $output = } $this->filesystem->junction($realUrl, $path); } else { - $absolutePath = $path; - if (!$this->filesystem->isAbsolutePath($absolutePath)) { - $absolutePath = Platform::getCwd() . DIRECTORY_SEPARATOR . $path; - } - $shortestPath = $this->filesystem->findShortestPath($absolutePath, $realUrl); $path = rtrim($path, "/"); if ($output) { $this->io->writeError(sprintf('Symlinking from %s', $url), false); } - if ($transportOptions['relative']) { + if ($transportOptions['relative'] === true) { + $absolutePath = $path; + if (!$this->filesystem->isAbsolutePath($absolutePath)) { + $absolutePath = Platform::getCwd() . DIRECTORY_SEPARATOR . $path; + } + $shortestPath = $this->filesystem->findShortestPath($absolutePath, $realUrl, false, true); $symfonyFilesystem->symlink($shortestPath.'/', $path); } else { $symfonyFilesystem->symlink($realUrl.'/', $path); @@ -185,13 +194,18 @@ public function remove(PackageInterface $package, string $path, bool $output = t return \React\Promise\resolve(null); } + $url = $package->getDistUrl(); + if (null === $url) { + throw new \RuntimeException('The package '.$package->getPrettyName().' has no dist url configured, cannot remove.'); + } + // ensure that the source path (dist url) is not the same as the install path, which // can happen when using custom installers, see https://github.com/composer/composer/pull/9116 // not using realpath here as we do not want to resolve the symlink to the original dist url // it points to $fs = new Filesystem; $absPath = $fs->isAbsolutePath($path) ? $path : Platform::getCwd() . '/' . $path; - $absDistUrl = $fs->isAbsolutePath($package->getDistUrl()) ? $package->getDistUrl() : Platform::getCwd() . '/' . $package->getDistUrl(); + $absDistUrl = $fs->isAbsolutePath($url) ? $url : Platform::getCwd() . '/' . $url; if ($fs->normalizePath($absPath) === $fs->normalizePath($absDistUrl)) { if ($output) { $this->io->writeError(" - " . UninstallOperation::format($package).", source is still present in $path"); @@ -210,11 +224,12 @@ public function getVcsReference(PackageInterface $package, string $path): ?strin { $path = Filesystem::trimTrailingSlash($path); $parser = new VersionParser; - $guesser = new VersionGuesser($this->config, $this->process, $parser); + $guesser = new VersionGuesser($this->config, $this->process, $parser, $this->io); $dumper = new ArrayDumper; $packageConfig = $dumper->dump($package); - if ($packageVersion = $guesser->guessVersion($packageConfig, $path)) { + $packageVersion = $guesser->guessVersion($packageConfig, $path); + if ($packageVersion !== null) { return $packageVersion['commit']; } @@ -226,7 +241,14 @@ public function getVcsReference(PackageInterface $package, string $path): ?strin */ protected function getInstallOperationAppendix(PackageInterface $package, string $path): string { - $realUrl = realpath($package->getDistUrl()); + $url = $package->getDistUrl(); + if (null === $url) { + throw new \RuntimeException('The package '.$package->getPrettyName().' has no dist url configured, cannot install.'); + } + $realUrl = realpath($url); + if (false === $realUrl) { + throw new \RuntimeException('Failed to realpath '.$url); + } if (realpath($path) === $realUrl) { return ': Source already present'; @@ -257,7 +279,7 @@ private function computeAllowedStrategies(array $transportOptions): array $allowedStrategies = [self::STRATEGY_SYMLINK, self::STRATEGY_MIRROR]; $mirrorPathRepos = Platform::getEnv('COMPOSER_MIRROR_PATH_REPOS'); - if ($mirrorPathRepos) { + if ((bool) $mirrorPathRepos) { $currentStrategy = self::STRATEGY_MIRROR; } diff --git a/app/vendor/composer/composer/src/Composer/Downloader/RarDownloader.php b/app/vendor/composer/composer/src/Composer/Downloader/RarDownloader.php index a4142c655..04e16eaff 100644 --- a/app/vendor/composer/composer/src/Composer/Downloader/RarDownloader.php +++ b/app/vendor/composer/composer/src/Composer/Downloader/RarDownloader.php @@ -34,13 +34,13 @@ protected function extract(PackageInterface $package, string $file, string $path // Try to use unrar on *nix if (!Platform::isWindows()) { - $command = 'unrar x -- ' . ProcessExecutor::escape($file) . ' ' . ProcessExecutor::escape($path) . ' >/dev/null && chmod -R u+w ' . ProcessExecutor::escape($path); + $command = ['sh', '-c', 'unrar x -- "$0" "$1" >/dev/null && chmod -R u+w "$1"', $file, $path]; if (0 === $this->process->execute($command, $ignoredOutput)) { return \React\Promise\resolve(null); } - $processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput(); + $processError = 'Failed to execute ' . implode(' ', $command) . "\n\n" . $this->process->getErrorOutput(); } if (!class_exists('RarArchive')) { diff --git a/app/vendor/composer/composer/src/Composer/Downloader/SvnDownloader.php b/app/vendor/composer/composer/src/Composer/Downloader/SvnDownloader.php index be180d63d..ca88ea839 100644 --- a/app/vendor/composer/composer/src/Composer/Downloader/SvnDownloader.php +++ b/app/vendor/composer/composer/src/Composer/Downloader/SvnDownloader.php @@ -59,7 +59,7 @@ protected function doInstall(PackageInterface $package, string $path, string $ur } $this->io->writeError(" Checking out ".$package->getSourceReference()); - $this->execute($package, $url, "svn co", sprintf("%s/%s", $url, $ref), null, $path); + $this->execute($package, $url, ['svn', 'co'], sprintf("%s/%s", $url, $ref), null, $path); return \React\Promise\resolve(null); } @@ -77,13 +77,13 @@ protected function doUpdate(PackageInterface $initial, PackageInterface $target, } $util = new SvnUtil($url, $this->io, $this->config, $this->process); - $flags = ""; + $flags = []; if (version_compare($util->binaryVersion(), '1.7.0', '>=')) { - $flags .= ' --ignore-ancestry'; + $flags[] = '--ignore-ancestry'; } $this->io->writeError(" Checking out " . $ref); - $this->execute($target, $url, "svn switch" . $flags, sprintf("%s/%s", $url, $ref), $path); + $this->execute($target, $url, array_merge(['svn', 'switch'], $flags), sprintf("%s/%s", $url, $ref), $path); return \React\Promise\resolve(null); } @@ -97,7 +97,7 @@ public function getLocalChanges(PackageInterface $package, string $path): ?strin return null; } - $this->process->execute('svn status --ignore-externals', $output, $path); + $this->process->execute(['svn', 'status', '--ignore-externals'], $output, $path); return Preg::isMatch('{^ *[^X ] +}m', $output) ? $output : null; } @@ -107,13 +107,13 @@ public function getLocalChanges(PackageInterface $package, string $path): ?strin * if necessary. * * @param string $baseUrl Base URL of the repository - * @param string $command SVN command to run + * @param non-empty-list $command SVN command to run * @param string $url SVN url * @param string $cwd Working directory * @param string $path Target for a checkout * @throws \RuntimeException */ - protected function execute(PackageInterface $package, string $baseUrl, string $command, string $url, ?string $cwd = null, ?string $path = null): string + protected function execute(PackageInterface $package, string $baseUrl, array $command, string $url, ?string $cwd = null, ?string $path = null): string { $util = new SvnUtil($baseUrl, $this->io, $this->config, $this->process); $util->setCacheCredentials($this->cacheCredentials); @@ -194,10 +194,10 @@ protected function getCommitLogs(string $fromReference, string $toReference, str { if (Preg::isMatch('{@(\d+)$}', $fromReference) && Preg::isMatch('{@(\d+)$}', $toReference)) { // retrieve the svn base url from the checkout folder - $command = sprintf('svn info --non-interactive --xml -- %s', ProcessExecutor::escape($path)); + $command = ['svn', 'info', '--non-interactive', '--xml', '--', $path]; if (0 !== $this->process->execute($command, $output, $path)) { throw new \RuntimeException( - 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput() + 'Failed to execute ' . implode(' ', $command) . "\n\n" . $this->process->getErrorOutput() ); } @@ -214,7 +214,7 @@ protected function getCommitLogs(string $fromReference, string $toReference, str $fromRevision = Preg::replace('{.*@(\d+)$}', '$1', $fromReference); $toRevision = Preg::replace('{.*@(\d+)$}', '$1', $toReference); - $command = sprintf('svn log -r%s:%s --incremental', ProcessExecutor::escape($fromRevision), ProcessExecutor::escape($toRevision)); + $command = ['svn', 'log', '-r', $fromRevision.':'.$toRevision, '--incremental']; $util = new SvnUtil($baseUrl, $this->io, $this->config, $this->process); $util->setCacheCredentials($this->cacheCredentials); @@ -222,7 +222,7 @@ protected function getCommitLogs(string $fromReference, string $toReference, str return $util->executeLocal($command, $path, null, $this->io->isVerbose()); } catch (\RuntimeException $e) { throw new \RuntimeException( - 'Failed to execute ' . $command . "\n\n".$e->getMessage() + 'Failed to execute ' . implode(' ', $command) . "\n\n".$e->getMessage() ); } } @@ -235,7 +235,7 @@ protected function getCommitLogs(string $fromReference, string $toReference, str */ protected function discardChanges(string $path): PromiseInterface { - if (0 !== $this->process->execute('svn revert -R .', $output, $path)) { + if (0 !== $this->process->execute(['svn', 'revert', '-R', '.'], $output, $path)) { throw new \RuntimeException("Could not reset changes\n\n:".$this->process->getErrorOutput()); } diff --git a/app/vendor/composer/composer/src/Composer/Downloader/TransportException.php b/app/vendor/composer/composer/src/Composer/Downloader/TransportException.php index 5ab5ca6f3..a30842e1e 100644 --- a/app/vendor/composer/composer/src/Composer/Downloader/TransportException.php +++ b/app/vendor/composer/composer/src/Composer/Downloader/TransportException.php @@ -26,7 +26,7 @@ class TransportException extends \RuntimeException /** @var array */ protected $responseInfo = []; - public function __construct(string $message = "", int $code = 400, \Throwable $previous = null) + public function __construct(string $message = "", int $code = 400, ?\Throwable $previous = null) { parent::__construct($message, $code, $previous); } diff --git a/app/vendor/composer/composer/src/Composer/Downloader/VcsDownloader.php b/app/vendor/composer/composer/src/Composer/Downloader/VcsDownloader.php index a1c5979d5..626bcb5c5 100644 --- a/app/vendor/composer/composer/src/Composer/Downloader/VcsDownloader.php +++ b/app/vendor/composer/composer/src/Composer/Downloader/VcsDownloader.php @@ -241,7 +241,7 @@ public function remove(PackageInterface $package, string $path): PromiseInterfac public function getVcsReference(PackageInterface $package, string $path): ?string { $parser = new VersionParser; - $guesser = new VersionGuesser($this->config, $this->process, $parser); + $guesser = new VersionGuesser($this->config, $this->process, $parser, $this->io); $dumper = new ArrayDumper; $packageConfig = $dumper->dump($package); diff --git a/app/vendor/composer/composer/src/Composer/Downloader/XzDownloader.php b/app/vendor/composer/composer/src/Composer/Downloader/XzDownloader.php index 8c44cd199..286d32cff 100644 --- a/app/vendor/composer/composer/src/Composer/Downloader/XzDownloader.php +++ b/app/vendor/composer/composer/src/Composer/Downloader/XzDownloader.php @@ -26,13 +26,13 @@ class XzDownloader extends ArchiveDownloader { protected function extract(PackageInterface $package, string $file, string $path): PromiseInterface { - $command = 'tar -xJf ' . ProcessExecutor::escape($file) . ' -C ' . ProcessExecutor::escape($path); + $command = ['tar', '-xJf', $file, '-C', $path]; if (0 === $this->process->execute($command, $ignoredOutput)) { return \React\Promise\resolve(null); } - $processError = 'Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput(); + $processError = 'Failed to execute ' . implode(' ', $command) . "\n\n" . $this->process->getErrorOutput(); throw new \RuntimeException($processError); } diff --git a/app/vendor/composer/composer/src/Composer/Downloader/ZipDownloader.php b/app/vendor/composer/composer/src/Composer/Downloader/ZipDownloader.php index 9d0f35353..5c86579f8 100644 --- a/app/vendor/composer/composer/src/Composer/Downloader/ZipDownloader.php +++ b/app/vendor/composer/composer/src/Composer/Downloader/ZipDownloader.php @@ -27,7 +27,7 @@ */ class ZipDownloader extends ArchiveDownloader { - /** @var array */ + /** @var array> */ private static $unzipCommands; /** @var bool */ private static $hasZipArchive; @@ -35,7 +35,7 @@ class ZipDownloader extends ArchiveDownloader private static $isWindows; /** @var ZipArchive|null */ - private $zipArchiveObject; // @phpstan-ignore-line helper property that is set via reflection for testing purposes + private $zipArchiveObject; // @phpstan-ignore property.onlyRead (helper property that is set via reflection for testing purposes) /** * @inheritDoc @@ -46,16 +46,16 @@ public function download(PackageInterface $package, string $path, ?PackageInterf self::$unzipCommands = []; $finder = new ExecutableFinder; if (Platform::isWindows() && ($cmd = $finder->find('7z', null, ['C:\Program Files\7-Zip']))) { - self::$unzipCommands[] = ['7z', ProcessExecutor::escape($cmd).' x -bb0 -y %s -o%s']; + self::$unzipCommands[] = ['7z', $cmd, 'x', '-bb0', '-y', '%file%', '-o%path%']; } if ($cmd = $finder->find('unzip')) { - self::$unzipCommands[] = ['unzip', ProcessExecutor::escape($cmd).' -qq %s -d %s']; + self::$unzipCommands[] = ['unzip', $cmd, '-qq', '%file%', '-d', '%path%']; } if (!Platform::isWindows() && ($cmd = $finder->find('7z'))) { // 7z linux/macOS support is only used if unzip is not present - self::$unzipCommands[] = ['7z', ProcessExecutor::escape($cmd).' x -bb0 -y %s -o%s']; + self::$unzipCommands[] = ['7z', $cmd, 'x', '-bb0', '-y', '%file%', '-o%path%']; } if (!Platform::isWindows() && ($cmd = $finder->find('7zz'))) { // 7zz linux/macOS support is only used if unzip is not present - self::$unzipCommands[] = ['7zz', ProcessExecutor::escape($cmd).' x -bb0 -y %s -o%s']; + self::$unzipCommands[] = ['7zz', $cmd, 'x', '-bb0', '-y', '%file%', '-o%path%']; } } @@ -114,24 +114,28 @@ private function extractWithSystemUnzip(PackageInterface $package, string $file, // Force Exception throwing if the other alternative extraction method is not available $isLastChance = !self::$hasZipArchive; - if (!self::$unzipCommands) { + if (0 === \count(self::$unzipCommands)) { // This was call as the favorite extract way, but is not available // We switch to the alternative return $this->extractWithZipArchive($package, $file, $path); } $commandSpec = reset(self::$unzipCommands); - $command = sprintf($commandSpec[1], ProcessExecutor::escape($file), ProcessExecutor::escape($path)); - // normalize separators to backslashes to avoid problems with 7-zip on windows - // see https://github.com/composer/composer/issues/10058 - if (Platform::isWindows()) { - $command = sprintf($commandSpec[1], ProcessExecutor::escape(strtr($file, '/', '\\')), ProcessExecutor::escape(strtr($path, '/', '\\'))); - } - $executable = $commandSpec[0]; + $command = array_slice($commandSpec, 1); + $map = [ + // normalize separators to backslashes to avoid problems with 7-zip on windows + // see https://github.com/composer/composer/issues/10058 + '%file%' => strtr($file, '/', DIRECTORY_SEPARATOR), + '%path%' => strtr($path, '/', DIRECTORY_SEPARATOR), + ]; + $command = array_map(static function ($value) use ($map) { + return strtr($value, $map); + }, $command); + if (!$warned7ZipLinux && !Platform::isWindows() && in_array($executable, ['7z', '7zz'], true)) { $warned7ZipLinux = true; - if (0 === $this->process->execute($executable, $output)) { + if (0 === $this->process->execute([$commandSpec[1]], $output)) { if (Preg::isMatchStrictGroups('{^\s*7-Zip(?: \[64\])? ([0-9.]+)}', $output, $match) && version_compare($match[1], '21.01', '<')) { $this->io->writeError(' Unzipping using '.$executable.' '.$match[1].' may result in incorrect file permissions. Install '.$executable.' 21.01+ or unzip to ensure you get correct permissions.'); } @@ -144,6 +148,10 @@ private function extractWithSystemUnzip(PackageInterface $package, string $file, throw $processError; } + if (str_contains($processError->getMessage(), 'zip bomb')) { + throw $processError; + } + if (!is_file($file)) { $io->writeError(' '.$processError->getMessage().''); $io->writeError(' This most likely is due to a custom installer plugin not handling the returned Promise from the downloader'); @@ -182,7 +190,7 @@ private function extractWithSystemUnzip(PackageInterface $package, string $file, $output = $process->getErrorOutput(); $output = str_replace(', '.$file.'.zip or '.$file.'.ZIP', '', $output); - return $tryFallback(new \RuntimeException('Failed to extract '.$package->getName().': ('.$process->getExitCode().') '.$command."\n\n".$output)); + return $tryFallback(new \RuntimeException('Failed to extract '.$package->getName().': ('.$process->getExitCode().') '.implode(' ', $command)."\n\n".$output)); } }); } catch (\Throwable $e) { @@ -208,7 +216,32 @@ private function extractWithZipArchive(PackageInterface $package, string $file, } else { $retval = $zipArchive->open($file); } + if (true === $retval) { + $totalSize = 0; + $archiveSize = filesize($file); + $totalFiles = $zipArchive->count(); + if ($totalFiles > 0) { + $inspectAll = false; + $filesToInspect = min($totalFiles, 5); + for ($i = 0; $i < $filesToInspect; $i++) { + $stat = $zipArchive->statIndex($inspectAll ? $i : random_int(0, $totalFiles - 1)); + if ($stat === false) { + continue; + } + $totalSize += $stat['size']; + if (!$inspectAll && $stat['size'] > $stat['comp_size'] * 200) { + $totalSize = 0; + $inspectAll = true; + $i = -1; + $filesToInspect = $totalFiles; + } + } + if ($archiveSize !== false && $totalSize > $archiveSize * 100 && $totalSize > 50*1024*1024) { + throw new \RuntimeException('Invalid zip file for "'.$package->getName().'" with compression ratio >99% (possible zip bomb)'); + } + } + $extractResult = $zipArchive->extractTo($path); if (true === $extractResult) { @@ -217,12 +250,12 @@ private function extractWithZipArchive(PackageInterface $package, string $file, return \React\Promise\resolve(null); } - $processError = new \RuntimeException(rtrim("There was an error extracting the ZIP file, it is either corrupted or using an invalid format.\n")); + $processError = new \RuntimeException(rtrim("There was an error extracting the ZIP file for \"{$package->getName()}\", it is either corrupted or using an invalid format.\n")); } else { $processError = new \UnexpectedValueException(rtrim($this->getErrorMessage($retval, $file)."\n"), $retval); } } catch (\ErrorException $e) { - $processError = new \RuntimeException('The archive may contain identical file names with different capitalization (which fails on case insensitive filesystems): '.$e->getMessage(), 0, $e); + $processError = new \RuntimeException('The archive for "'.$package->getName().'" may contain identical file names with different capitalization (which fails on case insensitive filesystems): '.$e->getMessage(), 0, $e); } catch (\Throwable $e) { $processError = $e; } diff --git a/app/vendor/composer/composer/src/Composer/EventDispatcher/EventDispatcher.php b/app/vendor/composer/composer/src/Composer/EventDispatcher/EventDispatcher.php index cab856252..6f34a6f64 100644 --- a/app/vendor/composer/composer/src/Composer/EventDispatcher/EventDispatcher.php +++ b/app/vendor/composer/composer/src/Composer/EventDispatcher/EventDispatcher.php @@ -67,6 +67,8 @@ class EventDispatcher protected $runScripts = true; /** @var list */ private $eventStack; + /** @var list */ + private $skipScripts; /** * Constructor. @@ -81,6 +83,12 @@ public function __construct(PartialComposer $composer, IOInterface $io, ?Process $this->io = $io; $this->process = $process ?? new ProcessExecutor($io); $this->eventStack = []; + $this->skipScripts = array_values(array_filter( + array_map('trim', explode(',', (string) Platform::getEnv('COMPOSER_SKIP_SCRIPTS'))), + function ($val) { + return $val !== ''; + } + )); } /** @@ -90,7 +98,7 @@ public function __construct(PartialComposer $composer, IOInterface $io, ?Process */ public function setRunScripts(bool $runScripts = true): self { - $this->runScripts = (bool) $runScripts; + $this->runScripts = $runScripts; return $this; } @@ -202,7 +210,12 @@ protected function doDispatch(Event $event) $return = 0; $this->ensureBinDirIsInPath(); - $formattedEventNameWithArgs = $event->getName() . ($event->getArguments() !== [] ? ' (' . implode(', ', $event->getArguments()) . ')' : ''); + $additionalArgs = $event->getArguments(); + if (is_string($callable) && str_contains($callable, '@no_additional_args')) { + $callable = Preg::replace('{ ?@no_additional_args}', '', $callable); + $additionalArgs = []; + } + $formattedEventNameWithArgs = $event->getName() . ($additionalArgs !== [] ? ' (' . implode(', ', $additionalArgs) . ')' : ''); if (!is_string($callable)) { if (!is_callable($callable)) { $className = is_object($callable[0]) ? get_class($callable[0]) : $callable[0]; @@ -220,7 +233,12 @@ protected function doDispatch(Event $event) $scriptName = $script[0]; unset($script[0]); - $args = array_merge($script, $event->getArguments()); + $index = array_search('@additional_args', $script, true); + if ($index !== false) { + $args = array_splice($script, $index, 0, $additionalArgs); + } else { + $args = array_merge($script, $additionalArgs); + } $flags = $event->getFlags(); if (isset($flags['script-alias-input'])) { $argsString = implode(' ', array_map(static function ($arg) { return ProcessExecutor::escape($arg); }, $script)); @@ -291,15 +309,20 @@ protected function doDispatch(Event $event) } $app->setAutoExit(false); $cmd = new $className($event->getName()); - $app->add($cmd); + if (method_exists($app, 'addCommand')) { + $app->addCommand($cmd); + } else { + // Compatibility layer for symfony/console <7.4 + $app->add($cmd); + } $app->setDefaultCommand((string) $cmd->getName(), true); try { - $args = implode(' ', array_map(static function ($arg) { return ProcessExecutor::escape($arg); }, $event->getArguments())); + $args = implode(' ', array_map(static function ($arg) { return ProcessExecutor::escape($arg); }, $additionalArgs)); // reusing the output from $this->io is mostly needed for tests, but generally speaking // it does not hurt to keep the same stream as the current Application if ($this->io instanceof ConsoleIO) { $reflProp = new \ReflectionProperty($this->io, 'output'); - if (PHP_VERSION_ID < 80100) { + if (\PHP_VERSION_ID < 80100) { $reflProp->setAccessible(true); } $output = $reflProp->getValue($this->io); @@ -313,24 +336,32 @@ protected function doDispatch(Event $event) throw $e; } } else { - $args = implode(' ', array_map(['Composer\Util\ProcessExecutor', 'escape'], $event->getArguments())); + $args = implode(' ', array_map(['Composer\Util\ProcessExecutor', 'escape'], $additionalArgs)); // @putenv does not receive arguments if (strpos($callable, '@putenv ') === 0) { $exec = $callable; } else { - $exec = $callable . ($args === '' ? '' : ' '.$args); + if (str_contains($callable, '@additional_args')) { + $exec = str_replace('@additional_args', $args, $callable); + } else { + $exec = $callable . ($args === '' ? '' : ' '.$args); + } } if ($this->io->isVerbose()) { $this->io->writeError(sprintf('> %s: %s', $event->getName(), $exec)); - } elseif ($event->getName() !== '__exec_command') { + } elseif ( // do not output the command being run when using `composer exec` as it is fairly obvious the user is running it + $event->getName() !== '__exec_command' + // do not output the command being run when using `composer ` as it is also fairly obvious the user is running it + && ($event->getFlags()['script-alias-input'] ?? null) === null + ) { $this->io->writeError(sprintf('> %s', $exec)); } $possibleLocalBinaries = $this->composer->getPackage()->getBinaries(); - if ($possibleLocalBinaries) { + if (count($possibleLocalBinaries) > 0) { foreach ($possibleLocalBinaries as $localExec) { if (Preg::isMatch('{\b'.preg_quote($callable).'$}', $localExec)) { $caller = BinaryInstaller::determineBinaryCaller($localExec); @@ -354,7 +385,7 @@ protected function doDispatch(Event $event) $pathAndArgs = substr($exec, 5); if (Platform::isWindows()) { $pathAndArgs = Preg::replaceCallback('{^\S+}', static function ($path) { - return str_replace('/', '\\', (string) $path[0]); + return str_replace('/', '\\', $path[0]); }, $pathAndArgs); } // match somename (not in quote, and not a qualified path) and if it is not a valid path from CWD then try to find it @@ -384,8 +415,6 @@ protected function doDispatch(Event $event) if (Platform::isWindows()) { $exec = Preg::replaceCallback('{^\S+}', static function ($path) { - assert(is_string($path[0])); - return str_replace('/', '\\', $path[0]); }, $exec); } @@ -455,7 +484,7 @@ protected function getPhpExecCommand(): string throw new \RuntimeException('Failed to locate PHP binary to execute '.$phpPath); } $phpArgs = $finder->findArguments(); - $phpArgs = $phpArgs ? ' ' . implode(' ', $phpArgs) : ''; + $phpArgs = \count($phpArgs) > 0 ? ' ' . implode(' ', $phpArgs) : ''; $allowUrlFOpenFlag = ' -d allow_url_fopen=' . ProcessExecutor::escape(ini_get('allow_url_fopen')); $disableFunctionsFlag = ' -d disable_functions=' . ProcessExecutor::escape(ini_get('disable_functions')); $memoryLimitFlag = ' -d memory_limit=' . ProcessExecutor::escape(ini_get('memory_limit')); @@ -572,6 +601,12 @@ protected function getScriptListeners(Event $event): array return []; } + if (in_array($event->getName(), $this->skipScripts, true)) { + $this->io->writeError('Skipped script listeners for '.$event->getName().' because of COMPOSER_SKIP_SCRIPTS', true, IOInterface::VERBOSE); + + return []; + } + assert($this->composer instanceof Composer, new \LogicException('This should only be reached with a fully loaded Composer')); if ($this->loader) { diff --git a/app/vendor/composer/composer/src/Composer/Factory.php b/app/vendor/composer/composer/src/Composer/Factory.php index 0d455b7e3..539989904 100644 --- a/app/vendor/composer/composer/src/Composer/Factory.php +++ b/app/vendor/composer/composer/src/Composer/Factory.php @@ -216,29 +216,26 @@ public static function createConfig(?IOInterface $io = null, ?string $cwd = null } $config->setAuthConfigSource(new JsonConfigSource($file, true)); - // load COMPOSER_AUTH environment variable if set - if ($composerAuthEnv = Platform::getEnv('COMPOSER_AUTH')) { - $authData = json_decode($composerAuthEnv); - if (null === $authData) { - throw new \UnexpectedValueException('COMPOSER_AUTH environment variable is malformed, should be a valid JSON object'); - } else { - if ($io instanceof IOInterface) { - $io->writeError('Loading auth config from COMPOSER_AUTH', true, IOInterface::DEBUG); - } - self::validateJsonSchema($io, $authData, JsonFile::AUTH_SCHEMA, 'COMPOSER_AUTH'); - $authData = json_decode($composerAuthEnv, true); - if (null !== $authData) { - $config->merge(['config' => $authData], 'COMPOSER_AUTH'); - } - } - } + self::loadComposerAuthEnv($config, $io); return $config; } public static function getComposerFile(): string { - return trim((string) Platform::getEnv('COMPOSER')) ?: './composer.json'; + $env = Platform::getEnv('COMPOSER'); + if (is_string($env)) { + $env = trim($env); + if ('' !== $env) { + if (is_dir($env)) { + throw new \RuntimeException('The COMPOSER environment variable is set to '.$env.' which is a directory, this variable should point to a composer.json or be left unset.'); + } + + return $env; + } + } + + return './composer.json'; } public static function getLockFile(string $composerFile): string @@ -327,7 +324,9 @@ public function createComposer(IOInterface $io, $localConfig = null, $disablePlu // Load config and override with local config/auth config $config = static::createConfig($io, $cwd); + $isGlobal = $localConfigSource !== Config::SOURCE_UNKNOWN && realpath($config->get('home')) === realpath(dirname($localConfigSource)); $config->merge($localConfig, $localConfigSource); + if (isset($composerFile)) { $io->writeError('Loading config file ' . $composerFile .' ('.realpath($composerFile).')', true, IOInterface::DEBUG); $config->setConfigSource(new JsonConfigSource(new JsonFile(realpath($composerFile), null, $io))); @@ -341,11 +340,17 @@ public function createComposer(IOInterface $io, $localConfig = null, $disablePlu } } + // make sure we load the auth env again over the local auth.json + composer.json config + self::loadComposerAuthEnv($config, $io); + $vendorDir = $config->get('vendor-dir'); // initialize composer $composer = $fullLoad ? new Composer() : new PartialComposer(); $composer->setConfig($config); + if ($isGlobal) { + $composer->setGlobal(); + } if ($fullLoad) { // load auth configs into the IO instance @@ -384,7 +389,7 @@ public function createComposer(IOInterface $io, $localConfig = null, $disablePlu // load package $parser = new VersionParser; - $guesser = new VersionGuesser($config, $process, $parser); + $guesser = new VersionGuesser($config, $process, $parser, $io); $loader = $this->loadRootPackage($rm, $config, $parser, $guesser, $io); $package = $loader->load($localConfig, 'Composer\Package\RootPackage', $cwd); $composer->setPackage($package); @@ -429,14 +434,14 @@ public function createComposer(IOInterface $io, $localConfig = null, $disablePlu if ($composer instanceof Composer) { $globalComposer = null; - if (realpath($config->get('home')) !== $cwd) { + if (!$composer->isGlobal()) { $globalComposer = $this->createGlobalComposer($io, $config, $disablePlugins, $disableScripts); } $pm = $this->createPluginManager($io, $composer, $globalComposer, $disablePlugins); $composer->setPluginManager($pm); - if (realpath($config->get('home')) === $cwd) { + if ($composer->isGlobal()) { $pm->setRunningInGlobalDir(true); } @@ -678,6 +683,28 @@ public static function createHttpDownloader(IOInterface $io, Config $config, arr return $httpDownloader; } + private static function loadComposerAuthEnv(Config $config, ?IOInterface $io): void + { + $composerAuthEnv = Platform::getEnv('COMPOSER_AUTH'); + if (false === $composerAuthEnv || '' === $composerAuthEnv) { + return; + } + + $authData = json_decode($composerAuthEnv); + if (null === $authData) { + throw new \UnexpectedValueException('COMPOSER_AUTH environment variable is malformed, should be a valid JSON object'); + } + + if ($io instanceof IOInterface) { + $io->writeError('Loading auth config from COMPOSER_AUTH', true, IOInterface::DEBUG); + } + self::validateJsonSchema($io, $authData, JsonFile::AUTH_SCHEMA, 'COMPOSER_AUTH'); + $authData = json_decode($composerAuthEnv, true); + if (null !== $authData) { + $config->merge(['config' => $authData], 'COMPOSER_AUTH'); + } + } + private static function useXdg(): bool { foreach (array_keys($_SERVER) as $key) { diff --git a/app/vendor/composer/composer/src/Composer/IO/BaseIO.php b/app/vendor/composer/composer/src/Composer/IO/BaseIO.php index c4d40ba01..55ac16604 100644 --- a/app/vendor/composer/composer/src/Composer/IO/BaseIO.php +++ b/app/vendor/composer/composer/src/Composer/IO/BaseIO.php @@ -176,46 +176,74 @@ public function loadConfiguration(Config $config) ProcessExecutor::setTimeout($config->get('process-timeout')); } + /** + * @param string|\Stringable $message + */ public function emergency($message, array $context = []): void { $this->log(LogLevel::EMERGENCY, $message, $context); } + /** + * @param string|\Stringable $message + */ public function alert($message, array $context = []): void { $this->log(LogLevel::ALERT, $message, $context); } + /** + * @param string|\Stringable $message + */ public function critical($message, array $context = []): void { $this->log(LogLevel::CRITICAL, $message, $context); } + /** + * @param string|\Stringable $message + */ public function error($message, array $context = []): void { $this->log(LogLevel::ERROR, $message, $context); } + /** + * @param string|\Stringable $message + */ public function warning($message, array $context = []): void { $this->log(LogLevel::WARNING, $message, $context); } + /** + * @param string|\Stringable $message + */ public function notice($message, array $context = []): void { $this->log(LogLevel::NOTICE, $message, $context); } + /** + * @param string|\Stringable $message + */ public function info($message, array $context = []): void { $this->log(LogLevel::INFO, $message, $context); } + /** + * @param string|\Stringable $message + */ public function debug($message, array $context = []): void { $this->log(LogLevel::DEBUG, $message, $context); } + /** + * @param mixed|LogLevel::* $level + * @param string|\Stringable $message + */ public function log($level, $message, array $context = []): void { $message = (string) $message; diff --git a/app/vendor/composer/composer/src/Composer/IO/BufferIO.php b/app/vendor/composer/composer/src/Composer/IO/BufferIO.php index 0404287a0..6cf962b84 100644 --- a/app/vendor/composer/composer/src/Composer/IO/BufferIO.php +++ b/app/vendor/composer/composer/src/Composer/IO/BufferIO.php @@ -14,6 +14,8 @@ use Composer\Pcre\Preg; use Symfony\Component\Console\Helper\QuestionHelper; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\StreamOutput; use Symfony\Component\Console\Formatter\OutputFormatterInterface; use Symfony\Component\Console\Input\StreamableInputInterface; @@ -25,17 +27,16 @@ */ class BufferIO extends ConsoleIO { - /** @var StringInput */ - protected $input; - /** @var StreamOutput */ - protected $output; - public function __construct(string $input = '', int $verbosity = StreamOutput::VERBOSITY_NORMAL, ?OutputFormatterInterface $formatter = null) { $input = new StringInput($input); $input->setInteractive(false); - $output = new StreamOutput(fopen('php://memory', 'rw'), $verbosity, $formatter ? $formatter->isDecorated() : false, $formatter); + $stream = fopen('php://memory', 'rw'); + if ($stream === false) { + throw new \RuntimeException('Unable to open memory output stream'); + } + $output = new StreamOutput($stream, $verbosity, $formatter !== null ? $formatter->isDecorated() : false, $formatter); parent::__construct($input, $output, new HelperSet([ new QuestionHelper(), @@ -47,13 +48,12 @@ public function __construct(string $input = '', int $verbosity = StreamOutput::V */ public function getOutput(): string { + assert($this->output instanceof StreamOutput); fseek($this->output->getStream(), 0); - $output = stream_get_contents($this->output->getStream()); + $output = (string) stream_get_contents($this->output->getStream()); $output = Preg::replaceCallback("{(?<=^|\n|\x08)(.+?)(\x08+)}", static function ($matches): string { - assert(is_string($matches[1])); - assert(is_string($matches[2])); $pre = strip_tags($matches[1]); if (strlen($pre) === strlen($matches[2])) { @@ -85,11 +85,14 @@ public function setUserInputs(array $inputs): void /** * @param string[] $inputs * - * @return false|resource stream + * @return resource stream */ private function createStream(array $inputs) { $stream = fopen('php://memory', 'r+'); + if ($stream === false) { + throw new \RuntimeException('Unable to open memory output stream'); + } foreach ($inputs as $input) { fwrite($stream, $input.PHP_EOL); diff --git a/app/vendor/composer/composer/src/Composer/InstalledVersions.php b/app/vendor/composer/composer/src/Composer/InstalledVersions.php index 51e734a77..2052022fd 100644 --- a/app/vendor/composer/composer/src/Composer/InstalledVersions.php +++ b/app/vendor/composer/composer/src/Composer/InstalledVersions.php @@ -26,12 +26,23 @@ */ class InstalledVersions { + /** + * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to + * @internal + */ + private static $selfDir = null; + /** * @var mixed[]|null * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null */ private static $installed; + /** + * @var bool + */ + private static $installedIsLocalDir; + /** * @var bool|null */ @@ -309,6 +320,24 @@ public static function reload($data) { self::$installed = $data; self::$installedByVendor = array(); + + // when using reload, we disable the duplicate protection to ensure that self::$installed data is + // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not, + // so we have to assume it does not, and that may result in duplicate data being returned when listing + // all installed packages for example + self::$installedIsLocalDir = false; + } + + /** + * @return string + */ + private static function getSelfDir() + { + if (self::$selfDir === null) { + self::$selfDir = strtr(__DIR__, '\\', '/'); + } + + return self::$selfDir; } /** @@ -322,19 +351,27 @@ private static function getInstalled() } $installed = array(); + $copiedLocalDir = false; if (self::$canGetVendors) { + $selfDir = self::getSelfDir(); foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + $vendorDir = strtr($vendorDir, '\\', '/'); if (isset(self::$installedByVendor[$vendorDir])) { $installed[] = self::$installedByVendor[$vendorDir]; } elseif (is_file($vendorDir.'/composer/installed.php')) { /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ $required = require $vendorDir.'/composer/installed.php'; - $installed[] = self::$installedByVendor[$vendorDir] = $required; - if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { - self::$installed = $installed[count($installed) - 1]; + self::$installedByVendor[$vendorDir] = $required; + $installed[] = $required; + if (self::$installed === null && $vendorDir.'/composer' === $selfDir) { + self::$installed = $required; + self::$installedIsLocalDir = true; } } + if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) { + $copiedLocalDir = true; + } } } @@ -350,7 +387,7 @@ private static function getInstalled() } } - if (self::$installed !== array()) { + if (self::$installed !== array() && !$copiedLocalDir) { $installed[] = self::$installed; } diff --git a/app/vendor/composer/composer/src/Composer/Installer.php b/app/vendor/composer/composer/src/Composer/Installer.php index 5f07b0e17..2502a7d02 100644 --- a/app/vendor/composer/composer/src/Composer/Installer.php +++ b/app/vendor/composer/composer/src/Composer/Installer.php @@ -538,10 +538,7 @@ protected function doUpdate(InstalledRepositoryInterface $localRepo, bool $doIns return $exitCode; } - // exists as of composer/semver 3.3.0 - if (method_exists('Composer\Semver\CompilingMatcher', 'clear')) { // @phpstan-ignore-line - \Composer\Semver\CompilingMatcher::clear(); - } + \Composer\Semver\CompilingMatcher::clear(); // write lock $platformReqs = $this->extractPlatformRequirements($this->package->getRequires()); @@ -745,16 +742,31 @@ protected function doInstall(InstalledRepositoryInterface $localRepo, bool $alre if ($missingRequirementInfo !== []) { $this->io->writeError($missingRequirementInfo); - return self::ERROR_LOCK_FILE_INVALID; + if (!$this->config->get('allow-missing-requirements')) { + return self::ERROR_LOCK_FILE_INVALID; + } } foreach ($lockedRepository->getPackages() as $package) { $request->fixLockedPackage($package); } + $rootRequires = $this->package->getRequires(); + if ($this->devMode) { + $rootRequires = array_merge($rootRequires, $this->package->getDevRequires()); + } + foreach ($rootRequires as $link) { + if (PlatformRepository::isPlatformPackage($link->getTarget())) { + $request->requireName($link->getTarget(), $link->getConstraint()); + } + } + foreach ($this->locker->getPlatformRequirements($this->devMode) as $link) { - $request->requireName($link->getTarget(), $link->getConstraint()); + if (!isset($rootRequires[$link->getTarget()])) { + $request->requireName($link->getTarget(), $link->getConstraint()); + } } + unset($rootRequires, $link); $pool = $repositorySet->createPool($request, $this->io, $this->eventDispatcher, null, $this->ignoredTypes, $this->allowedTypes); @@ -900,7 +912,7 @@ private function createRepositorySet(bool $forUpdate, PlatformRepository $platfo $this->fixedRootPackage->setRequires([]); $this->fixedRootPackage->setDevRequires([]); - $stabilityFlags[$this->package->getName()] = BasePackage::$stabilities[VersionParser::parseStability($this->package->getVersion())]; + $stabilityFlags[$this->package->getName()] = BasePackage::STABILITIES[VersionParser::parseStability($this->package->getVersion())]; $repositorySet = new RepositorySet($minimumStability, $stabilityFlags, $rootAliases, $this->package->getReferences(), $rootRequires, $this->temporaryConstraints); $repositorySet->addRepository(new RootPackageRepository($this->fixedRootPackage)); @@ -1163,7 +1175,7 @@ public function setTemporaryConstraints(array $constraints): self */ public function setDryRun(bool $dryRun = true): self { - $this->dryRun = (bool) $dryRun; + $this->dryRun = $dryRun; return $this; } @@ -1195,7 +1207,7 @@ public function setDownloadOnly(bool $downloadOnly = true): self */ public function setPreferSource(bool $preferSource = true): self { - $this->preferSource = (bool) $preferSource; + $this->preferSource = $preferSource; return $this; } @@ -1207,7 +1219,7 @@ public function setPreferSource(bool $preferSource = true): self */ public function setPreferDist(bool $preferDist = true): self { - $this->preferDist = (bool) $preferDist; + $this->preferDist = $preferDist; return $this; } @@ -1219,7 +1231,7 @@ public function setPreferDist(bool $preferDist = true): self */ public function setOptimizeAutoloader(bool $optimizeAutoloader): self { - $this->optimizeAutoloader = (bool) $optimizeAutoloader; + $this->optimizeAutoloader = $optimizeAutoloader; if (!$this->optimizeAutoloader) { // Force classMapAuthoritative off when not optimizing the // autoloader @@ -1237,7 +1249,7 @@ public function setOptimizeAutoloader(bool $optimizeAutoloader): self */ public function setClassMapAuthoritative(bool $classMapAuthoritative): self { - $this->classMapAuthoritative = (bool) $classMapAuthoritative; + $this->classMapAuthoritative = $classMapAuthoritative; if ($this->classMapAuthoritative) { // Force optimizeAutoloader when classmap is authoritative $this->setOptimizeAutoloader(true); @@ -1266,7 +1278,7 @@ public function setApcuAutoloader(bool $apcuAutoloader, ?string $apcuAutoloaderP */ public function setUpdate(bool $update): self { - $this->update = (bool) $update; + $this->update = $update; return $this; } @@ -1278,7 +1290,7 @@ public function setUpdate(bool $update): self */ public function setInstall(bool $install): self { - $this->install = (bool) $install; + $this->install = $install; return $this; } @@ -1290,7 +1302,7 @@ public function setInstall(bool $install): self */ public function setDevMode(bool $devMode = true): self { - $this->devMode = (bool) $devMode; + $this->devMode = $devMode; return $this; } @@ -1304,7 +1316,7 @@ public function setDevMode(bool $devMode = true): self */ public function setDumpAutoloader(bool $dumpAutoloader = true): self { - $this->dumpAutoloader = (bool) $dumpAutoloader; + $this->dumpAutoloader = $dumpAutoloader; return $this; } @@ -1319,7 +1331,7 @@ public function setDumpAutoloader(bool $dumpAutoloader = true): self */ public function setRunScripts(bool $runScripts = true): self { - $this->runScripts = (bool) $runScripts; + $this->runScripts = $runScripts; return $this; } @@ -1343,7 +1355,7 @@ public function setConfig(Config $config): self */ public function setVerbose(bool $verbose = true): self { - $this->verbose = (bool) $verbose; + $this->verbose = $verbose; return $this; } diff --git a/app/vendor/composer/composer/src/Composer/Installer/BinaryInstaller.php b/app/vendor/composer/composer/src/Composer/Installer/BinaryInstaller.php index 9e3123ff8..921132552 100644 --- a/app/vendor/composer/composer/src/Composer/Installer/BinaryInstaller.php +++ b/app/vendor/composer/composer/src/Composer/Installer/BinaryInstaller.php @@ -213,7 +213,7 @@ protected function generateUnixyProxyCode(string $bin, string $link): string $binDir = ProcessExecutor::escape(dirname($binPath)); $binFile = basename($binPath); - $binContents = file_get_contents($bin); + $binContents = (string) file_get_contents($bin, false, null, 0, 500); // For php files, we generate a PHP proxy instead of a shell one, // which allows calling the proxy with a custom php process if (Preg::isMatch('{^(#!.*\r?\n)?[\r\n\t ]*<\?php}', $binContents, $match)) { @@ -224,7 +224,7 @@ protected function generateUnixyProxyCode(string $bin, string $link): string $globalsCode = '$GLOBALS[\'_composer_bin_dir\'] = __DIR__;'."\n"; $phpunitHack1 = $phpunitHack2 = ''; // Don't expose autoload path when vendor dir was not set in custom installers - if ($this->vendorDir) { + if ($this->vendorDir !== null) { // ensure comparisons work accurately if the CWD is a symlink, as $link is realpath'd already $vendorDirReal = realpath($this->vendorDir); if ($vendorDirReal === false) { @@ -242,7 +242,7 @@ protected function generateUnixyProxyCode(string $bin, string $link): string $data = str_replace(\'__DIR__\', var_export(dirname($this->realpath), true), $data); $data = str_replace(\'__FILE__\', var_export($this->realpath, true), $data);'; } - if (trim((string) $match[0]) !== ' */ + /** @var list */ private $installers = []; /** @var array */ private $cache = []; @@ -180,7 +180,7 @@ public function ensureBinariesPresence(PackageInterface $package): void */ public function execute(InstalledRepositoryInterface $repo, array $operations, bool $devMode = true, bool $runScripts = true, bool $downloadOnly = false): void { - /** @var array> */ + /** @var array> $cleanupPromises */ $cleanupPromises = []; $signalHandler = SignalHandler::create([SignalHandler::SIGINT, SignalHandler::SIGTERM, SignalHandler::SIGHUP], function (string $signal, SignalHandler $handler) use (&$cleanupPromises) { @@ -197,25 +197,28 @@ public function execute(InstalledRepositoryInterface $repo, array $operations, b foreach ($operations as $index => $operation) { if ($operation instanceof UpdateOperation || $operation instanceof InstallOperation) { $package = $operation instanceof UpdateOperation ? $operation->getTargetPackage() : $operation->getPackage(); - if ($package->getType() === 'composer-plugin' && ($extra = $package->getExtra()) && isset($extra['plugin-modifies-downloads']) && $extra['plugin-modifies-downloads'] === true) { - if ($batch) { - $batches[] = $batch; + if ($package->getType() === 'composer-plugin') { + $extra = $package->getExtra(); + if (isset($extra['plugin-modifies-downloads']) && $extra['plugin-modifies-downloads'] === true) { + if (count($batch) > 0) { + $batches[] = $batch; + } + $batches[] = [$index => $operation]; + $batch = []; + + continue; } - $batches[] = [$index => $operation]; - $batch = []; - - continue; } } $batch[$index] = $operation; } - if ($batch) { + if (count($batch) > 0) { $batches[] = $batch; } - foreach ($batches as $batch) { - $this->downloadAndExecuteBatch($repo, $batch, $cleanupPromises, $devMode, $runScripts, $downloadOnly, $operations); + foreach ($batches as $batchToExecute) { + $this->downloadAndExecuteBatch($repo, $batchToExecute, $cleanupPromises, $devMode, $runScripts, $downloadOnly, $operations); } } catch (\Exception $e) { $this->runCleanup($cleanupPromises); @@ -248,7 +251,7 @@ private function downloadAndExecuteBatch(InstalledRepositoryInterface $repo, arr $opType = $operation->getOperationType(); // ignoring alias ops as they don't need to execute anything at this stage - if (!in_array($opType, ['update', 'install', 'uninstall'])) { + if (!in_array($opType, ['update', 'install', 'uninstall'], true)) { continue; } @@ -266,7 +269,7 @@ private function downloadAndExecuteBatch(InstalledRepositoryInterface $repo, arr $cleanupPromises[$index] = static function () use ($opType, $installer, $package, $initialPackage): ?PromiseInterface { // avoid calling cleanup if the download was not even initialized for a package // as without installation source configured nothing will work - if (!$package->getInstallationSource()) { + if (null === $package->getInstallationSource()) { return \React\Promise\resolve(null); } @@ -282,7 +285,7 @@ private function downloadAndExecuteBatch(InstalledRepositoryInterface $repo, arr } // execute all downloads first - if (count($promises)) { + if (count($promises) > 0) { $this->waitOnPromises($promises); } @@ -299,7 +302,7 @@ private function downloadAndExecuteBatch(InstalledRepositoryInterface $repo, arr if ($operation instanceof InstallOperation || $operation instanceof UpdateOperation) { $package = $operation instanceof UpdateOperation ? $operation->getTargetPackage() : $operation->getPackage(); if ($package->getType() === 'composer-plugin' || $package->getType() === 'composer-installer') { - if ($batch) { + if (count($batch) > 0) { $batches[] = $batch; } $batches[] = [$index => $operation]; @@ -311,12 +314,12 @@ private function downloadAndExecuteBatch(InstalledRepositoryInterface $repo, arr $batch[$index] = $operation; } - if ($batch) { + if (count($batch) > 0) { $batches[] = $batch; } - foreach ($batches as $batch) { - $this->executeBatch($repo, $batch, $cleanupPromises, $devMode, $runScripts, $allOperations); + foreach ($batches as $batchToExecute) { + $this->executeBatch($repo, $batchToExecute, $cleanupPromises, $devMode, $runScripts, $allOperations); } } @@ -334,7 +337,7 @@ private function executeBatch(InstalledRepositoryInterface $repo, array $operati $opType = $operation->getOperationType(); // ignoring alias ops as they don't need to execute anything - if (!in_array($opType, ['update', 'install', 'uninstall'])) { + if (!in_array($opType, ['update', 'install', 'uninstall'], true)) { // output alias ops in debug verbosity as they have no output otherwise if ($this->io->isDebug()) { $this->io->writeError(' - ' . $operation->show(false)); @@ -360,9 +363,9 @@ private function executeBatch(InstalledRepositoryInterface $repo, array $operati 'install' => PackageEvents::PRE_PACKAGE_INSTALL, 'update' => PackageEvents::PRE_PACKAGE_UPDATE, 'uninstall' => PackageEvents::PRE_PACKAGE_UNINSTALL, - ][$opType] ?? null; + ][$opType]; - if (null !== $eventName && $runScripts && $this->eventDispatcher) { + if ($runScripts && $this->eventDispatcher !== null) { $this->eventDispatcher->dispatchPackageEvent($eventName, $devMode, $repo, $allOperations, $operation); } @@ -389,9 +392,9 @@ private function executeBatch(InstalledRepositoryInterface $repo, array $operati 'install' => PackageEvents::POST_PACKAGE_INSTALL, 'update' => PackageEvents::POST_PACKAGE_UPDATE, 'uninstall' => PackageEvents::POST_PACKAGE_UNINSTALL, - ][$opType] ?? null; + ][$opType]; - if (null !== $eventName && $runScripts && $dispatcher) { + if ($runScripts && $dispatcher !== null) { $postExecCallbacks[] = static function () use ($dispatcher, $eventName, $devMode, $repo, $allOperations, $operation): void { $dispatcher->dispatchPackageEvent($eventName, $devMode, $repo, $allOperations, $operation); }; @@ -401,7 +404,7 @@ private function executeBatch(InstalledRepositoryInterface $repo, array $operati } // execute all prepare => installs/updates/removes => cleanup steps - if (count($promises)) { + if (count($promises) > 0) { $this->waitOnPromises($promises); } @@ -421,14 +424,14 @@ private function waitOnPromises(array $promises): void if ( $this->outputProgress && $this->io instanceof ConsoleIO - && !Platform::getEnv('CI') + && !((bool) Platform::getEnv('CI')) && !$this->io->isDebug() && count($promises) > 1 ) { $progress = $this->io->getProgressBar(); } $this->loop->wait($promises, $progress); - if ($progress) { + if ($progress !== null) { $progress->clear(); // ProgressBar in non-decorated output does not output a final line-break and clear() does nothing if (!$this->io->isDecorated()) { @@ -573,7 +576,7 @@ public function notifyInstalls(IOInterface $io): void try { foreach ($this->notifiablePackages as $repoUrl => $packages) { // non-batch API, deprecated - if (strpos($repoUrl, '%package%')) { + if (str_contains($repoUrl, '%package%')) { foreach ($packages as $package) { $url = str_replace('%package%', $package->getPrettyName(), $repoUrl); @@ -635,7 +638,7 @@ public function notifyInstalls(IOInterface $io): void private function markForNotification(PackageInterface $package): void { - if ($package->getNotificationUrl()) { + if ($package->getNotificationUrl() !== null) { $this->notifiablePackages[$package->getNotificationUrl()][$package->getName()] = $package; } } @@ -663,7 +666,7 @@ private function runCleanup(array $cleanupPromises): void }); } - if (!empty($promises)) { + if (count($promises) > 0) { $this->loop->wait($promises); } } diff --git a/app/vendor/composer/composer/src/Composer/Installer/SuggestedPackagesReporter.php b/app/vendor/composer/composer/src/Composer/Installer/SuggestedPackagesReporter.php index caaf81376..f33349d8d 100644 --- a/app/vendor/composer/composer/src/Composer/Installer/SuggestedPackagesReporter.php +++ b/app/vendor/composer/composer/src/Composer/Installer/SuggestedPackagesReporter.php @@ -200,7 +200,7 @@ private function getFilteredSuggestions(?InstalledRepository $installedRepo = nu $suggestions = []; foreach ($suggestedPackages as $suggestion) { - if (in_array($suggestion['target'], $installedNames) || ($sourceFilter && !in_array($suggestion['source'], $sourceFilter))) { + if (in_array($suggestion['target'], $installedNames) || (\count($sourceFilter) > 0 && !in_array($suggestion['source'], $sourceFilter))) { continue; } diff --git a/app/vendor/composer/composer/src/Composer/Json/JsonFile.php b/app/vendor/composer/composer/src/Composer/Json/JsonFile.php index 7f9814d61..785e46bfa 100644 --- a/app/vendor/composer/composer/src/Composer/Json/JsonFile.php +++ b/app/vendor/composer/composer/src/Composer/Json/JsonFile.php @@ -32,6 +32,7 @@ class JsonFile public const LAX_SCHEMA = 1; public const STRICT_SCHEMA = 2; public const AUTH_SCHEMA = 3; + public const LOCK_SCHEMA = 4; /** @deprecated Use \JSON_UNESCAPED_SLASHES */ public const JSON_UNESCAPED_SLASHES = 64; @@ -41,6 +42,7 @@ class JsonFile public const JSON_UNESCAPED_UNICODE = 256; public const COMPOSER_SCHEMA_PATH = __DIR__ . '/../../../res/composer-schema.json'; + public const LOCK_SCHEMA_PATH = __DIR__ . '/../../../res/composer-lock-schema.json'; public const INDENT_DEFAULT = ' '; @@ -228,8 +230,12 @@ public static function validateJsonSchema(string $source, $data, int $schema, ?s { $isComposerSchemaFile = false; if (null === $schemaFile) { - $isComposerSchemaFile = true; - $schemaFile = self::COMPOSER_SCHEMA_PATH; + if ($schema === self::LOCK_SCHEMA) { + $schemaFile = self::LOCK_SCHEMA_PATH; + } else { + $isComposerSchemaFile = true; + $schemaFile = self::COMPOSER_SCHEMA_PATH; + } } // Prepend with file:// only when not using a special schema already (e.g. in the phar) @@ -237,12 +243,10 @@ public static function validateJsonSchema(string $source, $data, int $schema, ?s $schemaFile = 'file://' . $schemaFile; } - $schemaData = (object) ['$ref' => $schemaFile]; + $schemaData = (object) ['$ref' => $schemaFile, '$schema' => "https://json-schema.org/draft-04/schema#"]; - if ($schema === self::LAX_SCHEMA) { - $schemaData->additionalProperties = true; - $schemaData->required = []; - } elseif ($schema === self::STRICT_SCHEMA && $isComposerSchemaFile) { + if ($schema === self::STRICT_SCHEMA && $isComposerSchemaFile) { + $schemaData = json_decode((string) file_get_contents($schemaFile)); $schemaData->additionalProperties = false; $schemaData->required = ['name', 'description']; } elseif ($schema === self::AUTH_SCHEMA && $isComposerSchemaFile) { @@ -250,11 +254,13 @@ public static function validateJsonSchema(string $source, $data, int $schema, ?s } $validator = new Validator(); - $validator->check($data, $schemaData); + // convert assoc arrays to objects + $data = json_decode((string) json_encode($data)); + $validator->validate($data, $schemaData); if (!$validator->isValid()) { $errors = []; - foreach ((array) $validator->getErrors() as $error) { + foreach ($validator->getErrors() as $error) { $errors[] = ($error['property'] ? $error['property'].' : ' : '').$error['message']; } throw new JsonValidationException('"'.$source.'" does not match the expected JSON schema', $errors); @@ -284,7 +290,7 @@ public static function encode($data, int $options = 448, string $indent = self:: return Preg::replaceCallback( '#^ {4,}#m', static function ($match) use ($indent): string { - return str_repeat($indent, (int)(strlen($match[0] ?? '') / 4)); + return str_repeat($indent, (int)(strlen($match[0]) / 4)); }, $json ); diff --git a/app/vendor/composer/composer/src/Composer/Json/JsonFormatter.php b/app/vendor/composer/composer/src/Composer/Json/JsonFormatter.php index 006365675..fa1a3c53f 100644 --- a/app/vendor/composer/composer/src/Composer/Json/JsonFormatter.php +++ b/app/vendor/composer/composer/src/Composer/Json/JsonFormatter.php @@ -67,9 +67,7 @@ public static function format(string $json, bool $unescapeUnicode, bool $unescap if ($unescapeUnicode && function_exists('mb_convert_encoding')) { // https://stackoverflow.com/questions/2934563/how-to-decode-unicode-escape-sequences-like-u00ed-to-proper-utf-8-encoded-cha - $buffer = Preg::replaceCallback('/(\\\\+)u([0-9a-f]{4})/i', static function ($match) { - assert(is_string($match[1])); - assert(is_string($match[2])); + $buffer = Preg::replaceCallback('/(\\\\+)u([0-9a-f]{4})/i', static function ($match): string { $l = strlen($match[1]); if ($l % 2) { diff --git a/app/vendor/composer/composer/src/Composer/Json/JsonManipulator.php b/app/vendor/composer/composer/src/Composer/Json/JsonManipulator.php index 2e0f70411..0b45d6556 100644 --- a/app/vendor/composer/composer/src/Composer/Json/JsonManipulator.php +++ b/app/vendor/composer/composer/src/Composer/Json/JsonManipulator.php @@ -214,6 +214,14 @@ public function removeProperty(string $name): bool return $this->removeSubNode('scripts', substr($name, 8)); } + if (strpos($name, 'autoload.') === 0) { + return $this->removeSubNode('autoload', substr($name, 9)); + } + + if (strpos($name, 'autoload-dev.') === 0) { + return $this->removeSubNode('autoload-dev', substr($name, 13)); + } + return $this->removeMainKey($name); } @@ -280,15 +288,9 @@ public function addSubNode(string $mainNode, string $name, $value, bool $append return $matches['start'] . $this->format($value, 1) . $matches['end']; }, $children); - } else { - Preg::match('#^{ (?P\s*?) (?P\S+.*?)? (?P\s*) }$#sx', $children, $match); - - $whitespace = ''; - if (!empty($match['trailingspace'])) { - $whitespace = $match['trailingspace']; - } - - if (!empty($match['content'])) { + } elseif (Preg::isMatch('#^\{(?P\s*?)(?P\S+.*?)?(?P\s*)\}$#s', $children, $match)) { + $whitespace = $match['trailingspace']; + if (null !== $match['content']) { if ($subName !== null) { $value = [$subName => $value]; } @@ -301,11 +303,7 @@ public function addSubNode(string $mainNode, string $name, $value, bool $append $children ); } else { - $whitespace = ''; - if (!empty($match['leadingspace'])) { - $whitespace = $match['leadingspace']; - } - + $whitespace = $match['leadingspace']; $children = Preg::replace( '#^{'.$whitespace.'#', addcslashes('{' . $whitespace . JsonFile::encode($name).': '.$this->format($value, 1) . ',' . $this->newline . $this->indent . $this->indent, '\\$'), @@ -320,6 +318,8 @@ public function addSubNode(string $mainNode, string $name, $value, bool $append // children present but empty $children = '{' . $this->newline . $this->indent . $this->indent . JsonFile::encode($name).': '.$this->format($value, 1) . $whitespace . '}'; } + } else { + throw new \LogicException('Nothing matched above for: '.$children); } $this->contents = Preg::replaceCallback($nodeRegex, static function ($m) use ($children): string { @@ -403,26 +403,27 @@ public function removeSubNode(string $mainNode, string $name): bool // no child data left, $name was the only key in unset($match); - Preg::match('#^{ \s*? (?P\S+.*?)? (?P\s*) }$#sx', $childrenClean, $match); - if (empty($match['content'])) { - $newline = $this->newline; - $indent = $this->indent; + if (Preg::isMatch('#^\{\s*?(?P\S+.*?)?(?P\s*)\}$#s', $childrenClean, $match)) { + if (null === $match['content']) { + $newline = $this->newline; + $indent = $this->indent; - $this->contents = Preg::replaceCallback($nodeRegex, static function ($matches) use ($indent, $newline): string { - return $matches['start'] . '{' . $newline . $indent . '}' . $matches['end']; - }, $this->contents); + $this->contents = Preg::replaceCallback($nodeRegex, static function ($matches) use ($indent, $newline): string { + return $matches['start'] . '{' . $newline . $indent . '}' . $matches['end']; + }, $this->contents); - // we have a subname, so we restore the rest of $name - if ($subName !== null) { - $curVal = json_decode($children, true); - unset($curVal[$name][$subName]); - if ($curVal[$name] === []) { - $curVal[$name] = new \ArrayObject(); + // we have a subname, so we restore the rest of $name + if ($subName !== null) { + $curVal = json_decode($children, true); + unset($curVal[$name][$subName]); + if ($curVal[$name] === []) { + $curVal[$name] = new \ArrayObject(); + } + $this->addSubNode($mainNode, $name, $curVal[$name]); } - $this->addSubNode($mainNode, $name, $curVal[$name]); - } - return true; + return true; + } } $this->contents = Preg::replaceCallback($nodeRegex, function ($matches) use ($name, $subName, $childrenClean): string { diff --git a/app/vendor/composer/composer/src/Composer/PHPStan/ConfigReturnTypeExtension.php b/app/vendor/composer/composer/src/Composer/PHPStan/ConfigReturnTypeExtension.php index e7ff6e52e..88cd635c5 100644 --- a/app/vendor/composer/composer/src/Composer/PHPStan/ConfigReturnTypeExtension.php +++ b/app/vendor/composer/composer/src/Composer/PHPStan/ConfigReturnTypeExtension.php @@ -61,28 +61,26 @@ public function isMethodSupported(MethodReflection $methodReflection): bool return strtolower($methodReflection->getName()) === 'get'; } - public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): Type + public function getTypeFromMethodCall(MethodReflection $methodReflection, MethodCall $methodCall, Scope $scope): ?Type { $args = $methodCall->getArgs(); - $defaultReturn = ParametersAcceptorSelector::selectSingle($methodReflection->getVariants())->getReturnType(); - if (count($args) < 1) { - return $defaultReturn; + return null; } $keyType = $scope->getType($args[0]->value); - if (method_exists($keyType, 'getConstantStrings')) { // @phpstan-ignore-line - depending on PHPStan version, this method will always exist, or not. + if (method_exists($keyType, 'getConstantStrings')) { // @phpstan-ignore function.alreadyNarrowedType (- depending on PHPStan version, this method will always exist, or not.) $strings = $keyType->getConstantStrings(); } else { // for compat with old phpstan versions, we use a deprecated phpstan method. - $strings = TypeUtils::getConstantStrings($keyType); // @phpstan-ignore-line ignore deprecation + $strings = TypeUtils::getConstantStrings($keyType); // @phpstan-ignore staticMethod.deprecated (ignore deprecation) } if ($strings !== []) { $types = []; foreach($strings as $string) { if (!isset($this->properties[$string->getValue()])) { - return $defaultReturn; + return null; } $types[] = $this->properties[$string->getValue()]; } @@ -90,7 +88,7 @@ public function getTypeFromMethodCall(MethodReflection $methodReflection, Method return TypeCombinator::union(...$types); } - return $defaultReturn; + return null; } /** diff --git a/app/vendor/composer/composer/src/Composer/Package/Archiver/ArchivableFilesFinder.php b/app/vendor/composer/composer/src/Composer/Package/Archiver/ArchivableFilesFinder.php index b2b6b87b8..2cf7ffc72 100644 --- a/app/vendor/composer/composer/src/Composer/Package/Archiver/ArchivableFilesFinder.php +++ b/app/vendor/composer/composer/src/Composer/Package/Archiver/ArchivableFilesFinder.php @@ -47,7 +47,11 @@ public function __construct(string $sources, array $excludes, bool $ignoreFilter { $fs = new Filesystem(); - $sources = $fs->normalizePath(realpath($sources)); + $sourcesRealPath = realpath($sources); + if ($sourcesRealPath === false) { + throw new \RuntimeException('Could not realpath() the source directory "'.$sources.'"'); + } + $sources = $fs->normalizePath($sourcesRealPath); if ($ignoreFilters) { $filters = []; @@ -61,14 +65,18 @@ public function __construct(string $sources, array $excludes, bool $ignoreFilter $this->finder = new Finder(); $filter = static function (\SplFileInfo $file) use ($sources, $filters, $fs): bool { - if ($file->isLink() && ($file->getRealPath() === false || strpos($file->getRealPath(), $sources) !== 0)) { + $realpath = $file->getRealPath(); + if ($realpath === false) { + return false; + } + if ($file->isLink() && strpos($realpath, $sources) !== 0) { return false; } $relativePath = Preg::replace( '#^'.preg_quote($sources, '#').'#', '', - $fs->normalizePath($file->getRealPath()) + $fs->normalizePath($realpath) ); $exclude = false; @@ -79,10 +87,6 @@ public function __construct(string $sources, array $excludes, bool $ignoreFilter return !$exclude; }; - if (method_exists($filter, 'bindTo')) { - $filter = $filter->bindTo(null); - } - $this->finder ->in($sources) ->filter($filter) diff --git a/app/vendor/composer/composer/src/Composer/Package/Archiver/ArchiveManager.php b/app/vendor/composer/composer/src/Composer/Package/Archiver/ArchiveManager.php index 4b15fa844..77c3ebe3d 100644 --- a/app/vendor/composer/composer/src/Composer/Package/Archiver/ArchiveManager.php +++ b/app/vendor/composer/composer/src/Composer/Package/Archiver/ArchiveManager.php @@ -96,7 +96,7 @@ public function getPackageFilenameParts(CompletePackageInterface $package): arra $sourceReference = $package->getSourceReference(); if (null !== $sourceReference) { - $parts['source_reference'] = substr(sha1($sourceReference), 0, 6); + $parts['source_reference'] = substr(hash('sha1', $sourceReference), 0, 6); } $parts = array_filter($parts, function (?string $part) { @@ -171,7 +171,7 @@ public function archive(CompletePackageInterface $package, string $format, strin $sourcePath = realpath('.'); } else { // Directory used to download the sources - $sourcePath = sys_get_temp_dir().'/composer_archive'.uniqid(); + $sourcePath = sys_get_temp_dir().'/composer_archive'.bin2hex(random_bytes(5)); $filesystem->ensureDirectoryExists($sourcePath); try { @@ -216,7 +216,7 @@ public function archive(CompletePackageInterface $package, string $format, strin } // Create the archive - $tempTarget = sys_get_temp_dir().'/composer_archive'.uniqid().'.'.$format; + $tempTarget = sys_get_temp_dir().'/composer_archive'.bin2hex(random_bytes(5)).'.'.$format; $filesystem->ensureDirectoryExists(dirname($tempTarget)); $archivePath = $usableArchiver->archive( diff --git a/app/vendor/composer/composer/src/Composer/Package/Archiver/PharArchiver.php b/app/vendor/composer/composer/src/Composer/Package/Archiver/PharArchiver.php index c3d025f8d..6a64480ed 100644 --- a/app/vendor/composer/composer/src/Composer/Package/Archiver/PharArchiver.php +++ b/app/vendor/composer/composer/src/Composer/Package/Archiver/PharArchiver.php @@ -12,6 +12,8 @@ namespace Composer\Package\Archiver; +use PharData; + /** * @author Till Klampaeckel * @author Nils Adermann @@ -65,9 +67,45 @@ public function archive(string $sources, string $target, string $format, array $ $phar->buildFromIterator($filesOnly, $sources); $filesOnly->addEmptyDir($phar, $sources); + if (!file_exists($target)) { + $target = $filename . '.' . $format; + unset($phar); + + if ($format === 'tar') { + // create an empty tar file (=10240 null bytes) if the tar file is empty and PharData thus did not write it to disk + file_put_contents($target, str_repeat("\0", 10240)); + } elseif ($format === 'zip') { + // create minimal valid ZIP file (Empty Central Directory + End of Central Directory record) + $eocd = pack( + 'VvvvvVVv', + 0x06054b50, // End of central directory signature + 0, // Number of this disk + 0, // Disk where central directory starts + 0, // Number of central directory records on this disk + 0, // Total number of central directory records + 0, // Size of central directory (bytes) + 0, // Offset of start of central directory + 0 // Comment length + ); + + file_put_contents($target, $eocd); + } elseif ($format === 'tar.gz' || $format === 'tar.bz2') { + if (!PharData::canCompress(static::$compressFormats[$format])) { + throw new \RuntimeException(sprintf('Can not compress to %s format', $format)); + } + if ($format === 'tar.gz' && function_exists('gzcompress')) { + file_put_contents($target, gzcompress(str_repeat("\0", 10240))); + } elseif ($format === 'tar.bz2' && function_exists('bzcompress')) { + file_put_contents($target, bzcompress(str_repeat("\0", 10240))); + } + } + + return $target; + } + if (isset(static::$compressFormats[$format])) { // Check can be compressed? - if (!$phar->canCompress(static::$compressFormats[$format])) { + if (!PharData::canCompress(static::$compressFormats[$format])) { throw new \RuntimeException(sprintf('Can not compress to %s format', $format)); } diff --git a/app/vendor/composer/composer/src/Composer/Package/Archiver/ZipArchiver.php b/app/vendor/composer/composer/src/Composer/Package/Archiver/ZipArchiver.php index 5ab5bd55b..bc6829af9 100644 --- a/app/vendor/composer/composer/src/Composer/Package/Archiver/ZipArchiver.php +++ b/app/vendor/composer/composer/src/Composer/Package/Archiver/ZipArchiver.php @@ -12,8 +12,9 @@ namespace Composer\Package\Archiver; -use ZipArchive; use Composer\Util\Filesystem; +use Composer\Util\Platform; +use ZipArchive; /** * @author Jan Prieser @@ -44,15 +45,17 @@ public function archive(string $sources, string $target, string $format, array $ $files = new ArchivableFilesFinder($sources, $excludes, $ignoreFilters); foreach ($files as $file) { /** @var \Symfony\Component\Finder\SplFileInfo $file */ - $filepath = strtr($file->getPath()."/".$file->getFilename(), '\\', '/'); - $localname = $filepath; - if (strpos($localname, $sources . '/') === 0) { - $localname = substr($localname, strlen($sources . '/')); + $filepath = $file->getPathname(); + $relativePath = $file->getRelativePathname(); + + if (Platform::isWindows()) { + $relativePath = strtr($relativePath, '\\', '/'); } + if ($file->isDir()) { - $zip->addEmptyDir($localname); + $zip->addEmptyDir($relativePath); } else { - $zip->addFile($filepath, $localname); + $zip->addFile($filepath, $relativePath); } /** @@ -64,10 +67,26 @@ public function archive(string $sources, string $target, string $format, array $ /** * Ensure to preserve the permission umasks for the filepath in the archive. */ - $zip->setExternalAttributesName($localname, ZipArchive::OPSYS_UNIX, $perms << 16); + $zip->setExternalAttributesName($relativePath, ZipArchive::OPSYS_UNIX, $perms << 16); } } if ($zip->close()) { + if (!file_exists($target)) { + // create minimal valid ZIP file (Empty Central Directory + End of Central Directory record) + $eocd = pack( + 'VvvvvVVv', + 0x06054b50, // End of central directory signature + 0, // Number of this disk + 0, // Disk where central directory starts + 0, // Number of central directory records on this disk + 0, // Total number of central directory records + 0, // Size of central directory (bytes) + 0, // Offset of start of central directory + 0 // Comment length + ); + file_put_contents($target, $eocd); + } + return $target; } } diff --git a/app/vendor/composer/composer/src/Composer/Package/BasePackage.php b/app/vendor/composer/composer/src/Composer/Package/BasePackage.php index d6d37d360..764fdb424 100644 --- a/app/vendor/composer/composer/src/Composer/Package/BasePackage.php +++ b/app/vendor/composer/composer/src/Composer/Package/BasePackage.php @@ -40,8 +40,7 @@ abstract class BasePackage implements PackageInterface public const STABILITY_ALPHA = 15; public const STABILITY_DEV = 20; - /** @var array */ - public static $stabilities = [ + public const STABILITIES = [ 'stable' => self::STABILITY_STABLE, 'RC' => self::STABILITY_RC, 'beta' => self::STABILITY_BETA, @@ -49,6 +48,14 @@ abstract class BasePackage implements PackageInterface 'dev' => self::STABILITY_DEV, ]; + /** + * @deprecated + * @readonly + * @var array, self::STABILITY_*> + * @phpstan-ignore property.readOnlyByPhpDocDefaultValue + */ + public static $stabilities = self::STABILITIES; + /** * READ-ONLY: The package id, public for fast access in dependency solver * @var int @@ -234,7 +241,7 @@ public function getFullPrettyVersion(bool $truncate = true, int $displayMode = P */ public function getStabilityPriority(): int { - return self::$stabilities[$this->getStability()]; + return self::STABILITIES[$this->getStability()]; } public function __clone() diff --git a/app/vendor/composer/composer/src/Composer/Package/Comparer/Comparer.php b/app/vendor/composer/composer/src/Composer/Package/Comparer/Comparer.php index 1fd79b8bb..70a7a28f8 100644 --- a/app/vendor/composer/composer/src/Composer/Package/Comparer/Comparer.php +++ b/app/vendor/composer/composer/src/Composer/Package/Comparer/Comparer.php @@ -136,7 +136,7 @@ private function doTree(string $dir, array &$array) return false; } } elseif (is_file($dir.'/'.$file) && filesize($dir.'/'.$file)) { - $array[$dir][$file] = md5_file($dir.'/'.$file); + $array[$dir][$file] = hash_file(\PHP_VERSION_ID > 80100 ? 'xxh3' : 'sha1', $dir.'/'.$file); } } } diff --git a/app/vendor/composer/composer/src/Composer/Package/Dumper/ArrayDumper.php b/app/vendor/composer/composer/src/Composer/Package/Dumper/ArrayDumper.php index 046ba6674..9333bd9a0 100644 --- a/app/vendor/composer/composer/src/Composer/Package/Dumper/ArrayDumper.php +++ b/app/vendor/composer/composer/src/Composer/Package/Dumper/ArrayDumper.php @@ -37,6 +37,7 @@ public function dump(PackageInterface $package): array 'devAutoload' => 'autoload-dev', 'notificationUrl' => 'notification-url', 'includePaths' => 'include-path', + 'phpExt' => 'php-ext', ]; $data = []; diff --git a/app/vendor/composer/composer/src/Composer/Package/Loader/RootPackageLoader.php b/app/vendor/composer/composer/src/Composer/Package/Loader/RootPackageLoader.php index 64a169019..1e278a1d0 100644 --- a/app/vendor/composer/composer/src/Composer/Package/Loader/RootPackageLoader.php +++ b/app/vendor/composer/composer/src/Composer/Package/Loader/RootPackageLoader.php @@ -60,7 +60,12 @@ public function __construct(RepositoryManager $manager, Config $config, ?Version $this->manager = $manager; $this->config = $config; - $this->versionGuesser = $versionGuesser ?: new VersionGuesser($config, new ProcessExecutor($io), $this->versionParser); + if (null === $versionGuesser) { + $processExecutor = new ProcessExecutor($io); + $processExecutor->enableAsync(); + $versionGuesser = new VersionGuesser($config, $processExecutor, $this->versionParser); + } + $this->versionGuesser = $versionGuesser; $this->io = $io; } @@ -88,7 +93,7 @@ public function load(array $config, string $class = 'Composer\Package\RootPackag // override with env var if available if (Platform::getEnv('COMPOSER_ROOT_VERSION')) { - $config['version'] = Platform::getEnv('COMPOSER_ROOT_VERSION'); + $config['version'] = $this->versionGuesser->getRootVersionFromEnv(); } else { $versionData = $this->versionGuesser->guessVersion($config, $cwd ?? Platform::getCwd(true)); if ($versionData) { @@ -227,6 +232,7 @@ private function extractAliases(array $requires, array $aliases): array * * @param array $requires * @param array $stabilityFlags + * @param key-of $minimumStability * * @return array * @@ -235,8 +241,7 @@ private function extractAliases(array $requires, array $aliases): array */ public static function extractStabilityFlags(array $requires, string $minimumStability, array $stabilityFlags): array { - $stabilities = BasePackage::$stabilities; - /** @var int $minimumStability */ + $stabilities = BasePackage::STABILITIES; $minimumStability = $stabilities[$minimumStability]; foreach ($requires as $reqName => $reqVersion) { $constraints = []; diff --git a/app/vendor/composer/composer/src/Composer/Package/Loader/ValidatingArrayLoader.php b/app/vendor/composer/composer/src/Composer/Package/Loader/ValidatingArrayLoader.php index 6d1388e23..e3600d6e1 100644 --- a/app/vendor/composer/composer/src/Composer/Package/Loader/ValidatingArrayLoader.php +++ b/app/vendor/composer/composer/src/Composer/Package/Loader/ValidatingArrayLoader.php @@ -132,33 +132,54 @@ public function load(array $config, string $class = 'Composer\Package\CompletePa } } - // check for license validity on newly updated branches - if (isset($this->config['license']) && (null === $releaseDate || $releaseDate->getTimestamp() >= strtotime('-8days'))) { + if (isset($this->config['license'])) { + // validate main data types if (is_array($this->config['license']) || is_string($this->config['license'])) { $licenses = (array) $this->config['license']; - $licenseValidator = new SpdxLicenses(); - foreach ($licenses as $license) { - // replace proprietary by MIT for validation purposes since it's not a valid SPDX identifier, but is accepted by composer - if ('proprietary' === $license) { - continue; + foreach ($licenses as $index => $license) { + if (!is_string($license)) { + $this->warnings[] = sprintf( + 'License %s should be a string.', + json_encode($license) + ); + unset($licenses[$index]); } - $licenseToValidate = str_replace('proprietary', 'MIT', $license); - if (!$licenseValidator->validate($licenseToValidate)) { - if ($licenseValidator->validate(trim($licenseToValidate))) { - $this->warnings[] = sprintf( - 'License %s must not contain extra spaces, make sure to trim it.', - json_encode($license) - ); - } else { - $this->warnings[] = sprintf( - 'License %s is not a valid SPDX license identifier, see https://spdx.org/licenses/ if you use an open license.' . PHP_EOL . - 'If the software is closed-source, you may use "proprietary" as license.', - json_encode($license) - ); + } + + // check for license validity on newly updated branches/tags + if (null === $releaseDate || $releaseDate->getTimestamp() >= strtotime('-8days')) { + $licenseValidator = new SpdxLicenses(); + foreach ($licenses as $license) { + // replace proprietary by MIT for validation purposes since it's not a valid SPDX identifier, but is accepted by composer + if ('proprietary' === $license) { + continue; + } + $licenseToValidate = str_replace('proprietary', 'MIT', $license); + if (!$licenseValidator->validate($licenseToValidate)) { + if ($licenseValidator->validate(trim($licenseToValidate))) { + $this->warnings[] = sprintf( + 'License %s must not contain extra spaces, make sure to trim it.', + json_encode($license) + ); + } else { + $this->warnings[] = sprintf( + 'License %s is not a valid SPDX license identifier, see https://spdx.org/licenses/ if you use an open license.' . PHP_EOL . + 'If the software is closed-source, you may use "proprietary" as license.', + json_encode($license) + ); + } } } } + + $this->config['license'] = array_values($licenses); + } else { + $this->warnings[] = sprintf( + 'License must be a string or array of strings, got %s.', + json_encode($this->config['license']) + ); + unset($this->config['license']); } } @@ -323,8 +344,8 @@ public function load(array $config, string $class = 'Composer\Package\CompletePa } if ($this->validateString('minimum-stability') && isset($this->config['minimum-stability'])) { - if (!isset(BasePackage::$stabilities[strtolower($this->config['minimum-stability'])]) && $this->config['minimum-stability'] !== 'RC') { - $this->errors[] = 'minimum-stability : invalid value ('.$this->config['minimum-stability'].'), must be one of '.implode(', ', array_keys(BasePackage::$stabilities)); + if (!isset(BasePackage::STABILITIES[strtolower($this->config['minimum-stability'])]) && $this->config['minimum-stability'] !== 'RC') { + $this->errors[] = 'minimum-stability : invalid value ('.$this->config['minimum-stability'].'), must be one of '.implode(', ', array_keys(BasePackage::STABILITIES)); unset($this->config['minimum-stability']); } } diff --git a/app/vendor/composer/composer/src/Composer/Package/Locker.php b/app/vendor/composer/composer/src/Composer/Package/Locker.php index f832e797c..38cd8ef3a 100644 --- a/app/vendor/composer/composer/src/Composer/Package/Locker.php +++ b/app/vendor/composer/composer/src/Composer/Package/Locker.php @@ -66,13 +66,21 @@ public function __construct(IOInterface $io, JsonFile $lockFile, InstallationMan { $this->lockFile = $lockFile; $this->installationManager = $installationManager; - $this->hash = md5($composerFileContents); + $this->hash = hash('md5', $composerFileContents); $this->contentHash = self::getContentHash($composerFileContents); $this->loader = new ArrayLoader(null, true); $this->dumper = new ArrayDumper(); $this->process = $process ?? new ProcessExecutor($io); } + /** + * @internal + */ + public function getJsonFile(): JsonFile + { + return $this->lockFile; + } + /** * Returns the md5 hash of the sorted content of the composer file. * @@ -107,7 +115,7 @@ public static function getContentHash(string $composerFileContents): string ksort($relevantContent); - return md5(JsonFile::encode($relevantContent, 0)); + return hash('md5', JsonFile::encode($relevantContent, 0)); } /** @@ -247,6 +255,9 @@ public function getPlatformRequirements(bool $withDevReqs = false): array return $requirements; } + /** + * @return key-of + */ public function getMinimumStability(): string { $lockData = $this->getLockData(); @@ -361,7 +372,7 @@ public function setLockData(array $packages, ?array $devPackages, array $platfor 'Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies', 'This file is @gener'.'ated automatically', ], 'content-hash' => $this->contentHash, - 'packages' => null, + 'packages' => $this->lockPackages($packages), 'packages-dev' => null, 'aliases' => $aliases, 'minimum-stability' => $minimumStability, @@ -370,7 +381,6 @@ public function setLockData(array $packages, ?array $devPackages, array $platfor 'prefer-lowest' => $preferLowest, ]; - $lock['packages'] = $this->lockPackages($packages); if (null !== $devPackages) { $lock['packages-dev'] = $this->lockPackages($devPackages); } @@ -382,6 +392,8 @@ public function setLockData(array $packages, ?array $devPackages, array $platfor } $lock['plugin-api-version'] = PluginInterface::PLUGIN_API_VERSION; + $lock = $this->fixupJsonDataType($lock); + try { $isLocked = $this->isLocked(); } catch (ParsingException $e) { @@ -403,6 +415,60 @@ public function setLockData(array $packages, ?array $devPackages, array $platfor return false; } + /** + * Updates the lock file's hash in-place from a given composer.json's JsonFile + * + * This does not reload or require any packages, and retains the filemtime of the lock file. + * + * Use this only to update the lock file hash after updating a composer.json in ways that are guaranteed NOT to impact the dependency resolution. + * + * This is a risky method, use carefully. + * + * @param (callable(array): array)|null $dataProcessor Receives the lock data and can process it before it gets written to disk + */ + public function updateHash(JsonFile $composerJson, ?callable $dataProcessor = null): void + { + $contents = file_get_contents($composerJson->getPath()); + if (false === $contents) { + throw new \RuntimeException('Unable to read '.$composerJson->getPath().' contents to update the lock file hash.'); + } + + $lockMtime = filemtime($this->lockFile->getPath()); + $lockData = $this->lockFile->read(); + $lockData['content-hash'] = Locker::getContentHash($contents); + if ($dataProcessor !== null) { + $lockData = $dataProcessor($lockData); + } + + $this->lockFile->write($this->fixupJsonDataType($lockData)); + $this->lockDataCache = null; + $this->virtualFileWritten = false; + if (is_int($lockMtime)) { + @touch($this->lockFile->getPath(), $lockMtime); + } + } + + /** + * Ensures correct data types and ordering for the JSON lock format + * + * @param array $lockData + * @return array + */ + private function fixupJsonDataType(array $lockData): array + { + foreach (['stability-flags', 'platform', 'platform-dev'] as $key) { + if (isset($lockData[$key]) && is_array($lockData[$key]) && \count($lockData[$key]) === 0) { + $lockData[$key] = new \stdClass(); + } + } + + if (is_array($lockData['stability-flags'])) { + ksort($lockData['stability-flags']); + } + + return $lockData; + } + /** * @param PackageInterface[] $packages * @@ -488,13 +554,14 @@ private function getPackageTime(PackageInterface $package): ?string case 'git': GitUtil::cleanEnv(); - if (0 === $this->process->execute('git log -n1 --pretty=%ct '.ProcessExecutor::escape($sourceRef).GitUtil::getNoShowSignatureFlag($this->process), $output, $path) && Preg::isMatch('{^\s*\d+\s*$}', $output)) { + $command = array_merge(['git', 'log', '-n1', '--pretty=%ct', (string) $sourceRef], GitUtil::getNoShowSignatureFlags($this->process)); + if (0 === $this->process->execute($command, $output, $path) && Preg::isMatch('{^\s*\d+\s*$}', $output)) { $datetime = new \DateTime('@'.trim($output), new \DateTimeZone('UTC')); } break; case 'hg': - if (0 === $this->process->execute('hg log --template "{date|hgdate}" -r '.ProcessExecutor::escape($sourceRef), $output, $path) && Preg::isMatch('{^\s*(\d+)\s*}', $output, $match)) { + if (0 === $this->process->execute(['hg', 'log', '--template', '{date|hgdate}', '-r', (string) $sourceRef], $output, $path) && Preg::isMatch('{^\s*(\d+)\s*}', $output, $match)) { $datetime = new \DateTime('@'.$match[1], new \DateTimeZone('UTC')); } break; diff --git a/app/vendor/composer/composer/src/Composer/Package/Package.php b/app/vendor/composer/composer/src/Composer/Package/Package.php index 9d1b0ffc1..faa2a07a0 100644 --- a/app/vendor/composer/composer/src/Composer/Package/Package.php +++ b/app/vendor/composer/composer/src/Composer/Package/Package.php @@ -23,6 +23,7 @@ * * @phpstan-import-type AutoloadRules from PackageInterface * @phpstan-import-type DevAutoloadRules from PackageInterface + * @phpstan-import-type PhpExtConfig from PackageInterface */ class Package extends BasePackage { @@ -98,7 +99,10 @@ class Package extends BasePackage protected $isDefaultBranch = false; /** @var mixed[] */ protected $transportOptions = []; - /** @var array{priority?: int, configure-options?: list}|null */ + /** + * @var array|null + * @phpstan-var PhpExtConfig|null + */ protected $phpExt = null; /** @@ -593,9 +597,11 @@ public function getIncludePaths(): array } /** - * Sets the list of paths added to PHP's include path. + * Sets the settings for php extension packages + * + * @param array|null $phpExt * - * @param array{extension-name?: string, priority?: int, support-zts?: bool, configure-options?: list}|null $phpExt List of directories. + * @phpstan-param PhpExtConfig|null $phpExt */ public function setPhpExt(?array $phpExt): void { diff --git a/app/vendor/composer/composer/src/Composer/Package/PackageInterface.php b/app/vendor/composer/composer/src/Composer/Package/PackageInterface.php index b7c9ecd45..68e22fa0e 100644 --- a/app/vendor/composer/composer/src/Composer/Package/PackageInterface.php +++ b/app/vendor/composer/composer/src/Composer/Package/PackageInterface.php @@ -23,6 +23,7 @@ * * @phpstan-type AutoloadRules array{psr-0?: array, psr-4?: array, classmap?: list, files?: list, exclude-from-classmap?: list} * @phpstan-type DevAutoloadRules array{psr-0?: array, psr-4?: array, classmap?: list, files?: list} + * @phpstan-type PhpExtConfig array{extension-name?: string, priority?: int, support-zts?: bool, support-nts?: bool, build-path?: string|null, download-url-method?: string, os-families?: non-empty-list, os-families-exclude?: non-empty-list, configure-options?: list} */ interface PackageInterface { @@ -326,7 +327,9 @@ public function getIncludePaths(): array; /** * Returns the settings for php extension packages * - * @return array{extension-name?: string, priority?: int, support-zts?: bool, configure-options?: list}|null + * @return array|null + * + * @phpstan-return PhpExtConfig|null */ public function getPhpExt(): ?array; diff --git a/app/vendor/composer/composer/src/Composer/Package/RootPackage.php b/app/vendor/composer/composer/src/Composer/Package/RootPackage.php index e1305426f..a0f8e659f 100644 --- a/app/vendor/composer/composer/src/Composer/Package/RootPackage.php +++ b/app/vendor/composer/composer/src/Composer/Package/RootPackage.php @@ -21,7 +21,7 @@ class RootPackage extends CompletePackage implements RootPackageInterface { public const DEFAULT_PRETTY_VERSION = '1.0.0+no-version-set'; - /** @var string */ + /** @var key-of */ protected $minimumStability = 'stable'; /** @var bool */ protected $preferStable = false; diff --git a/app/vendor/composer/composer/src/Composer/Package/RootPackageInterface.php b/app/vendor/composer/composer/src/Composer/Package/RootPackageInterface.php index 4adad6c8b..8a08060f8 100644 --- a/app/vendor/composer/composer/src/Composer/Package/RootPackageInterface.php +++ b/app/vendor/composer/composer/src/Composer/Package/RootPackageInterface.php @@ -33,6 +33,8 @@ public function getAliases(): array; /** * Returns the minimum stability of the package + * + * @return key-of */ public function getMinimumStability(): string; @@ -120,12 +122,14 @@ public function setDevAutoload(array $devAutoload): void; /** * Set the stabilityFlags * - * @param array $stabilityFlags + * @phpstan-param array $stabilityFlags */ public function setStabilityFlags(array $stabilityFlags): void; /** * Set the minimumStability + * + * @phpstan-param key-of $minimumStability */ public function setMinimumStability(string $minimumStability): void; diff --git a/app/vendor/composer/composer/src/Composer/Package/Version/StabilityFilter.php b/app/vendor/composer/composer/src/Composer/Package/Version/StabilityFilter.php index 172901d44..7e0182a6e 100644 --- a/app/vendor/composer/composer/src/Composer/Package/Version/StabilityFilter.php +++ b/app/vendor/composer/composer/src/Composer/Package/Version/StabilityFilter.php @@ -23,11 +23,11 @@ class StabilityFilter * Checks if any of the provided package names in the given stability match the configured acceptable stability and flags * * @param int[] $acceptableStabilities array of stability => BasePackage::STABILITY_* value - * @phpstan-param array $acceptableStabilities + * @phpstan-param array, BasePackage::STABILITY_*> $acceptableStabilities * @param int[] $stabilityFlags an array of package name => BasePackage::STABILITY_* value * @phpstan-param array $stabilityFlags * @param string[] $names The package name(s) to check for stability flags - * @param string $stability one of 'stable', 'RC', 'beta', 'alpha' or 'dev' + * @param key-of $stability one of 'stable', 'RC', 'beta', 'alpha' or 'dev' * @return bool true if any package name is acceptable */ public static function isPackageAcceptable(array $acceptableStabilities, array $stabilityFlags, array $names, string $stability): bool @@ -35,7 +35,7 @@ public static function isPackageAcceptable(array $acceptableStabilities, array $ foreach ($names as $name) { // allow if package matches the package-specific stability flag if (isset($stabilityFlags[$name])) { - if (BasePackage::$stabilities[$stability] <= $stabilityFlags[$name]) { + if (BasePackage::STABILITIES[$stability] <= $stabilityFlags[$name]) { return true; } } elseif (isset($acceptableStabilities[$stability])) { diff --git a/app/vendor/composer/composer/src/Composer/Package/Version/VersionBumper.php b/app/vendor/composer/composer/src/Composer/Package/Version/VersionBumper.php index e6dbdebe6..b100d0e00 100644 --- a/app/vendor/composer/composer/src/Composer/Package/Version/VersionBumper.php +++ b/app/vendor/composer/composer/src/Composer/Package/Version/VersionBumper.php @@ -39,6 +39,8 @@ class VersionBumper * * ^1.2 || ^2.3 + 2.4.0 -> ^1.2 || ^2.4 * * ^3@dev + 3.2.99999-dev -> ^3.2@dev * * ~2 + 2.0-beta.1 -> ~2 + * * ~2.0.0 + 2.0.3 -> ~2.0.3 + * * ~2.0 + 2.0.3 -> ^2.0.3 * * dev-master + dev-master -> dev-master * * * + 1.2.3 -> >=1.2.3 */ @@ -84,7 +86,7 @@ public function bumpRequirement(ConstraintInterface $constraint, PackageInterfac (?<=,|\ |\||^) # leading separator (?P \^v?'.$major.'(?:\.\d+)* # e.g. ^2.anything - | ~v?'.$major.'(?:\.\d+){0,2} # e.g. ~2 or ~2.2 or ~2.2.2 but no more + | ~v?'.$major.'(?:\.\d+){1,3} # e.g. ~2.2 or ~2.2.2 or ~2.2.2.2 | v?'.$major.'(?:\.[*x])+ # e.g. 2.* or 2.*.* or 2.x.x.x etc | >=v?\d(?:\.\d+)* # e.g. >=2 or >=1.2 etc | \* # full wildcard @@ -99,8 +101,11 @@ public function bumpRequirement(ConstraintInterface $constraint, PackageInterfac if (substr_count($match[0], '.') === 2 && substr_count($versionWithoutSuffix, '.') === 1) { $suffix = '.0'; } - if (str_starts_with($match[0], '~') && substr_count($match[0], '.') === 2) { - $replacement = '~'.$versionWithoutSuffix.$suffix; + if (str_starts_with($match[0], '~') && substr_count($match[0], '.') !== 1) { + // take as many version bits from the current version as we have in the constraint to bump it without making it more specific + $versionBits = explode('.', $versionWithoutSuffix); + $versionBits = array_pad($versionBits, substr_count($match[0], '.') + 1, '0'); + $replacement = '~'.implode('.', array_slice($versionBits, 0, substr_count($match[0], '.') + 1)); } elseif ($match[0] === '*' || str_starts_with($match[0], '>=')) { $replacement = '>='.$versionWithoutSuffix.$suffix; } else { diff --git a/app/vendor/composer/composer/src/Composer/Package/Version/VersionGuesser.php b/app/vendor/composer/composer/src/Composer/Package/Version/VersionGuesser.php index 2b2b19706..7e0f8278e 100644 --- a/app/vendor/composer/composer/src/Composer/Package/Version/VersionGuesser.php +++ b/app/vendor/composer/composer/src/Composer/Package/Version/VersionGuesser.php @@ -13,6 +13,7 @@ namespace Composer\Package\Version; use Composer\Config; +use Composer\IO\IOInterface; use Composer\Pcre\Preg; use Composer\Repository\Vcs\HgDriver; use Composer\IO\NullIO; @@ -50,11 +51,17 @@ class VersionGuesser */ private $versionParser; - public function __construct(Config $config, ProcessExecutor $process, SemverVersionParser $versionParser) + /** + * @var IOInterface|null + */ + private $io; + + public function __construct(Config $config, ProcessExecutor $process, SemverVersionParser $versionParser, ?IOInterface $io = null) { $this->config = $config; $this->process = $process; $this->versionParser = $versionParser; + $this->io = $io; } /** @@ -173,11 +180,12 @@ private function guessGitVersion(array $packageConfig, string $path): array $featurePrettyVersion = $prettyVersion; // try to find the best (nearest) version branch to assume this feature's version - $result = $this->guessFeatureVersion($packageConfig, $version, $branches, 'git rev-list %candidate%..%branch%', $path); + $result = $this->guessFeatureVersion($packageConfig, $version, $branches, ['git', 'rev-list', '%candidate%..%branch%'], $path); $version = $result['version']; $prettyVersion = $result['pretty_version']; } } + GitUtil::checkForRepoOwnershipError($this->process->getErrorOutput(), $path, $this->io); if (!$version || $isDetached) { $result = $this->versionFromGitTags($path); @@ -190,7 +198,7 @@ private function guessGitVersion(array $packageConfig, string $path): array } if (null === $commit) { - $command = 'git log --pretty="%H" -n1 HEAD'.GitUtil::getNoShowSignatureFlag($this->process); + $command = array_merge(['git', 'log', '--pretty=%H', '-n1', 'HEAD'], GitUtil::getNoShowSignatureFlags($this->process)); if (0 === $this->process->execute($command, $output, $path)) { $commit = trim($output) ?: null; } @@ -209,7 +217,7 @@ private function guessGitVersion(array $packageConfig, string $path): array private function versionFromGitTags(string $path): ?array { // try to fetch current version from git tags - if (0 === $this->process->execute('git describe --exact-match --tags', $output, $path)) { + if (0 === $this->process->execute(['git', 'describe', '--exact-match', '--tags'], $output, $path)) { try { $version = $this->versionParser->normalize(trim($output)); @@ -229,7 +237,7 @@ private function versionFromGitTags(string $path): ?array private function guessHgVersion(array $packageConfig, string $path): ?array { // try to fetch current version from hg branch - if (0 === $this->process->execute('hg branch', $output, $path)) { + if (0 === $this->process->execute(['hg', 'branch'], $output, $path)) { $branch = trim($output); $version = $this->versionParser->normalizeBranch($branch); $isFeatureBranch = 0 === strpos($version, 'dev-'); @@ -248,7 +256,7 @@ private function guessHgVersion(array $packageConfig, string $path): ?array $branches = array_map('strval', array_keys($driver->getBranches())); // try to find the best (nearest) version branch to assume this feature's version - $result = $this->guessFeatureVersion($packageConfig, $version, $branches, 'hg log -r "not ancestors(\'%candidate%\') and ancestors(\'%branch%\')" --template "{node}\\n"', $path); + $result = $this->guessFeatureVersion($packageConfig, $version, $branches, ['hg', 'log', '-r', 'not ancestors(\'%candidate%\') and ancestors(\'%branch%\')', '--template', '"{node}\\n"'], $path); $result['commit'] = ''; $result['feature_version'] = $version; $result['feature_pretty_version'] = $version; @@ -261,13 +269,12 @@ private function guessHgVersion(array $packageConfig, string $path): ?array /** * @param array $packageConfig - * @param string[] $branches - * - * @phpstan-param non-empty-string $scmCmdline + * @param list $branches + * @param list $scmCmdline * * @return array{version: string|null, pretty_version: string|null} */ - private function guessFeatureVersion(array $packageConfig, ?string $version, array $branches, string $scmCmdline, string $path): array + private function guessFeatureVersion(array $packageConfig, ?string $version, array $branches, array $scmCmdline, string $path): array { $prettyVersion = $version; @@ -285,7 +292,7 @@ private function guessFeatureVersion(array $packageConfig, ?string $version, arr } // sort local branches first then remote ones - // and sort numeric branches below named ones, to make sure if the branch has the same distance from main and 1.10 and 1.9 for example, main is picked + // and sort numeric branches below named ones, to make sure if the branch has the same distance from main and 1.10 and 1.9 for example, 1.9 is picked // and sort using natural sort so that 1.10 will appear before 1.9 usort($branches, static function ($a, $b): int { $aRemote = 0 === strpos($a, 'remotes/'); @@ -301,7 +308,8 @@ private function guessFeatureVersion(array $packageConfig, ?string $version, arr $promises = []; $this->process->setMaxJobs(30); try { - foreach ($branches as $candidate) { + $lastIndex = -1; + foreach ($branches as $index => $candidate) { $candidateVersion = Preg::replace('{^remotes/\S+/}', '', $candidate); // do not compare against itself or other feature branches @@ -309,14 +317,20 @@ private function guessFeatureVersion(array $packageConfig, ?string $version, arr continue; } - $cmdLine = str_replace(['%candidate%', '%branch%'], [$candidate, $branch], $scmCmdline); - $promises[] = $this->process->executeAsync($cmdLine, $path)->then(function (Process $process) use (&$length, &$version, &$prettyVersion, $candidateVersion, &$promises): void { + $cmdLine = array_map(static function (string $component) use ($candidate, $branch) { + return str_replace(['%candidate%', '%branch%'], [$candidate, $branch], $component); + }, $scmCmdline); + $promises[] = $this->process->executeAsync($cmdLine, $path)->then(function (Process $process) use (&$lastIndex, $index, &$length, &$version, &$prettyVersion, $candidateVersion, &$promises): void { if (!$process->isSuccessful()) { return; } $output = $process->getOutput(); - if (strlen($output) < $length) { + // overwrite existing if we have a shorter diff, or we have an equal diff and an index that comes later in the array (i.e. older version) + // as newer versions typically have more commits, if the feature branch is based on a newer branch it should have a longer diff to the old version + // but if it doesn't and they have equal diffs, then it probably is based on the old version + if (strlen($output) < $length || (strlen($output) === $length && $lastIndex < $index)) { + $lastIndex = $index; $length = strlen($output); $version = $this->versionParser->normalizeBranch($candidateVersion); $prettyVersion = 'dev-' . $candidateVersion; @@ -361,14 +375,14 @@ private function guessFossilVersion(string $path): array $prettyVersion = null; // try to fetch current version from fossil - if (0 === $this->process->execute('fossil branch list', $output, $path)) { + if (0 === $this->process->execute(['fossil', 'branch', 'list'], $output, $path)) { $branch = trim($output); $version = $this->versionParser->normalizeBranch($branch); $prettyVersion = 'dev-' . $branch; } // try to fetch current version from fossil tags - if (0 === $this->process->execute('fossil tag list', $output, $path)) { + if (0 === $this->process->execute(['fossil', 'tag', 'list'], $output, $path)) { try { $version = $this->versionParser->normalize(trim($output)); $prettyVersion = trim($output); @@ -389,7 +403,7 @@ private function guessSvnVersion(array $packageConfig, string $path): ?array SvnUtil::cleanEnv(); // try to fetch current version from svn - if (0 === $this->process->execute('svn info --xml', $output, $path)) { + if (0 === $this->process->execute(['svn', 'info', '--xml'], $output, $path)) { $trunkPath = isset($packageConfig['trunk-path']) ? preg_quote($packageConfig['trunk-path'], '#') : 'trunk'; $branchesPath = isset($packageConfig['branches-path']) ? preg_quote($packageConfig['branches-path'], '#') : 'branches'; $tagsPath = isset($packageConfig['tags-path']) ? preg_quote($packageConfig['tags-path'], '#') : 'tags'; @@ -419,4 +433,17 @@ private function guessSvnVersion(array $packageConfig, string $path): ?array return null; } + + public function getRootVersionFromEnv(): string + { + $version = Platform::getEnv('COMPOSER_ROOT_VERSION'); + if (!is_string($version) || $version === '') { + throw new \RuntimeException('COMPOSER_ROOT_VERSION not set or empty'); + } + if (Preg::isMatch('{^(\d+(?:\.\d+)*)-dev$}i', $version, $match)) { + $version = $match[1].'.x-dev'; + } + + return $version; + } } diff --git a/app/vendor/composer/composer/src/Composer/Package/Version/VersionSelector.php b/app/vendor/composer/composer/src/Composer/Package/Version/VersionSelector.php index 9ab322084..7c0c61a31 100644 --- a/app/vendor/composer/composer/src/Composer/Package/Version/VersionSelector.php +++ b/app/vendor/composer/composer/src/Composer/Package/Version/VersionSelector.php @@ -71,7 +71,7 @@ public function __construct(RepositorySet $repositorySet, ?PlatformRepository $p */ public function findBestCandidate(string $packageName, ?string $targetPackageVersion = null, string $preferredStability = 'stable', $platformRequirementFilter = null, int $repoSetFlags = 0, ?IOInterface $io = null, $showWarnings = true) { - if (!isset(BasePackage::$stabilities[$preferredStability])) { + if (!isset(BasePackage::STABILITIES[$preferredStability])) { // If you get this, maybe you are still relying on the Composer 1.x signature where the 3rd arg was the php version throw new \UnexpectedValueException('Expected a valid stability name as 3rd argument, got '.$preferredStability); } @@ -86,7 +86,7 @@ public function findBestCandidate(string $packageName, ?string $targetPackageVer $constraint = $targetPackageVersion ? $this->getParser()->parseConstraints($targetPackageVersion) : null; $candidates = $this->repositorySet->findPackages(strtolower($packageName), $constraint, $repoSetFlags); - $minPriority = BasePackage::$stabilities[$preferredStability]; + $minPriority = BasePackage::STABILITIES[$preferredStability]; usort($candidates, static function (PackageInterface $a, PackageInterface $b) use ($minPriority) { $aPriority = $a->getStabilityPriority(); $bPriority = $b->getStabilityPriority(); @@ -121,6 +121,7 @@ public function findBestCandidate(string $packageName, ?string $targetPackageVer foreach ($candidates as $pkg) { $reqs = $pkg->getRequires(); + $skip = false; foreach ($reqs as $name => $link) { if (!PlatformRepository::isPlatformPackage($name) || $platformRequirementFilter->isIgnored($name)) { continue; @@ -151,8 +152,8 @@ public function findBestCandidate(string $packageName, ?string $targetPackageVer $isLatestVersion = !isset($alreadySeenNames[$pkg->getName()]); $alreadySeenNames[$pkg->getName()] = true; if ($io !== null && ($showWarnings === true || (is_callable($showWarnings) && $showWarnings($pkg)))) { - $isFirstWarning = !isset($alreadyWarnedNames[$pkg->getName()]); - $alreadyWarnedNames[$pkg->getName()] = true; + $isFirstWarning = !isset($alreadyWarnedNames[$pkg->getName().'/'.$link->getTarget()]); + $alreadyWarnedNames[$pkg->getName().'/'.$link->getTarget()] = true; $latest = $isLatestVersion ? "'s latest version" : ''; $io->writeError( 'Cannot use '.$pkg->getPrettyName().$latest.' '.$pkg->getPrettyVersion().' as it '.$link->getDescription().' '.$link->getTarget().' '.$link->getPrettyConstraint().' which '.$reason.'.', @@ -162,7 +163,11 @@ public function findBestCandidate(string $packageName, ?string $targetPackageVer } // skip candidate - continue 2; + $skip = true; + } + + if ($skip) { + continue; } $package = $pkg; diff --git a/app/vendor/composer/composer/src/Composer/PartialComposer.php b/app/vendor/composer/composer/src/Composer/PartialComposer.php index c6f9c7523..f4b7910a8 100644 --- a/app/vendor/composer/composer/src/Composer/PartialComposer.php +++ b/app/vendor/composer/composer/src/Composer/PartialComposer.php @@ -23,6 +23,11 @@ */ class PartialComposer { + /** + * @var bool + */ + private $global = false; + /** * @var RootPackageInterface */ @@ -112,4 +117,14 @@ public function getEventDispatcher(): EventDispatcher { return $this->eventDispatcher; } + + public function isGlobal(): bool + { + return $this->global; + } + + public function setGlobal(): void + { + $this->global = true; + } } diff --git a/app/vendor/composer/composer/src/Composer/Platform/HhvmDetector.php b/app/vendor/composer/composer/src/Composer/Platform/HhvmDetector.php index 46886c353..284b0ba8a 100644 --- a/app/vendor/composer/composer/src/Composer/Platform/HhvmDetector.php +++ b/app/vendor/composer/composer/src/Composer/Platform/HhvmDetector.php @@ -49,11 +49,7 @@ public function getVersion(): ?string $hhvmPath = $this->executableFinder->find('hhvm'); if ($hhvmPath !== null) { $this->processExecutor = $this->processExecutor ?? new ProcessExecutor(); - $exitCode = $this->processExecutor->execute( - ProcessExecutor::escape($hhvmPath). - ' --php -d hhvm.jit=0 -r "echo HHVM_VERSION;" 2>/dev/null', - self::$hhvmVersion - ); + $exitCode = $this->processExecutor->execute([$hhvmPath, '--php', '-d', 'hhvm.jit=0', '-r', 'echo HHVM_VERSION;'], self::$hhvmVersion); if ($exitCode !== 0) { self::$hhvmVersion = false; } diff --git a/app/vendor/composer/composer/src/Composer/Platform/Runtime.php b/app/vendor/composer/composer/src/Composer/Platform/Runtime.php index b05af085c..940c02d0f 100644 --- a/app/vendor/composer/composer/src/Composer/Platform/Runtime.php +++ b/app/vendor/composer/composer/src/Composer/Platform/Runtime.php @@ -56,9 +56,12 @@ public function hasClass(string $class): bool } /** - * @param class-string $class + * @template T of object * @param mixed[] $arguments * + * @phpstan-param class-string $class + * @phpstan-return T + * * @throws \ReflectionException */ public function construct(string $class, array $arguments = []): object diff --git a/app/vendor/composer/composer/src/Composer/Plugin/PluginManager.php b/app/vendor/composer/composer/src/Composer/Plugin/PluginManager.php index f594478a6..8a6fad2cb 100644 --- a/app/vendor/composer/composer/src/Composer/Plugin/PluginManager.php +++ b/app/vendor/composer/composer/src/Composer/Plugin/PluginManager.php @@ -20,11 +20,13 @@ use Composer\Package\CompletePackage; use Composer\Package\Locker; use Composer\Package\Package; +use Composer\Package\RootPackageInterface; use Composer\Package\Version\VersionParser; use Composer\PartialComposer; use Composer\Pcre\Preg; use Composer\Repository\RepositoryInterface; use Composer\Repository\InstalledRepository; +use Composer\Repository\RepositoryUtils; use Composer\Repository\RootPackageRepository; use Composer\Package\PackageInterface; use Composer\Package\Link; @@ -53,7 +55,7 @@ class PluginManager /** @var array */ protected $plugins = []; - /** @var array */ + /** @var array> */ protected $registeredPlugins = []; /** @@ -98,7 +100,7 @@ public function loadInstalledPlugins(): void { if (!$this->arePluginsDisabled('local')) { $repo = $this->composer->getRepositoryManager()->getLocalRepository(); - $this->loadRepository($repo, false); + $this->loadRepository($repo, false, $this->composer->getPackage()); } if ($this->globalComposer !== null && !$this->arePluginsDisabled('global')) { @@ -287,14 +289,14 @@ public function registerPackage(PackageInterface $package, bool $failOnMissingCl $this->io->writeError('Loading "'.$package->getName() . '" '.($isGlobalPlugin || $this->runningInGlobalDir ? '(installed globally) ' : '').'which is a legacy composer-installer built for Composer 1.x, it is likely to cause issues as you are running Composer 2.x.'); $installer = new $class($this->io, $this->composer); $this->composer->getInstallationManager()->addInstaller($installer); - $this->registeredPlugins[$package->getName()] = $installer; + $this->registeredPlugins[$package->getName()][] = $installer; } elseif (class_exists($class)) { if (!is_a($class, 'Composer\Plugin\PluginInterface', true)) { throw new \RuntimeException('Could not activate plugin "'.$package->getName().'" as "'.$class.'" does not implement Composer\Plugin\PluginInterface'); } $plugin = new $class(); $this->addPlugin($plugin, $isGlobalPlugin, $package); - $this->registeredPlugins[$package->getName()] = $plugin; + $this->registeredPlugins[$package->getName()][] = $plugin; } elseif ($failOnMissingClasses) { throw new \UnexpectedValueException('Plugin '.$package->getName().' could not be initialized, class not found: '.$class); } @@ -315,13 +317,15 @@ public function deactivatePackage(PackageInterface $package): void return; } - $plugin = $this->registeredPlugins[$package->getName()]; - unset($this->registeredPlugins[$package->getName()]); - if ($plugin instanceof InstallerInterface) { - $this->composer->getInstallationManager()->removeInstaller($plugin); - } else { - $this->removePlugin($plugin); + $plugins = $this->registeredPlugins[$package->getName()]; + foreach ($plugins as $plugin) { + if ($plugin instanceof InstallerInterface) { + $this->composer->getInstallationManager()->removeInstaller($plugin); + } else { + $this->removePlugin($plugin); + } } + unset($this->registeredPlugins[$package->getName()]); } /** @@ -338,14 +342,16 @@ public function uninstallPackage(PackageInterface $package): void return; } - $plugin = $this->registeredPlugins[$package->getName()]; - if ($plugin instanceof InstallerInterface) { - $this->deactivatePackage($package); - } else { - unset($this->registeredPlugins[$package->getName()]); - $this->removePlugin($plugin); - $this->uninstallPlugin($plugin); + $plugins = $this->registeredPlugins[$package->getName()]; + foreach ($plugins as $plugin) { + if ($plugin instanceof InstallerInterface) { + $this->composer->getInstallationManager()->removeInstaller($plugin); + } else { + $this->removePlugin($plugin); + $this->uninstallPlugin($plugin); + } } + unset($this->registeredPlugins[$package->getName()]); } /** @@ -445,9 +451,11 @@ public function uninstallPlugin(PluginInterface $plugin): void * * @param RepositoryInterface $repo Repository to scan for plugins to install * + * @phpstan-param ($isGlobalRepo is true ? null : RootPackageInterface) $rootPackage + * * @throws \RuntimeException */ - private function loadRepository(RepositoryInterface $repo, bool $isGlobalRepo): void + private function loadRepository(RepositoryInterface $repo, bool $isGlobalRepo, ?RootPackageInterface $rootPackage = null): void { $packages = $repo->getPackages(); @@ -462,10 +470,28 @@ private function loadRepository(RepositoryInterface $repo, bool $isGlobalRepo): } $sortedPackages = PackageSorter::sortPackages($packages, $weights); + if (!$isGlobalRepo) { + $requiredPackages = RepositoryUtils::filterRequiredPackages($packages, $rootPackage, true); + } + foreach ($sortedPackages as $package) { if (!($package instanceof CompletePackage)) { continue; } + + if (!in_array($package->getType(), ['composer-plugin', 'composer-installer'], true)) { + continue; + } + + if ( + !$isGlobalRepo + && !in_array($package, $requiredPackages, true) + && !$this->isPluginAllowed($package->getName(), false, true, false) + ) { + $this->io->writeError('The "'.$package->getName().'" plugin was not loaded as it is not listed in allow-plugins and is not required by the root package anymore.'); + continue; + } + if ('composer-plugin' === $package->getType()) { $this->registerPackage($package, false, $isGlobalRepo); // Backward compatibility @@ -668,7 +694,7 @@ public function disablePlugins(): void /** * @internal */ - public function isPluginAllowed(string $package, bool $isGlobalPlugin, bool $optional = false): bool + public function isPluginAllowed(string $package, bool $isGlobalPlugin, bool $optional = false, bool $prompt = true): bool { if ($isGlobalPlugin) { $rules = &$this->allowGlobalPluginRules; @@ -703,7 +729,7 @@ public function isPluginAllowed(string $package, bool $isGlobalPlugin, bool $opt return false; } - if ($this->io->isInteractive()) { + if ($this->io->isInteractive() && $prompt) { $composer = $isGlobalPlugin && $this->globalComposer !== null ? $this->globalComposer : $this->composer; $this->io->writeError(''.$package.($isGlobalPlugin || $this->runningInGlobalDir ? ' (installed globally)' : '').' contains a Composer plugin which is currently not in your allow-plugins config. See https://getcomposer.org/allow-plugins'); @@ -728,7 +754,15 @@ public function isPluginAllowed(string $package, bool $isGlobalPlugin, bool $opt // persist answer in composer.json if it wasn't simply discarded if ($answer === 'y' || $answer === 'n') { - $composer->getConfig()->getConfigSource()->addConfigSetting('allow-plugins.'.$package, $allow); + $allowPlugins = $composer->getConfig()->get('allow-plugins'); + if (is_array($allowPlugins)) { + $allowPlugins[$package] = $allow; + if ($composer->getConfig()->get('sort-packages')) { + ksort($allowPlugins); + } + $composer->getConfig()->getConfigSource()->addConfigSetting('allow-plugins', $allowPlugins); + $composer->getConfig()->merge(['config' => ['allow-plugins' => $allowPlugins]]); + } } return $allow; diff --git a/app/vendor/composer/composer/src/Composer/Plugin/PostFileDownloadEvent.php b/app/vendor/composer/composer/src/Composer/Plugin/PostFileDownloadEvent.php index e78991646..a8d9a025f 100644 --- a/app/vendor/composer/composer/src/Composer/Plugin/PostFileDownloadEvent.php +++ b/app/vendor/composer/composer/src/Composer/Plugin/PostFileDownloadEvent.php @@ -59,7 +59,7 @@ class PostFileDownloadEvent extends Event */ public function __construct(string $name, ?string $fileName, ?string $checksum, string $url, string $type, $context = null) { - /** @phpstan-ignore-next-line */ + /** @phpstan-ignore instanceof.alwaysFalse, booleanAnd.alwaysFalse */ if ($context === null && $type instanceof PackageInterface) { $context = $type; $type = 'package'; diff --git a/app/vendor/composer/composer/src/Composer/Question/StrictConfirmationQuestion.php b/app/vendor/composer/composer/src/Composer/Question/StrictConfirmationQuestion.php index c27753b32..9cbc74ec5 100644 --- a/app/vendor/composer/composer/src/Composer/Question/StrictConfirmationQuestion.php +++ b/app/vendor/composer/composer/src/Composer/Question/StrictConfirmationQuestion.php @@ -40,7 +40,7 @@ class StrictConfirmationQuestion extends Question */ public function __construct(string $question, bool $default = true, string $trueAnswerRegex = '/^y(?:es)?$/i', string $falseAnswerRegex = '/^no?$/i') { - parent::__construct($question, (bool) $default); + parent::__construct($question, $default); $this->trueAnswerRegex = $trueAnswerRegex; $this->falseAnswerRegex = $falseAnswerRegex; diff --git a/app/vendor/composer/composer/src/Composer/Repository/ArtifactRepository.php b/app/vendor/composer/composer/src/Composer/Repository/ArtifactRepository.php index f73f4e9e1..78176fad7 100644 --- a/app/vendor/composer/composer/src/Composer/Repository/ArtifactRepository.php +++ b/app/vendor/composer/composer/src/Composer/Repository/ArtifactRepository.php @@ -129,7 +129,7 @@ private function getComposerInformation(\SplFileInfo $file): ?BasePackage $package['dist'] = [ 'type' => $fileType, 'url' => strtr($file->getPathname(), '\\', '/'), - 'shasum' => sha1_file($file->getRealPath()), + 'shasum' => hash_file('sha1', $file->getRealPath()), ]; try { diff --git a/app/vendor/composer/composer/src/Composer/Repository/ComposerRepository.php b/app/vendor/composer/composer/src/Composer/Repository/ComposerRepository.php index ec244b129..7e4172b5a 100644 --- a/app/vendor/composer/composer/src/Composer/Repository/ComposerRepository.php +++ b/app/vendor/composer/composer/src/Composer/Repository/ComposerRepository.php @@ -432,8 +432,7 @@ private function getVendorNames(): array $uniques = []; foreach ($names as $name) { - // @phpstan-ignore-next-line - $uniques[substr($name, 0, strpos($name, '/'))] = true; + $uniques[explode('/', $name, 2)[0]] = true; } $vendors = array_keys($uniques); @@ -828,7 +827,7 @@ private function hasProviders(): bool /** * @param string $name package name * @param array|null $acceptableStabilities - * @phpstan-param array|null $acceptableStabilities + * @phpstan-param array, BasePackage::STABILITY_*>|null $acceptableStabilities * @param array|null $stabilityFlags an array of package name => BasePackage::STABILITY_* value * @phpstan-param array|null $stabilityFlags * @param array> $alreadyLoaded @@ -998,7 +997,7 @@ public function addPackage(PackageInterface $package) * @param array $packageNames array of package name => ConstraintInterface|null - if a constraint is provided, only * packages matching it will be loaded * @param array|null $acceptableStabilities - * @phpstan-param array|null $acceptableStabilities + * @phpstan-param array, BasePackage::STABILITY_*>|null $acceptableStabilities * @param array|null $stabilityFlags an array of package name => BasePackage::STABILITY_* value * @phpstan-param array|null $stabilityFlags * @param array> $alreadyLoaded @@ -1130,7 +1129,7 @@ private function startCachedAsyncDownload(string $fileName, ?string $packageName * @param string $name package name (must be lowercased already) * @param array $versionData * @param array|null $acceptableStabilities - * @phpstan-param array|null $acceptableStabilities + * @phpstan-param array, BasePackage::STABILITY_*>|null $acceptableStabilities * @param array|null $stabilityFlags an array of package name => BasePackage::STABILITY_* value * @phpstan-param array|null $stabilityFlags */ @@ -1448,7 +1447,7 @@ private function createPackages(array $packages, ?string $source = null): array return $packageInstances; } catch (\Exception $e) { - throw new \RuntimeException('Could not load packages '.($packages[0]['name'] ?? json_encode($packages)).' in '.$this->getRepoName().($source ? ' from '.$source : '').': ['.get_class($e).'] '.$e->getMessage(), 0, $e); + throw new \RuntimeException('Could not load packages in '.$this->getRepoName().($source ? ' from '.$source : '').': ['.get_class($e).'] '.$e->getMessage(), 0, $e); } } diff --git a/app/vendor/composer/composer/src/Composer/Repository/FilesystemRepository.php b/app/vendor/composer/composer/src/Composer/Repository/FilesystemRepository.php index ec37573f2..6ae6b149f 100644 --- a/app/vendor/composer/composer/src/Composer/Repository/FilesystemRepository.php +++ b/app/vendor/composer/composer/src/Composer/Repository/FilesystemRepository.php @@ -169,7 +169,26 @@ public function write(bool $devMode, InstallationManager $installationManager) if ($installedVersionsClass !== false) { $this->filesystem->filePutContentsIfModified($repoDir.'/InstalledVersions.php', $installedVersionsClass); + // make sure the in memory state is up to date with on disk \Composer\InstalledVersions::reload($versions); + + // make sure the selfDir matches the expected data at runtime if the class was loaded from the vendor dir, as it may have been + // loaded from the Composer sources, causing packages to appear twice in that case if the installed.php is loaded in addition to the + // in memory loaded data from above + try { + $reflProp = new \ReflectionProperty(\Composer\InstalledVersions::class, 'selfDir'); + $reflProp->setAccessible(true); + $reflProp->setValue(null, strtr($repoDir, '\\', '/')); + + $reflProp = new \ReflectionProperty(\Composer\InstalledVersions::class, 'installedIsLocalDir'); + $reflProp->setAccessible(true); + $reflProp->setValue(null, true); + } catch (\ReflectionException $e) { + if (!Preg::isMatch('{Property .*? does not exist}i', $e->getMessage())) { + throw $e; + } + // noop, if outdated class is loaded we do not want to cause trouble + } } } } @@ -329,6 +348,14 @@ private function generateInstalledVersions(InstallationManager $installationMana ksort($versions['versions']); ksort($versions); + foreach ($versions['versions'] as $name => $version) { + foreach (['aliases', 'replaced', 'provided'] as $key) { + if (isset($versions['versions'][$name][$key])) { + sort($versions['versions'][$name][$key], SORT_NATURAL); + } + } + } + return $versions; } diff --git a/app/vendor/composer/composer/src/Composer/Repository/InstalledRepository.php b/app/vendor/composer/composer/src/Composer/Repository/InstalledRepository.php index e3b52079e..3520fdec6 100644 --- a/app/vendor/composer/composer/src/Composer/Repository/InstalledRepository.php +++ b/app/vendor/composer/composer/src/Composer/Repository/InstalledRepository.php @@ -84,7 +84,7 @@ public function findPackagesWithReplacersAndProviders(string $name, $constraint * @param string[] $packagesFound Used internally when recurring * * @return array[] An associative array of arrays as described above. - * @phpstan-return array + * @phpstan-return array|false}> */ public function getDependents($needle, ?ConstraintInterface $constraint = null, bool $invert = false, bool $recurse = true, ?array $packagesFound = null): array { @@ -137,6 +137,7 @@ public function getDependents($needle, ?ConstraintInterface $constraint = null, } } } + unset($needle); } // Require-dev is only relevant for the root package @@ -163,7 +164,7 @@ public function getDependents($needle, ?ConstraintInterface $constraint = null, } // When inverting, we need to check for conflicts of the needles against installed packages - if ($invert && in_array($package->getName(), $needles)) { + if ($invert && in_array($package->getName(), $needles, true)) { foreach ($package->getConflicts() as $link) { foreach ($this->findPackages($link->getTarget()) as $pkg) { $version = new Constraint('=', $pkg->getVersion()); @@ -176,7 +177,7 @@ public function getDependents($needle, ?ConstraintInterface $constraint = null, // List conflicts against X as they may explain why the current version was selected, or explain why it is rejected if the conflict matched when inverting foreach ($package->getConflicts() as $link) { - if (in_array($link->getTarget(), $needles)) { + if (in_array($link->getTarget(), $needles, true)) { foreach ($this->findPackages($link->getTarget()) as $pkg) { $version = new Constraint('=', $pkg->getVersion()); if ($link->getConstraint()->matches($version) === $invert) { @@ -187,7 +188,7 @@ public function getDependents($needle, ?ConstraintInterface $constraint = null, } // When inverting, we need to check for conflicts of the needles' requirements against installed packages - if ($invert && $constraint && in_array($package->getName(), $needles) && $constraint->matches(new Constraint('=', $package->getVersion()))) { + if ($invert && $constraint && in_array($package->getName(), $needles, true) && $constraint->matches(new Constraint('=', $package->getVersion()))) { foreach ($package->getRequires() as $link) { if (PlatformRepository::isPlatformPackage($link->getTarget())) { if ($this->findPackage($link->getTarget(), $link->getConstraint())) { diff --git a/app/vendor/composer/composer/src/Composer/Repository/PathRepository.php b/app/vendor/composer/composer/src/Composer/Repository/PathRepository.php index 06676e73e..0b8d99236 100644 --- a/app/vendor/composer/composer/src/Composer/Repository/PathRepository.php +++ b/app/vendor/composer/composer/src/Composer/Repository/PathRepository.php @@ -116,7 +116,7 @@ public function __construct(array $repoConfig, IOInterface $io, Config $config, $this->loader = new ArrayLoader(null, true); $this->url = Platform::expandPath($repoConfig['url']); $this->process = $process ?? new ProcessExecutor($io); - $this->versionGuesser = new VersionGuesser($config, $this->process, new VersionParser()); + $this->versionGuesser = new VersionGuesser($config, $this->process, new VersionParser(), $io); $this->repoConfig = $repoConfig; $this->options = $repoConfig['options'] ?? []; if (!isset($this->options['relative'])) { @@ -181,7 +181,7 @@ protected function initialize(): void if ('none' === $reference) { $package['dist']['reference'] = null; } elseif ('config' === $reference || 'auto' === $reference) { - $package['dist']['reference'] = sha1($json . serialize($this->options)); + $package['dist']['reference'] = hash('sha1', $json . serialize($this->options)); } // copy symlink/relative options to transport options @@ -194,16 +194,16 @@ protected function initialize(): void // carry over the root package version if this path repo is in the same git repository as root package if (!isset($package['version']) && ($rootVersion = Platform::getEnv('COMPOSER_ROOT_VERSION'))) { if ( - 0 === $this->process->execute('git rev-parse HEAD', $ref1, $path) - && 0 === $this->process->execute('git rev-parse HEAD', $ref2) + 0 === $this->process->execute(['git', 'rev-parse', 'HEAD'], $ref1, $path) + && 0 === $this->process->execute(['git', 'rev-parse', 'HEAD'], $ref2) && $ref1 === $ref2 ) { - $package['version'] = $rootVersion; + $package['version'] = $this->versionGuesser->getRootVersionFromEnv(); } } $output = ''; - if ('auto' === $reference && is_dir($path . DIRECTORY_SEPARATOR . '.git') && 0 === $this->process->execute('git log -n1 --pretty=%H'.GitUtil::getNoShowSignatureFlag($this->process), $output, $path)) { + if ('auto' === $reference && is_dir($path . DIRECTORY_SEPARATOR . '.git') && 0 === $this->process->execute(array_merge(['git', 'log', '-n1', '--pretty=%H'], GitUtil::getNoShowSignatureFlags($this->process)), $output, $path)) { $package['dist']['reference'] = trim($output); } diff --git a/app/vendor/composer/composer/src/Composer/Repository/PlatformRepository.php b/app/vendor/composer/composer/src/Composer/Repository/PlatformRepository.php index 61c70cf32..4c6024946 100644 --- a/app/vendor/composer/composer/src/Composer/Repository/PlatformRepository.php +++ b/app/vendor/composer/composer/src/Composer/Repository/PlatformRepository.php @@ -110,6 +110,8 @@ protected function initialize(): void { parent::initialize(); + $libraries = []; + $this->versionParser = new VersionParser(); // Add each of the override versions as options. @@ -207,12 +209,12 @@ protected function initialize(): void // librabbitmq version => 0.9.0 if (Preg::isMatch('/^librabbitmq version => (?.+)$/im', $info, $librabbitmqMatches)) { - $this->addLibrary($name.'-librabbitmq', $librabbitmqMatches['version'], 'AMQP librabbitmq version'); + $this->addLibrary($libraries, $name.'-librabbitmq', $librabbitmqMatches['version'], 'AMQP librabbitmq version'); } // AMQP protocol version => 0-9-1 if (Preg::isMatchStrictGroups('/^AMQP protocol version => (?.+)$/im', $info, $protocolMatches)) { - $this->addLibrary($name.'-protocol', str_replace('-', '.', $protocolMatches['version']), 'AMQP protocol version'); + $this->addLibrary($libraries, $name.'-protocol', str_replace('-', '.', $protocolMatches['version']), 'AMQP protocol version'); } break; @@ -221,13 +223,13 @@ protected function initialize(): void // BZip2 Version => 1.0.6, 6-Sept-2010 if (Preg::isMatch('/^BZip2 Version => (?.*),/im', $info, $matches)) { - $this->addLibrary($name, $matches['version']); + $this->addLibrary($libraries, $name, $matches['version']); } break; case 'curl': $curlVersion = $this->runtime->invoke('curl_version'); - $this->addLibrary($name, $curlVersion['version']); + $this->addLibrary($libraries, $name, $curlVersion['version']); $info = $this->runtime->getExtensionInfo($name); @@ -236,25 +238,25 @@ protected function initialize(): void $library = strtolower($sslMatches['library']); if ($library === 'openssl') { $parsedVersion = Version::parseOpenssl($sslMatches['version'], $isFips); - $this->addLibrary($name.'-openssl'.($isFips ? '-fips' : ''), $parsedVersion, 'curl OpenSSL version ('.$parsedVersion.')', [], $isFips ? ['curl-openssl'] : []); + $this->addLibrary($libraries, $name.'-openssl'.($isFips ? '-fips' : ''), $parsedVersion, 'curl OpenSSL version ('.$parsedVersion.')', [], $isFips ? ['curl-openssl'] : []); } else { if ($library === '(securetransport) openssl') { $shortlib = 'securetransport'; } else { $shortlib = $library; } - $this->addLibrary($name.'-'.$shortlib, $sslMatches['version'], 'curl '.$library.' version ('.$sslMatches['version'].')', ['curl-openssl']); + $this->addLibrary($libraries, $name.'-'.$shortlib, $sslMatches['version'], 'curl '.$library.' version ('.$sslMatches['version'].')', ['curl-openssl']); } } // libSSH Version => libssh2/1.4.3 if (Preg::isMatchStrictGroups('{^libSSH Version => (?[^/]+)/(?.+?)(?:/.*)?$}im', $info, $sshMatches)) { - $this->addLibrary($name.'-'.strtolower($sshMatches['library']), $sshMatches['version'], 'curl '.$sshMatches['library'].' version'); + $this->addLibrary($libraries, $name.'-'.strtolower($sshMatches['library']), $sshMatches['version'], 'curl '.$sshMatches['library'].' version'); } // ZLib Version => 1.2.8 if (Preg::isMatchStrictGroups('{^ZLib Version => (?.+)$}im', $info, $zlibMatches)) { - $this->addLibrary($name.'-zlib', $zlibMatches['version'], 'curl zlib version'); + $this->addLibrary($libraries, $name.'-zlib', $zlibMatches['version'], 'curl zlib version'); } break; @@ -263,7 +265,7 @@ protected function initialize(): void // timelib version => 2018.03 if (Preg::isMatchStrictGroups('/^timelib version => (?.+)$/im', $info, $timelibMatches)) { - $this->addLibrary($name.'-timelib', $timelibMatches['version'], 'date timelib version'); + $this->addLibrary($libraries, $name.'-timelib', $timelibMatches['version'], 'date timelib version'); } // Timezone Database => internal @@ -272,9 +274,9 @@ protected function initialize(): void if (Preg::isMatchStrictGroups('/^"Olson" Timezone Database Version => (?.+?)(?:\.system)?$/im', $info, $zoneinfoMatches)) { // If the timezonedb is provided by ext/timezonedb, register that version as a replacement if ($external && in_array('timezonedb', $loadedExtensions, true)) { - $this->addLibrary('timezonedb-zoneinfo', $zoneinfoMatches['version'], 'zoneinfo ("Olson") database for date (replaced by timezonedb)', [$name.'-zoneinfo']); + $this->addLibrary($libraries, 'timezonedb-zoneinfo', $zoneinfoMatches['version'], 'zoneinfo ("Olson") database for date (replaced by timezonedb)', [$name.'-zoneinfo']); } else { - $this->addLibrary($name.'-zoneinfo', $zoneinfoMatches['version'], 'zoneinfo ("Olson") database for date'); + $this->addLibrary($libraries, $name.'-zoneinfo', $zoneinfoMatches['version'], 'zoneinfo ("Olson") database for date'); } } } @@ -285,39 +287,39 @@ protected function initialize(): void // libmagic => 537 if (Preg::isMatch('/^libmagic => (?.+)$/im', $info, $magicMatches)) { - $this->addLibrary($name.'-libmagic', $magicMatches['version'], 'fileinfo libmagic version'); + $this->addLibrary($libraries, $name.'-libmagic', $magicMatches['version'], 'fileinfo libmagic version'); } break; case 'gd': - $this->addLibrary($name, $this->runtime->getConstant('GD_VERSION')); + $this->addLibrary($libraries, $name, $this->runtime->getConstant('GD_VERSION')); $info = $this->runtime->getExtensionInfo($name); if (Preg::isMatchStrictGroups('/^libJPEG Version => (?.+?)(?: compatible)?$/im', $info, $libjpegMatches)) { - $this->addLibrary($name.'-libjpeg', Version::parseLibjpeg($libjpegMatches['version']), 'libjpeg version for gd'); + $this->addLibrary($libraries, $name.'-libjpeg', Version::parseLibjpeg($libjpegMatches['version']), 'libjpeg version for gd'); } if (Preg::isMatchStrictGroups('/^libPNG Version => (?.+)$/im', $info, $libpngMatches)) { - $this->addLibrary($name.'-libpng', $libpngMatches['version'], 'libpng version for gd'); + $this->addLibrary($libraries, $name.'-libpng', $libpngMatches['version'], 'libpng version for gd'); } if (Preg::isMatchStrictGroups('/^FreeType Version => (?.+)$/im', $info, $freetypeMatches)) { - $this->addLibrary($name.'-freetype', $freetypeMatches['version'], 'freetype version for gd'); + $this->addLibrary($libraries, $name.'-freetype', $freetypeMatches['version'], 'freetype version for gd'); } if (Preg::isMatchStrictGroups('/^libXpm Version => (?\d+)$/im', $info, $libxpmMatches)) { - $this->addLibrary($name.'-libxpm', Version::convertLibxpmVersionId((int) $libxpmMatches['versionId']), 'libxpm version for gd'); + $this->addLibrary($libraries, $name.'-libxpm', Version::convertLibxpmVersionId((int) $libxpmMatches['versionId']), 'libxpm version for gd'); } break; case 'gmp': - $this->addLibrary($name, $this->runtime->getConstant('GMP_VERSION')); + $this->addLibrary($libraries, $name, $this->runtime->getConstant('GMP_VERSION')); break; case 'iconv': - $this->addLibrary($name, $this->runtime->getConstant('ICONV_VERSION')); + $this->addLibrary($libraries, $name, $this->runtime->getConstant('ICONV_VERSION')); break; case 'intl': @@ -326,47 +328,49 @@ protected function initialize(): void $description = 'The ICU unicode and globalization support library'; // Truthy check is for testing only so we can make the condition fail if ($this->runtime->hasConstant('INTL_ICU_VERSION')) { - $this->addLibrary('icu', $this->runtime->getConstant('INTL_ICU_VERSION'), $description); + $this->addLibrary($libraries, 'icu', $this->runtime->getConstant('INTL_ICU_VERSION'), $description); } elseif (Preg::isMatch('/^ICU version => (?.+)$/im', $info, $matches)) { - $this->addLibrary('icu', $matches['version'], $description); + $this->addLibrary($libraries, 'icu', $matches['version'], $description); } // ICU TZData version => 2019c if (Preg::isMatchStrictGroups('/^ICU TZData version => (?.*)$/im', $info, $zoneinfoMatches) && null !== ($version = Version::parseZoneinfoVersion($zoneinfoMatches['version']))) { - $this->addLibrary('icu-zoneinfo', $version, 'zoneinfo ("Olson") database for icu'); + $this->addLibrary($libraries, 'icu-zoneinfo', $version, 'zoneinfo ("Olson") database for icu'); } // Add a separate version for the CLDR library version if ($this->runtime->hasClass('ResourceBundle')) { $resourceBundle = $this->runtime->invoke(['ResourceBundle', 'create'], ['root', 'ICUDATA', false]); if ($resourceBundle !== null) { - $this->addLibrary('icu-cldr', $resourceBundle->get('Version'), 'ICU CLDR project version'); + $this->addLibrary($libraries, 'icu-cldr', $resourceBundle->get('Version'), 'ICU CLDR project version'); } } if ($this->runtime->hasClass('IntlChar')) { - $this->addLibrary('icu-unicode', implode('.', array_slice($this->runtime->invoke(['IntlChar', 'getUnicodeVersion']), 0, 3)), 'ICU unicode version'); + $this->addLibrary($libraries, 'icu-unicode', implode('.', array_slice($this->runtime->invoke(['IntlChar', 'getUnicodeVersion']), 0, 3)), 'ICU unicode version'); } break; case 'imagick': + // @phpstan-ignore staticMethod.dynamicCall (called like this for mockability) $imageMagickVersion = $this->runtime->construct('Imagick')->getVersion(); // 6.x: ImageMagick 6.2.9 08/24/06 Q16 http://www.imagemagick.org // 7.x: ImageMagick 7.0.8-34 Q16 x86_64 2019-03-23 https://imagemagick.org - Preg::match('/^ImageMagick (?[\d.]+)(?:-(?\d+))?/', $imageMagickVersion['versionString'], $matches); - $version = $matches['version']; - if (isset($matches['patch'])) { - $version .= '.'.$matches['patch']; - } + if (Preg::isMatch('/^ImageMagick (?[\d.]+)(?:-(?\d+))?/', $imageMagickVersion['versionString'], $matches)) { + $version = $matches['version']; + if (isset($matches['patch'])) { + $version .= '.'.$matches['patch']; + } - $this->addLibrary($name.'-imagemagick', $version, null, ['imagick']); + $this->addLibrary($libraries, $name.'-imagemagick', $version, null, ['imagick']); + } break; case 'ldap': $info = $this->runtime->getExtensionInfo($name); if (Preg::isMatchStrictGroups('/^Vendor Version => (?\d+)$/im', $info, $matches) && Preg::isMatchStrictGroups('/^Vendor Name => (?.+)$/im', $info, $vendorMatches)) { - $this->addLibrary($name.'-'.strtolower($vendorMatches['vendor']), Version::convertOpenldapVersionId((int) $matches['versionId']), $vendorMatches['vendor'].' version of ldap'); + $this->addLibrary($libraries, $name.'-'.strtolower($vendorMatches['vendor']), Version::convertOpenldapVersionId((int) $matches['versionId']), $vendorMatches['vendor'].' version of ldap'); } break; @@ -375,7 +379,7 @@ protected function initialize(): void $libxmlProvides = array_map(static function ($extension): string { return $extension . '-libxml'; }, array_intersect($loadedExtensions, ['dom', 'simplexml', 'xml', 'xmlreader', 'xmlwriter'])); - $this->addLibrary($name, $this->runtime->getConstant('LIBXML_DOTTED_VERSION'), 'libxml library version', [], $libxmlProvides); + $this->addLibrary($libraries, $name, $this->runtime->getConstant('LIBXML_DOTTED_VERSION'), 'libxml library version', [], $libxmlProvides); break; @@ -384,16 +388,16 @@ protected function initialize(): void // libmbfl version => 1.3.2 if (Preg::isMatch('/^libmbfl version => (?.+)$/im', $info, $libmbflMatches)) { - $this->addLibrary($name.'-libmbfl', $libmbflMatches['version'], 'mbstring libmbfl version'); + $this->addLibrary($libraries, $name.'-libmbfl', $libmbflMatches['version'], 'mbstring libmbfl version'); } if ($this->runtime->hasConstant('MB_ONIGURUMA_VERSION')) { - $this->addLibrary($name.'-oniguruma', $this->runtime->getConstant('MB_ONIGURUMA_VERSION'), 'mbstring oniguruma version'); + $this->addLibrary($libraries, $name.'-oniguruma', $this->runtime->getConstant('MB_ONIGURUMA_VERSION'), 'mbstring oniguruma version'); // Multibyte regex (oniguruma) version => 5.9.5 // oniguruma version => 6.9.0 } elseif (Preg::isMatch('/^(?:oniguruma|Multibyte regex \(oniguruma\)) version => (?.+)$/im', $info, $onigurumaMatches)) { - $this->addLibrary($name.'-oniguruma', $onigurumaMatches['version'], 'mbstring oniguruma version'); + $this->addLibrary($libraries, $name.'-oniguruma', $onigurumaMatches['version'], 'mbstring oniguruma version'); } break; @@ -403,7 +407,7 @@ protected function initialize(): void // libmemcached version => 1.0.18 if (Preg::isMatch('/^libmemcached version => (?.+)$/im', $info, $matches)) { - $this->addLibrary($name.'-libmemcached', $matches['version'], 'libmemcached version'); + $this->addLibrary($libraries, $name.'-libmemcached', $matches['version'], 'libmemcached version'); } break; @@ -411,18 +415,18 @@ protected function initialize(): void // OpenSSL 1.1.1g 21 Apr 2020 if (Preg::isMatchStrictGroups('{^(?:OpenSSL|LibreSSL)?\s*(?\S+)}i', $this->runtime->getConstant('OPENSSL_VERSION_TEXT'), $matches)) { $parsedVersion = Version::parseOpenssl($matches['version'], $isFips); - $this->addLibrary($name.($isFips ? '-fips' : ''), $parsedVersion, $this->runtime->getConstant('OPENSSL_VERSION_TEXT'), [], $isFips ? [$name] : []); + $this->addLibrary($libraries, $name.($isFips ? '-fips' : ''), $parsedVersion, $this->runtime->getConstant('OPENSSL_VERSION_TEXT'), [], $isFips ? [$name] : []); } break; case 'pcre': - $this->addLibrary($name, Preg::replace('{^(\S+).*}', '$1', $this->runtime->getConstant('PCRE_VERSION'))); + $this->addLibrary($libraries, $name, Preg::replace('{^(\S+).*}', '$1', $this->runtime->getConstant('PCRE_VERSION'))); $info = $this->runtime->getExtensionInfo($name); // PCRE Unicode Version => 12.1.0 if (Preg::isMatchStrictGroups('/^PCRE Unicode Version => (?.+)$/im', $info, $pcreUnicodeMatches)) { - $this->addLibrary($name.'-unicode', $pcreUnicodeMatches['version'], 'PCRE Unicode version support'); + $this->addLibrary($libraries, $name.'-unicode', $pcreUnicodeMatches['version'], 'PCRE Unicode version support'); } break; @@ -432,7 +436,7 @@ protected function initialize(): void $info = $this->runtime->getExtensionInfo($name); if (Preg::isMatchStrictGroups('/^(?:Client API version|Version) => mysqlnd (?.+?) /mi', $info, $matches)) { - $this->addLibrary($name.'-mysqlnd', $matches['version'], 'mysqlnd library version for '.$name); + $this->addLibrary($libraries, $name.'-mysqlnd', $matches['version'], 'mysqlnd library version for '.$name); } break; @@ -440,17 +444,17 @@ protected function initialize(): void $info = $this->runtime->getExtensionInfo($name); if (Preg::isMatchStrictGroups('/^libmongoc bundled version => (?.+)$/im', $info, $libmongocMatches)) { - $this->addLibrary($name.'-libmongoc', $libmongocMatches['version'], 'libmongoc version of mongodb'); + $this->addLibrary($libraries, $name.'-libmongoc', $libmongocMatches['version'], 'libmongoc version of mongodb'); } if (Preg::isMatchStrictGroups('/^libbson bundled version => (?.+)$/im', $info, $libbsonMatches)) { - $this->addLibrary($name.'-libbson', $libbsonMatches['version'], 'libbson version of mongodb'); + $this->addLibrary($libraries, $name.'-libbson', $libbsonMatches['version'], 'libbson version of mongodb'); } break; case 'pgsql': if ($this->runtime->hasConstant('PGSQL_LIBPQ_VERSION')) { - $this->addLibrary('pgsql-libpq', $this->runtime->getConstant('PGSQL_LIBPQ_VERSION'), 'libpq for pgsql'); + $this->addLibrary($libraries, 'pgsql-libpq', $this->runtime->getConstant('PGSQL_LIBPQ_VERSION'), 'libpq for pgsql'); break; } // intentional fall-through to next case... @@ -459,7 +463,7 @@ protected function initialize(): void $info = $this->runtime->getExtensionInfo($name); if (Preg::isMatch('/^PostgreSQL\(libpq\) Version => (?.*)$/im', $info, $matches)) { - $this->addLibrary($name.'-libpq', $matches['version'], 'libpq for '.$name); + $this->addLibrary($libraries, $name.'-libpq', $matches['version'], 'libpq for '.$name); } break; @@ -469,7 +473,7 @@ protected function initialize(): void // Used Library => Compiled => Linked // libpq => 14.3 (Ubuntu 14.3-1.pgdg22.04+1) => 15.0.2 if (Preg::isMatch('/^libpq => (?.+) => (?.+)$/im', $info, $matches)) { - $this->addLibrary($name.'-libpq', $matches['linked'], 'libpq for '.$name); + $this->addLibrary($libraries, $name.'-libpq', $matches['linked'], 'libpq for '.$name); } break; @@ -485,14 +489,15 @@ protected function initialize(): void * pre-release ID in practice is always 0xff even for RCs etc, so we ignore it */ $libRdKafkaVersionInt = $this->runtime->getConstant('RD_KAFKA_VERSION'); - $this->addLibrary($name.'-librdkafka', sprintf('%d.%d.%d', ($libRdKafkaVersionInt & 0xFF000000) >> 24, ($libRdKafkaVersionInt & 0x00FF0000) >> 16, ($libRdKafkaVersionInt & 0x0000FF00) >> 8), 'librdkafka for '.$name); + $this->addLibrary($libraries, $name.'-librdkafka', sprintf('%d.%d.%d', ($libRdKafkaVersionInt & 0x7F000000) >> 24, ($libRdKafkaVersionInt & 0x00FF0000) >> 16, ($libRdKafkaVersionInt & 0x0000FF00) >> 8), 'librdkafka for '.$name); } break; case 'libsodium': case 'sodium': if ($this->runtime->hasConstant('SODIUM_LIBRARY_VERSION')) { - $this->addLibrary('libsodium', $this->runtime->getConstant('SODIUM_LIBRARY_VERSION')); + $this->addLibrary($libraries, 'libsodium', $this->runtime->getConstant('SODIUM_LIBRARY_VERSION')); + $this->addLibrary($libraries, 'libsodium', $this->runtime->getConstant('SODIUM_LIBRARY_VERSION')); } break; @@ -501,7 +506,7 @@ protected function initialize(): void $info = $this->runtime->getExtensionInfo($name); if (Preg::isMatch('/^SQLite Library => (?.+)$/im', $info, $matches)) { - $this->addLibrary($name.'-sqlite', $matches['version']); + $this->addLibrary($libraries, $name.'-sqlite', $matches['version']); } break; @@ -509,16 +514,16 @@ protected function initialize(): void $info = $this->runtime->getExtensionInfo($name); if (Preg::isMatch('/^libssh2 version => (?.+)$/im', $info, $matches)) { - $this->addLibrary($name.'-libssh2', $matches['version']); + $this->addLibrary($libraries, $name.'-libssh2', $matches['version']); } break; case 'xsl': - $this->addLibrary('libxslt', $this->runtime->getConstant('LIBXSLT_DOTTED_VERSION'), null, ['xsl']); + $this->addLibrary($libraries, 'libxslt', $this->runtime->getConstant('LIBXSLT_DOTTED_VERSION'), null, ['xsl']); $info = $this->runtime->getExtensionInfo('xsl'); if (Preg::isMatch('/^libxslt compiled against libxml Version => (?.+)$/im', $info, $matches)) { - $this->addLibrary('libxslt-libxml', $matches['version'], 'libxml version libxslt is compiled against'); + $this->addLibrary($libraries, 'libxslt-libxml', $matches['version'], 'libxml version libxslt is compiled against'); } break; @@ -526,23 +531,23 @@ protected function initialize(): void $info = $this->runtime->getExtensionInfo('yaml'); if (Preg::isMatch('/^LibYAML Version => (?.+)$/im', $info, $matches)) { - $this->addLibrary($name.'-libyaml', $matches['version'], 'libyaml version of yaml'); + $this->addLibrary($libraries, $name.'-libyaml', $matches['version'], 'libyaml version of yaml'); } break; case 'zip': if ($this->runtime->hasConstant('LIBZIP_VERSION', 'ZipArchive')) { - $this->addLibrary($name.'-libzip', $this->runtime->getConstant('LIBZIP_VERSION', 'ZipArchive'), null, ['zip']); + $this->addLibrary($libraries, $name.'-libzip', $this->runtime->getConstant('LIBZIP_VERSION', 'ZipArchive'), null, ['zip']); } break; case 'zlib': if ($this->runtime->hasConstant('ZLIB_VERSION')) { - $this->addLibrary($name, $this->runtime->getConstant('ZLIB_VERSION')); + $this->addLibrary($libraries, $name, $this->runtime->getConstant('ZLIB_VERSION')); // Linked Version => 1.2.8 } elseif (Preg::isMatch('/^Linked Version => (?.+)$/im', $this->runtime->getExtensionInfo($name), $matches)) { - $this->addLibrary($name, $matches['version']); + $this->addLibrary($libraries, $name, $matches['version']); } break; @@ -678,10 +683,11 @@ private function buildPackageName(string $name): string } /** - * @param string[] $replaces - * @param string[] $provides + * @param array $libraries + * @param array $replaces + * @param array $provides */ - private function addLibrary(string $name, ?string $prettyVersion, ?string $description = null, array $replaces = [], array $provides = []): void + private function addLibrary(array &$libraries, string $name, ?string $prettyVersion, ?string $description = null, array $replaces = [], array $provides = []): void { if (null === $prettyVersion) { return; @@ -692,6 +698,13 @@ private function addLibrary(string $name, ?string $prettyVersion, ?string $descr return; } + // avoid adding the same lib twice even if two conflicting extensions provide the same lib + // see https://github.com/composer/composer/issues/12082 + if (isset($libraries['lib-'.$name])) { + return; + } + $libraries['lib-'.$name] = true; + if ($description === null) { $description = 'The '.$name.' library'; } diff --git a/app/vendor/composer/composer/src/Composer/Repository/RepositoryFactory.php b/app/vendor/composer/composer/src/Composer/Repository/RepositoryFactory.php index 62e918324..52da0d604 100644 --- a/app/vendor/composer/composer/src/Composer/Repository/RepositoryFactory.php +++ b/app/vendor/composer/composer/src/Composer/Repository/RepositoryFactory.php @@ -178,7 +178,7 @@ private static function createRepos(RepositoryManager $rm, array $repoConfigs): /** * @param int|string $index * @param array{url?: string} $repo - * @param array $existingRepos + * @param array $existingRepos */ public static function generateRepositoryName($index, array $repo, array $existingRepos): string { diff --git a/app/vendor/composer/composer/src/Composer/Repository/RepositoryInterface.php b/app/vendor/composer/composer/src/Composer/Repository/RepositoryInterface.php index c26248801..f90c96d50 100644 --- a/app/vendor/composer/composer/src/Composer/Repository/RepositoryInterface.php +++ b/app/vendor/composer/composer/src/Composer/Repository/RepositoryInterface.php @@ -72,12 +72,13 @@ public function getPackages(); * - The namesFound returned are names which should be considered as canonically found in this repository, that should not be looked up in any further lower priority repositories * * @param ConstraintInterface[] $packageNameMap package names pointing to constraints - * @param array $acceptableStabilities array of stability => BasePackage::STABILITY_* value + * @param array $acceptableStabilities array of stability => BasePackage::STABILITY_* value * @param array $stabilityFlags an array of package name => BasePackage::STABILITY_* value * @param array> $alreadyLoaded an array of package name => package version => package * * @return array * + * @phpstan-param array, BasePackage::STABILITY_*> $acceptableStabilities * @phpstan-param array $packageNameMap * @phpstan-return array{namesFound: array, packages: array} */ @@ -103,7 +104,7 @@ public function search(string $query, int $mode = 0, ?string $type = null); * @param string $packageName package name which must be provided * * @return array[] an array with the provider name as key and value of array('name' => '...', 'description' => '...', 'type' => '...') - * @phpstan-return array + * @phpstan-return array */ public function getProviders(string $packageName); diff --git a/app/vendor/composer/composer/src/Composer/Repository/RepositorySet.php b/app/vendor/composer/composer/src/Composer/Repository/RepositorySet.php index f6e8c7802..dcde36327 100644 --- a/app/vendor/composer/composer/src/Composer/Repository/RepositorySet.php +++ b/app/vendor/composer/composer/src/Composer/Repository/RepositorySet.php @@ -65,7 +65,7 @@ class RepositorySet /** * @var int[] array of stability => BasePackage::STABILITY_* value - * @phpstan-var array + * @phpstan-var array, BasePackage::STABILITY_*> */ private $acceptableStabilities; @@ -96,6 +96,7 @@ class RepositorySet * passing minimumStability is all you need to worry about. The rest is for advanced pool creation including * aliases, pinned references and other special cases. * + * @param key-of $minimumStability * @param int[] $stabilityFlags an array of package name => BasePackage::STABILITY_* value * @phpstan-param array $stabilityFlags * @param array[] $rootAliases @@ -112,8 +113,8 @@ public function __construct(string $minimumStability = 'stable', array $stabilit $this->rootReferences = $rootReferences; $this->acceptableStabilities = []; - foreach (BasePackage::$stabilities as $stability => $value) { - if ($value <= BasePackage::$stabilities[$minimumStability]) { + foreach (BasePackage::STABILITIES as $stability => $value) { + if ($value <= BasePackage::STABILITIES[$minimumStability]) { $this->acceptableStabilities[$stability] = $value; } } @@ -195,7 +196,7 @@ public function findPackages(string $name, ?ConstraintInterface $constraint = nu } } else { foreach ($this->repositories as $repository) { - $result = $repository->loadPackages([$name => $constraint], $ignoreStability ? BasePackage::$stabilities : $this->acceptableStabilities, $ignoreStability ? [] : $this->stabilityFlags); + $result = $repository->loadPackages([$name => $constraint], $ignoreStability ? BasePackage::STABILITIES : $this->acceptableStabilities, $ignoreStability ? [] : $this->stabilityFlags); $packages[] = $result['packages']; foreach ($result['namesFound'] as $nameFound) { @@ -283,7 +284,7 @@ private function getSecurityAdvisoriesForConstraints(array $packageConstraintMap /** * @return array[] an array with the provider name as key and value of array('name' => '...', 'description' => '...', 'type' => '...') - * @phpstan-return array + * @phpstan-return array */ public function getProviders(string $packageName): array { @@ -300,8 +301,8 @@ public function getProviders(string $packageName): array /** * Check for each given package name whether it would be accepted by this RepositorySet in the given $stability * - * @param string[] $names - * @param string $stability one of 'stable', 'RC', 'beta', 'alpha' or 'dev' + * @param string[] $names + * @param key-of $stability one of 'stable', 'RC', 'beta', 'alpha' or 'dev' */ public function isPackageAcceptable(array $names, string $stability): bool { diff --git a/app/vendor/composer/composer/src/Composer/Repository/RepositoryUtils.php b/app/vendor/composer/composer/src/Composer/Repository/RepositoryUtils.php index 62e1c5b0f..e6960c63d 100644 --- a/app/vendor/composer/composer/src/Composer/Repository/RepositoryUtils.php +++ b/app/vendor/composer/composer/src/Composer/Repository/RepositoryUtils.php @@ -24,23 +24,28 @@ class RepositoryUtils /** * Find all of $packages which are required by $requirer, either directly or transitively * - * Require-dev is ignored + * Require-dev is ignored by default, you can enable the require-dev of the initial $requirer + * packages by passing $includeRequireDev=true, but require-dev of transitive dependencies + * are always ignored. * * @template T of PackageInterface * @param array $packages * @param list $bucket Do not pass this in, only used to avoid recursion with circular deps * @return list */ - public static function filterRequiredPackages(array $packages, PackageInterface $requirer, array $bucket = []): array + public static function filterRequiredPackages(array $packages, PackageInterface $requirer, bool $includeRequireDev = false, array $bucket = []): array { $requires = $requirer->getRequires(); + if ($includeRequireDev) { + $requires = array_merge($requires, $requirer->getDevRequires()); + } foreach ($packages as $candidate) { foreach ($candidate->getNames() as $name) { if (isset($requires[$name])) { if (!in_array($candidate, $bucket, true)) { $bucket[] = $candidate; - $bucket = self::filterRequiredPackages($packages, $candidate, $bucket); + $bucket = self::filterRequiredPackages($packages, $candidate, false, $bucket); } break; } diff --git a/app/vendor/composer/composer/src/Composer/Repository/Vcs/FossilDriver.php b/app/vendor/composer/composer/src/Composer/Repository/Vcs/FossilDriver.php index e55b0d3ac..8a305216c 100644 --- a/app/vendor/composer/composer/src/Composer/Repository/Vcs/FossilDriver.php +++ b/app/vendor/composer/composer/src/Composer/Repository/Vcs/FossilDriver.php @@ -71,7 +71,7 @@ public function initialize(): void */ protected function checkFossil(): void { - if (0 !== $this->process->execute('fossil version', $ignoredOutput)) { + if (0 !== $this->process->execute(['fossil', 'version'], $ignoredOutput)) { throw new \RuntimeException("fossil was not found, check that it is installed and in your PATH env.\n\n" . $this->process->getErrorOutput()); } } @@ -81,6 +81,8 @@ protected function checkFossil(): void */ protected function updateLocalRepo(): void { + assert($this->repoFile !== null); + $fs = new Filesystem(); $fs->ensureDirectoryExists($this->checkoutDir); @@ -89,8 +91,8 @@ protected function updateLocalRepo(): void } // update the repo if it is a valid fossil repository - if (is_file($this->repoFile) && is_dir($this->checkoutDir) && 0 === $this->process->execute('fossil info', $output, $this->checkoutDir)) { - if (0 !== $this->process->execute('fossil pull', $output, $this->checkoutDir)) { + if (is_file($this->repoFile) && is_dir($this->checkoutDir) && 0 === $this->process->execute(['fossil', 'info'], $output, $this->checkoutDir)) { + if (0 !== $this->process->execute(['fossil', 'pull'], $output, $this->checkoutDir)) { $this->io->writeError('Failed to update '.$this->url.', package information from this repository may be outdated ('.$this->process->getErrorOutput().')'); } } else { @@ -100,13 +102,13 @@ protected function updateLocalRepo(): void $fs->ensureDirectoryExists($this->checkoutDir); - if (0 !== $this->process->execute(sprintf('fossil clone -- %s %s', ProcessExecutor::escape($this->url), ProcessExecutor::escape($this->repoFile)), $output)) { + if (0 !== $this->process->execute(['fossil', 'clone', '--', $this->url, $this->repoFile], $output)) { $output = $this->process->getErrorOutput(); throw new \RuntimeException('Failed to clone '.$this->url.' to repository ' . $this->repoFile . "\n\n" .$output); } - if (0 !== $this->process->execute(sprintf('fossil open --nested -- %s', ProcessExecutor::escape($this->repoFile)), $output, $this->checkoutDir)) { + if (0 !== $this->process->execute(['fossil', 'open', '--nested', '--', $this->repoFile], $output, $this->checkoutDir)) { $output = $this->process->getErrorOutput(); throw new \RuntimeException('Failed to open repository '.$this->repoFile.' in ' . $this->checkoutDir . "\n\n" .$output); @@ -155,10 +157,9 @@ public function getDist(string $identifier): ?array */ public function getFileContent(string $file, string $identifier): ?string { - $command = sprintf('fossil cat -r %s -- %s', ProcessExecutor::escape($identifier), ProcessExecutor::escape($file)); - $this->process->execute($command, $content, $this->checkoutDir); + $this->process->execute(['fossil', 'cat', '-r', $identifier, '--', $file], $content, $this->checkoutDir); - if (!trim($content)) { + if ('' === trim($content)) { return null; } @@ -170,7 +171,7 @@ public function getFileContent(string $file, string $identifier): ?string */ public function getChangeDate(string $identifier): ?\DateTimeImmutable { - $this->process->execute('fossil finfo -b -n 1 composer.json', $output, $this->checkoutDir); + $this->process->execute(['fossil', 'finfo', '-b', '-n', '1', 'composer.json'], $output, $this->checkoutDir); [, $date] = explode(' ', trim($output), 3); return new \DateTimeImmutable($date, new \DateTimeZone('UTC')); @@ -184,7 +185,7 @@ public function getTags(): array if (null === $this->tags) { $tags = []; - $this->process->execute('fossil tag list', $output, $this->checkoutDir); + $this->process->execute(['fossil', 'tag', 'list'], $output, $this->checkoutDir); foreach ($this->process->splitLines($output) as $tag) { $tags[$tag] = $tag; } @@ -203,7 +204,7 @@ public function getBranches(): array if (null === $this->branches) { $branches = []; - $this->process->execute('fossil branch list', $output, $this->checkoutDir); + $this->process->execute(['fossil', 'branch', 'list'], $output, $this->checkoutDir); foreach ($this->process->splitLines($output) as $branch) { $branch = trim(Preg::replace('/^\*/', '', trim($branch))); $branches[$branch] = $branch; @@ -237,7 +238,7 @@ public static function supports(IOInterface $io, Config $config, string $url, bo $process = new ProcessExecutor($io); // check whether there is a fossil repo in that path - if ($process->execute('fossil info', $output, $url) === 0) { + if ($process->execute(['fossil', 'info'], $output, $url) === 0) { return true; } } diff --git a/app/vendor/composer/composer/src/Composer/Repository/Vcs/GitDriver.php b/app/vendor/composer/composer/src/Composer/Repository/Vcs/GitDriver.php index 75ede6910..7be1faba0 100644 --- a/app/vendor/composer/composer/src/Composer/Repository/Vcs/GitDriver.php +++ b/app/vendor/composer/composer/src/Composer/Repository/Vcs/GitDriver.php @@ -52,7 +52,7 @@ public function initialize(): void throw new \RuntimeException('GitDriver requires a usable cache directory, and it looks like you set it to be disabled'); } - $this->repoDir = $this->config->get('cache-vcs-dir') . '/' . Preg::replace('{[^a-z0-9.]}i', '-', $this->url) . '/'; + $this->repoDir = $this->config->get('cache-vcs-dir') . '/' . Preg::replace('{[^a-z0-9.]}i', '-', Url::sanitize($this->url)) . '/'; GitUtil::cleanEnv(); @@ -102,7 +102,7 @@ public function getRootIdentifier(): string } // select currently checked out branch as default branch - $this->process->execute('git branch --no-color', $output, $this->repoDir); + $this->process->execute(['git', 'branch', '--no-color'], $output, $this->repoDir); $branches = $this->process->splitLines($output); if (!in_array('* master', $branches)) { foreach ($branches as $branch) { @@ -150,10 +150,9 @@ public function getFileContent(string $file, string $identifier): ?string throw new \RuntimeException('Invalid git identifier detected. Identifier must not start with a -, given: ' . $identifier); } - $resource = sprintf('%s:%s', ProcessExecutor::escape($identifier), ProcessExecutor::escape($file)); - $this->process->execute(sprintf('git show %s', $resource), $content, $this->repoDir); + $this->process->execute(['git', 'show', $identifier.':'.$file], $content, $this->repoDir); - if (!trim($content)) { + if (trim($content) === '') { return null; } @@ -165,10 +164,7 @@ public function getFileContent(string $file, string $identifier): ?string */ public function getChangeDate(string $identifier): ?\DateTimeImmutable { - $this->process->execute(sprintf( - 'git -c log.showSignature=false log -1 --format=%%at %s', - ProcessExecutor::escape($identifier) - ), $output, $this->repoDir); + $this->process->execute(['git', '-c', 'log.showSignature=false', 'log', '-1', '--format=%at', $identifier], $output, $this->repoDir); return new \DateTimeImmutable('@'.trim($output), new \DateTimeZone('UTC')); } @@ -181,10 +177,10 @@ public function getTags(): array if (null === $this->tags) { $this->tags = []; - $this->process->execute('git show-ref --tags --dereference', $output, $this->repoDir); - foreach ($output = $this->process->splitLines($output) as $tag) { - if ($tag && Preg::isMatch('{^([a-f0-9]{40}) refs/tags/(\S+?)(\^\{\})?$}', $tag, $match)) { - $this->tags[$match[2]] = (string) $match[1]; + $this->process->execute(['git', 'show-ref', '--tags', '--dereference'], $output, $this->repoDir); + foreach ($this->process->splitLines($output) as $tag) { + if ($tag !== '' && Preg::isMatch('{^([a-f0-9]{40}) refs/tags/(\S+?)(\^\{\})?$}', $tag, $match)) { + $this->tags[$match[2]] = $match[1]; } } } @@ -200,9 +196,9 @@ public function getBranches(): array if (null === $this->branches) { $branches = []; - $this->process->execute('git branch --no-color --no-abbrev -v', $output, $this->repoDir); + $this->process->execute(['git', 'branch', '--no-color', '--no-abbrev', '-v'], $output, $this->repoDir); foreach ($this->process->splitLines($output) as $branch) { - if ($branch && !Preg::isMatch('{^ *[^/]+/HEAD }', $branch)) { + if ($branch !== '' && !Preg::isMatch('{^ *[^/]+/HEAD }', $branch)) { if (Preg::isMatchStrictGroups('{^(?:\* )? *(\S+) *([a-f0-9]+)(?: .*)?$}', $branch, $match) && $match[1][0] !== '-') { $branches[$match[1]] = $match[2]; } @@ -233,9 +229,10 @@ public static function supports(IOInterface $io, Config $config, string $url, bo $process = new ProcessExecutor($io); // check whether there is a git repo in that path - if ($process->execute('git tag', $output, $url) === 0) { + if ($process->execute(['git', 'tag'], $output, $url) === 0) { return true; } + GitUtil::checkForRepoOwnershipError($process->getErrorOutput(), $url); } if (!$deep) { @@ -246,9 +243,7 @@ public static function supports(IOInterface $io, Config $config, string $url, bo GitUtil::cleanEnv(); try { - $gitUtil->runCommand(static function ($url): string { - return 'git ls-remote --heads -- ' . ProcessExecutor::escape($url); - }, $url, sys_get_temp_dir()); + $gitUtil->runCommands([['git', 'ls-remote', '--heads', '--', '%url%']], $url, sys_get_temp_dir()); } catch (\RuntimeException $e) { return false; } diff --git a/app/vendor/composer/composer/src/Composer/Repository/Vcs/GitHubDriver.php b/app/vendor/composer/composer/src/Composer/Repository/Vcs/GitHubDriver.php index 83c58887c..803aa23c3 100644 --- a/app/vendor/composer/composer/src/Composer/Repository/Vcs/GitHubDriver.php +++ b/app/vendor/composer/composer/src/Composer/Repository/Vcs/GitHubDriver.php @@ -63,8 +63,6 @@ public function initialize(): void throw new \InvalidArgumentException(sprintf('The GitHub repository URL %s is invalid.', $this->url)); } - assert(is_string($match[3])); - assert(is_string($match[4])); $this->owner = $match[3]; $this->repository = $match[4]; $this->originUrl = strtolower($match[1] ?? (string) $match[2]); @@ -237,7 +235,7 @@ private function getFundingInfo() $key = $match[1]; continue; } - if (Preg::isMatchStrictGroups('{^\[(.*)\](?:\s*#.*)?$}', $match[2], $match2)) { + if (Preg::isMatchStrictGroups('{^\[(.*?)\](?:\s*#.*)?$}', $match[2], $match2)) { foreach (array_map('trim', Preg::split('{[\'"]?\s*,\s*[\'"]?}', $match2[1])) as $item) { $result[] = ['type' => $match[1], 'url' => trim($item, '"\' ')]; } @@ -259,36 +257,60 @@ private function getFundingInfo() foreach ($result as $key => $item) { switch ($item['type']) { - case 'tidelift': - $result[$key]['url'] = 'https://tidelift.com/funding/github/' . $item['url']; + case 'community_bridge': + $result[$key]['url'] = 'https://funding.communitybridge.org/projects/' . basename($item['url']); break; case 'github': $result[$key]['url'] = 'https://github.com/' . basename($item['url']); break; - case 'patreon': - $result[$key]['url'] = 'https://www.patreon.com/' . basename($item['url']); - break; - case 'otechie': - $result[$key]['url'] = 'https://otechie.com/' . basename($item['url']); + case 'issuehunt': + $result[$key]['url'] = 'https://issuehunt.io/r/' . $item['url']; break; - case 'open_collective': - $result[$key]['url'] = 'https://opencollective.com/' . basename($item['url']); + case 'ko_fi': + $result[$key]['url'] = 'https://ko-fi.com/' . basename($item['url']); break; case 'liberapay': $result[$key]['url'] = 'https://liberapay.com/' . basename($item['url']); break; - case 'ko_fi': - $result[$key]['url'] = 'https://ko-fi.com/' . basename($item['url']); + case 'open_collective': + $result[$key]['url'] = 'https://opencollective.com/' . basename($item['url']); break; - case 'issuehunt': - $result[$key]['url'] = 'https://issuehunt.io/r/' . $item['url']; + case 'patreon': + $result[$key]['url'] = 'https://www.patreon.com/' . basename($item['url']); break; - case 'community_bridge': - $result[$key]['url'] = 'https://funding.communitybridge.org/projects/' . basename($item['url']); + case 'tidelift': + $result[$key]['url'] = 'https://tidelift.com/funding/github/' . $item['url']; + break; + case 'polar': + $result[$key]['url'] = 'https://polar.sh/' . basename($item['url']); break; case 'buy_me_a_coffee': $result[$key]['url'] = 'https://www.buymeacoffee.com/' . basename($item['url']); break; + case 'thanks_dev': + $result[$key]['url'] = 'https://thanks.dev/' . $item['url']; + break; + case 'otechie': + $result[$key]['url'] = 'https://otechie.com/' . basename($item['url']); + break; + case 'custom': + $bits = parse_url($item['url']); + if ($bits === false) { + unset($result[$key]); + break; + } + + if (!array_key_exists('scheme', $bits) && !array_key_exists('host', $bits)) { + if (Preg::isMatch('{^[a-z0-9-]++\.[a-z]{2,3}$}', $item['url'])) { + $result[$key]['url'] = 'https://'.$item['url']; + break; + } + + $this->io->writeError('Funding URL '.$item['url'].' not in a supported format.'); + unset($result[$key]); + break; + } + break; } } diff --git a/app/vendor/composer/composer/src/Composer/Repository/Vcs/GitLabDriver.php b/app/vendor/composer/composer/src/Composer/Repository/Vcs/GitLabDriver.php index 3721419b1..87e7c497c 100644 --- a/app/vendor/composer/composer/src/Composer/Repository/Vcs/GitLabDriver.php +++ b/app/vendor/composer/composer/src/Composer/Repository/Vcs/GitLabDriver.php @@ -97,8 +97,6 @@ public function initialize(): void throw new \InvalidArgumentException(sprintf('The GitLab repository URL %s is invalid. It must be the HTTP URL of a GitLab project.', $this->url)); } - assert(is_string($match['parts'])); - assert(is_string($match['repo'])); $guessedDomain = $match['domain'] ?? (string) $match['domain2']; $configuredDomains = $this->config->get('gitlab-domains'); $urlParts = explode('/', $match['parts']); @@ -109,13 +107,13 @@ public function initialize(): void ; $origin = self::determineOrigin($configuredDomains, $guessedDomain, $urlParts, $match['port']); if (false === $origin) { - throw new \LogicException('It should not be possible to create a gitlab driver with an unparseable origin URL ('.$this->url.')'); + throw new \LogicException('It should not be possible to create a gitlab driver with an unparsable origin URL ('.$this->url.')'); } $this->originUrl = $origin; if (is_string($protocol = $this->config->get('gitlab-protocol'))) { // https treated as a synonym for http. - if (!in_array($protocol, ['git', 'http', 'https'])) { + if (!in_array($protocol, ['git', 'http', 'https'], true)) { throw new \RuntimeException('gitlab-protocol must be one of git, http.'); } $this->protocol = $protocol === 'git' ? 'ssh' : 'http'; @@ -465,7 +463,7 @@ protected function getContents(string $url, bool $fetchingRepoData = false): Res if ($fetchingRepoData) { $json = $response->decodeJson(); - // Accessing the API with a token with Guest (10) access will return + // Accessing the API with a token with Guest (10) or Planner (15) access will return // more data than unauthenticated access but no default_branch data // accessing files via the API will then also fail if (!isset($json['default_branch']) && isset($json['permissions'])) { @@ -476,13 +474,13 @@ protected function getContents(string $url, bool $fetchingRepoData = false): Res // - value will be null if no access is set // - value will be array with key access_level if set foreach ($json['permissions'] as $permission) { - if ($permission && $permission['access_level'] > 10) { + if ($permission && $permission['access_level'] >= 20) { $moreThanGuestAccess = true; } } if (!$moreThanGuestAccess) { - $this->io->writeError('GitLab token with Guest only access detected'); + $this->io->writeError('GitLab token with Guest or Planner only access detected'); $this->attemptCloneFallback(); @@ -566,8 +564,6 @@ public static function supports(IOInterface $io, Config $config, string $url, bo return false; } - assert(is_string($match['parts'])); - assert(is_string($match['repo'])); $scheme = $match['scheme']; $guessedDomain = $match['domain'] ?? (string) $match['domain2']; $urlParts = explode('/', $match['parts']); diff --git a/app/vendor/composer/composer/src/Composer/Repository/Vcs/HgDriver.php b/app/vendor/composer/composer/src/Composer/Repository/Vcs/HgDriver.php index e70b9a6ac..625a2a1eb 100644 --- a/app/vendor/composer/composer/src/Composer/Repository/Vcs/HgDriver.php +++ b/app/vendor/composer/composer/src/Composer/Repository/Vcs/HgDriver.php @@ -19,6 +19,7 @@ use Composer\Util\ProcessExecutor; use Composer\Util\Filesystem; use Composer\IO\IOInterface; +use Composer\Util\Url; /** * @author Per Bernhardt @@ -47,7 +48,7 @@ public function initialize(): void } $cacheDir = $this->config->get('cache-vcs-dir'); - $this->repoDir = $cacheDir . '/' . Preg::replace('{[^a-z0-9]}i', '-', $this->url) . '/'; + $this->repoDir = $cacheDir . '/' . Preg::replace('{[^a-z0-9]}i', '-', Url::sanitize($this->url)) . '/'; $fs = new Filesystem(); $fs->ensureDirectoryExists($cacheDir); @@ -62,8 +63,8 @@ public function initialize(): void $hgUtils = new HgUtils($this->io, $this->config, $this->process); // update the repo if it is a valid hg repository - if (is_dir($this->repoDir) && 0 === $this->process->execute('hg summary', $output, $this->repoDir)) { - if (0 !== $this->process->execute('hg pull', $output, $this->repoDir)) { + if (is_dir($this->repoDir) && 0 === $this->process->execute(['hg', 'summary'], $output, $this->repoDir)) { + if (0 !== $this->process->execute(['hg', 'pull'], $output, $this->repoDir)) { $this->io->writeError('Failed to update '.$this->url.', package information from this repository may be outdated ('.$this->process->getErrorOutput().')'); } } else { @@ -71,8 +72,8 @@ public function initialize(): void $fs->removeDirectory($this->repoDir); $repoDir = $this->repoDir; - $command = static function ($url) use ($repoDir): string { - return sprintf('hg clone --noupdate -- %s %s', ProcessExecutor::escape($url), ProcessExecutor::escape($repoDir)); + $command = static function ($url) use ($repoDir): array { + return ['hg', 'clone', '--noupdate', '--', $url, $repoDir]; }; $hgUtils->runCommand($command, $this->url, null); @@ -89,7 +90,7 @@ public function initialize(): void public function getRootIdentifier(): string { if (null === $this->rootIdentifier) { - $this->process->execute('hg tip --template "{node}"', $output, $this->repoDir); + $this->process->execute(['hg', 'tip', '--template', '{node}'], $output, $this->repoDir); $output = $this->process->splitLines($output); $this->rootIdentifier = $output[0]; } @@ -130,7 +131,7 @@ public function getFileContent(string $file, string $identifier): ?string throw new \RuntimeException('Invalid hg identifier detected. Identifier must not start with a -, given: ' . $identifier); } - $resource = sprintf('hg cat -r %s -- %s', ProcessExecutor::escape($identifier), ProcessExecutor::escape($file)); + $resource = ['hg', 'cat', '-r', $identifier, '--', $file]; $this->process->execute($resource, $content, $this->repoDir); if (!trim($content)) { @@ -146,10 +147,7 @@ public function getFileContent(string $file, string $identifier): ?string public function getChangeDate(string $identifier): ?\DateTimeImmutable { $this->process->execute( - sprintf( - 'hg log --template "{date|rfc3339date}" -r %s', - ProcessExecutor::escape($identifier) - ), + ['hg', 'log', '--template', '{date|rfc3339date}', '-r', $identifier], $output, $this->repoDir ); @@ -165,7 +163,7 @@ public function getTags(): array if (null === $this->tags) { $tags = []; - $this->process->execute('hg tags', $output, $this->repoDir); + $this->process->execute(['hg', 'tags'], $output, $this->repoDir); foreach ($this->process->splitLines($output) as $tag) { if ($tag && Preg::isMatchStrictGroups('(^([^\s]+)\s+\d+:(.*)$)', $tag, $match)) { $tags[$match[1]] = $match[2]; @@ -188,14 +186,14 @@ public function getBranches(): array $branches = []; $bookmarks = []; - $this->process->execute('hg branches', $output, $this->repoDir); + $this->process->execute(['hg', 'branches'], $output, $this->repoDir); foreach ($this->process->splitLines($output) as $branch) { if ($branch && Preg::isMatchStrictGroups('(^([^\s]+)\s+\d+:([a-f0-9]+))', $branch, $match) && $match[1][0] !== '-') { $branches[$match[1]] = $match[2]; } } - $this->process->execute('hg bookmarks', $output, $this->repoDir); + $this->process->execute(['hg', 'bookmarks'], $output, $this->repoDir); foreach ($this->process->splitLines($output) as $branch) { if ($branch && Preg::isMatchStrictGroups('(^(?:[\s*]*)([^\s]+)\s+\d+:(.*)$)', $branch, $match) && $match[1][0] !== '-') { $bookmarks[$match[1]] = $match[2]; @@ -227,7 +225,7 @@ public static function supports(IOInterface $io, Config $config, string $url, bo $process = new ProcessExecutor($io); // check whether there is a hg repo in that path - if ($process->execute('hg summary', $output, $url) === 0) { + if ($process->execute(['hg', 'summary'], $output, $url) === 0) { return true; } } @@ -237,7 +235,7 @@ public static function supports(IOInterface $io, Config $config, string $url, bo } $process = new ProcessExecutor($io); - $exit = $process->execute(sprintf('hg identify -- %s', ProcessExecutor::escape($url)), $ignored); + $exit = $process->execute(['hg', 'identify', '--', $url], $ignored); return $exit === 0; } diff --git a/app/vendor/composer/composer/src/Composer/Repository/Vcs/SvnDriver.php b/app/vendor/composer/composer/src/Composer/Repository/Vcs/SvnDriver.php index ea8158e34..9a303ee14 100644 --- a/app/vendor/composer/composer/src/Composer/Repository/Vcs/SvnDriver.php +++ b/app/vendor/composer/composer/src/Composer/Repository/Vcs/SvnDriver.php @@ -177,8 +177,7 @@ public function getFileContent(string $file, string $identifier): ?string { $identifier = '/' . trim($identifier, '/') . '/'; - Preg::match('{^(.+?)(@\d+)?/$}', $identifier, $match); - if (!empty($match[2])) { + if (Preg::isMatch('{^(.+?)(@\d+)?/$}', $identifier, $match) && $match[2] !== null) { $path = $match[1]; $rev = $match[2]; } else { @@ -188,8 +187,8 @@ public function getFileContent(string $file, string $identifier): ?string try { $resource = $path.$file; - $output = $this->execute('svn cat', $this->baseUrl . $resource . $rev); - if (!trim($output)) { + $output = $this->execute(['svn', 'cat'], $this->baseUrl . $resource . $rev); + if ('' === trim($output)) { return null; } } catch (\RuntimeException $e) { @@ -206,8 +205,7 @@ public function getChangeDate(string $identifier): ?\DateTimeImmutable { $identifier = '/' . trim($identifier, '/') . '/'; - Preg::match('{^(.+?)(@\d+)?/$}', $identifier, $match); - if (null !== $match[2] && null !== $match[1]) { + if (Preg::isMatch('{^(.+?)(@\d+)?/$}', $identifier, $match) && null !== $match[2]) { $path = $match[1]; $rev = $match[2]; } else { @@ -215,9 +213,9 @@ public function getChangeDate(string $identifier): ?\DateTimeImmutable $rev = ''; } - $output = $this->execute('svn info', $this->baseUrl . $path . $rev); + $output = $this->execute(['svn', 'info'], $this->baseUrl . $path . $rev); foreach ($this->process->splitLines($output) as $line) { - if ($line && Preg::isMatchStrictGroups('{^Last Changed Date: ([^(]+)}', $line, $match)) { + if ($line !== '' && Preg::isMatchStrictGroups('{^Last Changed Date: ([^(]+)}', $line, $match)) { return new \DateTimeImmutable($match[1], new \DateTimeZone('UTC')); } } @@ -234,21 +232,19 @@ public function getTags(): array $tags = []; if ($this->tagsPath !== false) { - $output = $this->execute('svn ls --verbose', $this->baseUrl . '/' . $this->tagsPath); - if ($output) { + $output = $this->execute(['svn', 'ls', '--verbose'], $this->baseUrl . '/' . $this->tagsPath); + if ($output !== '') { $lastRev = 0; foreach ($this->process->splitLines($output) as $line) { $line = trim($line); - if ($line && Preg::isMatch('{^\s*(\S+).*?(\S+)\s*$}', $line, $match)) { - if (isset($match[1], $match[2])) { - if ($match[2] === './') { - $lastRev = (int) $match[1]; - } else { - $tags[rtrim($match[2], '/')] = $this->buildIdentifier( - '/' . $this->tagsPath . '/' . $match[2], - max($lastRev, (int) $match[1]) - ); - } + if ($line !== '' && Preg::isMatch('{^\s*(\S+).*?(\S+)\s*$}', $line, $match)) { + if ($match[2] === './') { + $lastRev = (int) $match[1]; + } else { + $tags[rtrim($match[2], '/')] = $this->buildIdentifier( + '/' . $this->tagsPath . '/' . $match[2], + max($lastRev, (int) $match[1]) + ); } } } @@ -275,12 +271,12 @@ public function getBranches(): array $trunkParent = $this->baseUrl . '/' . $this->trunkPath; } - $output = $this->execute('svn ls --verbose', $trunkParent); - if ($output) { + $output = $this->execute(['svn', 'ls', '--verbose'], $trunkParent); + if ($output !== '') { foreach ($this->process->splitLines($output) as $line) { $line = trim($line); - if ($line && Preg::isMatch('{^\s*(\S+).*?(\S+)\s*$}', $line, $match)) { - if (isset($match[1], $match[2]) && $match[2] === './') { + if ($line !== '' && Preg::isMatch('{^\s*(\S+).*?(\S+)\s*$}', $line, $match)) { + if ($match[2] === './') { $branches['trunk'] = $this->buildIdentifier( '/' . $this->trunkPath, (int) $match[1] @@ -294,21 +290,19 @@ public function getBranches(): array unset($output); if ($this->branchesPath !== false) { - $output = $this->execute('svn ls --verbose', $this->baseUrl . '/' . $this->branchesPath); - if ($output) { + $output = $this->execute(['svn', 'ls', '--verbose'], $this->baseUrl . '/' . $this->branchesPath); + if ($output !== '') { $lastRev = 0; foreach ($this->process->splitLines(trim($output)) as $line) { $line = trim($line); - if ($line && Preg::isMatch('{^\s*(\S+).*?(\S+)\s*$}', $line, $match)) { - if (isset($match[1], $match[2])) { - if ($match[2] === './') { - $lastRev = (int) $match[1]; - } else { - $branches[rtrim($match[2], '/')] = $this->buildIdentifier( - '/' . $this->branchesPath . '/' . $match[2], - max($lastRev, (int) $match[1]) - ); - } + if ($line !== '' && Preg::isMatch('{^\s*(\S+).*?(\S+)\s*$}', $line, $match)) { + if ($match[2] === './') { + $lastRev = (int) $match[1]; + } else { + $branches[rtrim($match[2], '/')] = $this->buildIdentifier( + '/' . $this->branchesPath . '/' . $match[2], + max($lastRev, (int) $match[1]) + ); } } } @@ -337,10 +331,7 @@ public static function supports(IOInterface $io, Config $config, string $url, bo } $process = new ProcessExecutor($io); - $exit = $process->execute( - "svn info --non-interactive -- ".ProcessExecutor::escape($url), - $ignoredOutput - ); + $exit = $process->execute(['svn', 'info', '--non-interactive', '--', $url], $ignoredOutput); if ($exit === 0) { // This is definitely a Subversion repository. @@ -381,11 +372,11 @@ protected static function normalizeUrl(string $url): string * Execute an SVN command and try to fix up the process with credentials * if necessary. * - * @param string $command The svn command to run. + * @param non-empty-list $command The svn command to run. * @param string $url The SVN URL. * @throws \RuntimeException */ - protected function execute(string $command, string $url): string + protected function execute(array $command, string $url): string { if (null === $this->util) { $this->util = new SvnUtil($this->baseUrl, $this->io, $this->config, $this->process); diff --git a/app/vendor/composer/composer/src/Composer/Repository/VcsRepository.php b/app/vendor/composer/composer/src/Composer/Repository/VcsRepository.php index d10ad87a0..5aaea602d 100644 --- a/app/vendor/composer/composer/src/Composer/Repository/VcsRepository.php +++ b/app/vendor/composer/composer/src/Composer/Repository/VcsRepository.php @@ -66,7 +66,7 @@ class VcsRepository extends ArrayRepository implements ConfigurableRepositoryInt private $driver; /** @var ?VersionCacheInterface */ private $versionCache; - /** @var string[] */ + /** @var list */ private $emptyReferences = []; /** @var array<'tags'|'branches', array> */ private $versionTransportExceptions = []; @@ -165,7 +165,7 @@ public function hadInvalidBranches(): bool } /** - * @return string[] + * @return list */ public function getEmptyReferences(): array { @@ -217,11 +217,6 @@ protected function initialize() foreach ($driver->getTags() as $tag => $identifier) { $tag = (string) $tag; $msg = 'Reading composer.json of ' . ($this->packageName ?: $this->url) . ' (' . $tag . ')'; - if ($isVeryVerbose) { - $this->io->writeError($msg); - } elseif ($isVerbose) { - $this->io->overwriteError($msg, false); - } // strip the release- prefix from tags if present $tag = str_replace('release-', '', $tag); @@ -245,6 +240,12 @@ protected function initialize() continue; } + if ($isVeryVerbose) { + $this->io->writeError($msg); + } elseif ($isVerbose) { + $this->io->overwriteError($msg, false); + } + try { $data = $driver->getComposerInformation($identifier); if (null === $data) { @@ -341,7 +342,8 @@ protected function initialize() // make sure branch packages have a dev flag if (strpos($parsedBranch, 'dev-') === 0 || VersionParser::DEFAULT_BRANCH_ALIAS === $parsedBranch) { - $version = 'dev-' . $branch; + $version = 'dev-' . str_replace('#', '+', $branch); + $parsedBranch = str_replace('#', '+', $parsedBranch); } else { $prefix = strpos($branch, 'v') === 0 ? 'v' : ''; $version = $prefix . Preg::replace('{(\.9{7})+}', '.x', $parsedBranch); @@ -441,6 +443,11 @@ protected function preProcess(VcsDriverInterface $driver, array $data, string $i $data['source'] = $driver->getSource($identifier); } + // if custom dist info is provided but does not provide a reference, copy the source reference to it + if (is_array($data['dist']) && !isset($data['dist']['reference']) && isset($data['source']['reference'])) { + $data['dist']['reference'] = $data['source']['reference']; + } + return $data; } diff --git a/app/vendor/composer/composer/src/Composer/SelfUpdate/Versions.php b/app/vendor/composer/composer/src/Composer/SelfUpdate/Versions.php index 045fb22a7..8cc7d455c 100644 --- a/app/vendor/composer/composer/src/Composer/SelfUpdate/Versions.php +++ b/app/vendor/composer/composer/src/Composer/SelfUpdate/Versions.php @@ -89,7 +89,7 @@ public function getLatest(?string $channel = null): array $versions = $this->getVersionsData(); foreach ($versions[$channel ?: $this->getChannel()] as $version) { - if ($version['min-php'] <= PHP_VERSION_ID) { + if ($version['min-php'] <= \PHP_VERSION_ID) { return $version; } } diff --git a/app/vendor/composer/composer/src/Composer/Util/Bitbucket.php b/app/vendor/composer/composer/src/Composer/Util/Bitbucket.php index 2be4a815c..15743a7e3 100644 --- a/app/vendor/composer/composer/src/Composer/Util/Bitbucket.php +++ b/app/vendor/composer/composer/src/Composer/Util/Bitbucket.php @@ -77,7 +77,7 @@ public function authorizeOAuth(string $originUrl): bool } // if available use token from git config - if (0 === $this->process->execute('git config bitbucket.accesstoken', $output)) { + if (0 === $this->process->execute(['git', 'config', 'bitbucket.accesstoken'], $output)) { $this->io->setAuthentication($originUrl, 'x-token-auth', trim($output)); return true; diff --git a/app/vendor/composer/composer/src/Composer/Util/ComposerMirror.php b/app/vendor/composer/composer/src/Composer/Util/ComposerMirror.php index 106e76c41..6be539693 100644 --- a/app/vendor/composer/composer/src/Composer/Util/ComposerMirror.php +++ b/app/vendor/composer/composer/src/Composer/Util/ComposerMirror.php @@ -28,9 +28,9 @@ class ComposerMirror public static function processUrl(string $mirrorUrl, string $packageName, string $version, ?string $reference, ?string $type, ?string $prettyVersion = null): string { if ($reference) { - $reference = Preg::isMatch('{^([a-f0-9]*|%reference%)$}', $reference) ? $reference : md5($reference); + $reference = Preg::isMatch('{^([a-f0-9]*|%reference%)$}', $reference) ? $reference : hash('md5', $reference); } - $version = strpos($version, '/') === false ? $version : md5($version); + $version = strpos($version, '/') === false ? $version : hash('md5', $version); $from = ['%package%', '%version%', '%reference%', '%type%']; $to = [$packageName, $version, $reference, $type]; diff --git a/app/vendor/composer/composer/src/Composer/Util/ErrorHandler.php b/app/vendor/composer/composer/src/Composer/Util/ErrorHandler.php index 38cf84e44..b99479c31 100644 --- a/app/vendor/composer/composer/src/Composer/Util/ErrorHandler.php +++ b/app/vendor/composer/composer/src/Composer/Util/ErrorHandler.php @@ -24,6 +24,9 @@ class ErrorHandler /** @var ?IOInterface */ private static $io; + /** @var int<0, 2> */ + private static $hasShownDeprecationNotice = 0; + /** * Error handler * @@ -40,7 +43,7 @@ public static function handle(int $level, string $message, string $file, int $li $isDeprecationNotice = $level === E_DEPRECATED || $level === E_USER_DEPRECATED; // error code is not included in error_reporting - if (!$isDeprecationNotice && !(error_reporting() & $level)) { + if (!$isDeprecationNotice && 0 === (error_reporting() & $level)) { return true; } @@ -50,11 +53,45 @@ public static function handle(int $level, string $message, string $file, int $li } if (!$isDeprecationNotice) { + // ignore some newly introduced warnings in new php versions until dependencies + // can be fixed as we do not want to abort execution for those + if (in_array($level, [E_WARNING, E_USER_WARNING], true) && str_contains($message, 'should either be used or intentionally ignored by casting it as (void)')) { + self::outputWarning('Ignored new PHP warning but it should be reported and fixed: '.$message.' in '.$file.':'.$line, true); + return true; + } + throw new \ErrorException($message, 0, $level, $file, $line); } - if (self::$io) { - self::$io->writeError('Deprecation Notice: '.$message.' in '.$file.':'.$line.''); + if (self::$io !== null) { + if (self::$hasShownDeprecationNotice > 0 && !self::$io->isVerbose()) { + if (self::$hasShownDeprecationNotice === 1) { + self::$io->writeError('More deprecation notices were hidden, run again with `-v` to show them.'); + self::$hasShownDeprecationNotice = 2; + } + return true; + } + self::$hasShownDeprecationNotice = 1; + self::outputWarning('Deprecation Notice: '.$message.' in '.$file.':'.$line); + } + + return true; + } + + /** + * Register error handler. + */ + public static function register(?IOInterface $io = null): void + { + set_error_handler([__CLASS__, 'handle']); + error_reporting(E_ALL); + self::$io = $io; + } + + private static function outputWarning(string $message, bool $outputEvenWithoutIO = false): void + { + if (self::$io !== null) { + self::$io->writeError(''.$message.''); if (self::$io->isVerbose()) { self::$io->writeError('Stack trace:'); self::$io->writeError(array_filter(array_map(static function ($a): ?string { @@ -67,18 +104,16 @@ public static function handle(int $level, string $message, string $file, int $li return $line !== null; })); } - } - return true; - } + return; + } - /** - * Register error handler. - */ - public static function register(?IOInterface $io = null): void - { - set_error_handler([__CLASS__, 'handle']); - error_reporting(E_ALL | E_STRICT); - self::$io = $io; + if ($outputEvenWithoutIO) { + if (defined('STDERR') && is_resource(STDERR)) { + fwrite(STDERR, 'Warning: '.$message.PHP_EOL); + } else { + echo 'Warning: '.$message.PHP_EOL; + } + } } } diff --git a/app/vendor/composer/composer/src/Composer/Util/Filesystem.php b/app/vendor/composer/composer/src/Composer/Util/Filesystem.php index ad0aae983..57e4fd6f3 100644 --- a/app/vendor/composer/composer/src/Composer/Util/Filesystem.php +++ b/app/vendor/composer/composer/src/Composer/Util/Filesystem.php @@ -13,6 +13,7 @@ namespace Composer\Util; use Composer\Pcre\Preg; +use ErrorException; use React\Promise\PromiseInterface; use RecursiveDirectoryIterator; use RecursiveIteratorIterator; @@ -108,9 +109,9 @@ public function removeDirectory(string $directory) } if (Platform::isWindows()) { - $cmd = sprintf('rmdir /S /Q %s', ProcessExecutor::escape(realpath($directory))); + $cmd = ['rmdir', '/S', '/Q', Platform::realpath($directory)]; } else { - $cmd = sprintf('rm -rf %s', ProcessExecutor::escape($directory)); + $cmd = ['rm', '-rf', $directory]; } $result = $this->getProcess()->execute($cmd, $output) === 0; @@ -143,9 +144,9 @@ public function removeDirectoryAsync(string $directory) } if (Platform::isWindows()) { - $cmd = sprintf('rmdir /S /Q %s', ProcessExecutor::escape(realpath($directory))); + $cmd = ['rmdir', '/S', '/Q', Platform::realpath($directory)]; } else { - $cmd = sprintf('rm -rf %s', ProcessExecutor::escape($directory)); + $cmd = ['rm', '-rf', $directory]; } $promise = $this->getProcess()->executeAsync($cmd); @@ -367,7 +368,29 @@ public function copy(string $source, string $target) $target = $this->normalizePath($target); if (!is_dir($source)) { - return copy($source, $target); + try { + return copy($source, $target); + } catch (ErrorException $e) { + // if copy fails we attempt to copy it manually as this can help bypass issues with VirtualBox shared folders + // see https://github.com/composer/composer/issues/12057 + if (str_contains($e->getMessage(), 'Bad address')) { + $sourceHandle = fopen($source, 'r'); + $targetHandle = fopen($target, 'w'); + if (false === $sourceHandle || false === $targetHandle) { + throw $e; + } + while (!feof($sourceHandle)) { + if (false === fwrite($targetHandle, (string) fread($sourceHandle, 1024 * 1024))) { + throw $e; + } + } + fclose($sourceHandle); + fclose($targetHandle); + + return true; + } + throw $e; + } } $it = new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS); @@ -404,8 +427,7 @@ public function rename(string $source, string $target) if (Platform::isWindows()) { // Try to copy & delete - this is a workaround for random "Access denied" errors. - $command = sprintf('xcopy %s %s /E /I /Q /Y', ProcessExecutor::escape($source), ProcessExecutor::escape($target)); - $result = $this->getProcess()->execute($command, $output); + $result = $this->getProcess()->execute(['xcopy', $source, $target, '/E', '/I', '/Q', '/Y'], $output); // clear stat cache because external processes aren't tracked by the php stat cache clearstatcache(); @@ -418,8 +440,7 @@ public function rename(string $source, string $target) } else { // We do not use PHP's "rename" function here since it does not support // the case where $source, and $target are located on different partitions. - $command = sprintf('mv %s %s', ProcessExecutor::escape($source), ProcessExecutor::escape($target)); - $result = $this->getProcess()->execute($command, $output); + $result = $this->getProcess()->execute(['mv', $source, $target], $output); // clear stat cache because external processes aren't tracked by the php stat cache clearstatcache(); @@ -436,10 +457,11 @@ public function rename(string $source, string $target) * Returns the shortest path from $from to $to * * @param bool $directories if true, the source/target are considered to be directories + * @param bool $preferRelative if true, relative paths will be preferred even if longer * @throws \InvalidArgumentException * @return string */ - public function findShortestPath(string $from, string $to, bool $directories = false) + public function findShortestPath(string $from, string $to, bool $directories = false, bool $preferRelative = false) { if (!$this->isAbsolutePath($from) || !$this->isAbsolutePath($to)) { throw new \InvalidArgumentException(sprintf('$from (%s) and $to (%s) must be absolute paths.', $from, $to)); @@ -471,7 +493,7 @@ public function findShortestPath(string $from, string $to, bool $directories = f $commonPathCode = str_repeat('../', $sourcePathDepth); // allow top level /foo & /bar dirs to be addressed relatively as this is common in Docker setups - if ('/' === $commonPath && $sourcePathDepth > 1) { + if (!$preferRelative && '/' === $commonPath && $sourcePathDepth > 1) { return $to; } @@ -487,10 +509,11 @@ public function findShortestPath(string $from, string $to, bool $directories = f * Returns PHP code that, when executed in $from, will return the path to $to * * @param bool $directories if true, the source/target are considered to be directories + * @param bool $preferRelative if true, relative paths will be preferred even if longer * @throws \InvalidArgumentException * @return string */ - public function findShortestPathCode(string $from, string $to, bool $directories = false, bool $staticCode = false) + public function findShortestPathCode(string $from, string $to, bool $directories = false, bool $staticCode = false, bool $preferRelative = false) { if (!$this->isAbsolutePath($from) || !$this->isAbsolutePath($to)) { throw new \InvalidArgumentException(sprintf('$from (%s) and $to (%s) must be absolute paths.', $from, $to)); @@ -520,7 +543,7 @@ public function findShortestPathCode(string $from, string $to, bool $directories $sourcePathDepth = substr_count((string) substr($from, \strlen($commonPath)), '/') + (int) $directories; // allow top level /foo & /bar dirs to be addressed relatively as this is common in Docker setups - if ('/' === $commonPath && $sourcePathDepth > 1) { + if (!$preferRelative && '/' === $commonPath && $sourcePathDepth > 1) { return var_export($to, true); } @@ -608,7 +631,6 @@ public function normalizePath(string $path) // ensure c: is normalized to C: $prefix = Preg::replaceCallback('{(^|://)[a-z]:$}i', static function (array $m) { - assert(is_string($m[0])); return strtoupper($m[0]); }, $prefix); @@ -638,7 +660,13 @@ public static function trimTrailingSlash(string $path) */ public static function isLocalPath(string $path) { - return Preg::isMatch('{^(file://(?!//)|/(?!/)|/?[a-z]:[\\\\/]|\.\.[\\\\/]|[a-z0-9_.-]+[\\\\/])}i', $path); + // on windows, \\foo indicates network paths so we exclude those from local paths, however it is unsafe + // on linux as file:////foo (which would be a network path \\foo on windows) will resolve to /foo which could be a local path + if (Platform::isWindows()) { + return Preg::isMatch('{^(file://(?!//)|/(?!/)|/?[a-z]:[\\\\/]|\.\.[\\\\/]|[a-z0-9_.-]+[\\\\/])}i', $path); + } + + return Preg::isMatch('{^(file://|/|/?[a-z]:[\\\\/]|\.\.[\\\\/]|[a-z0-9_.-]+[\\\\/])}i', $path); } /** @@ -811,11 +839,7 @@ public function junction(string $target, string $junction) @rmdir($junction); } - $cmd = sprintf( - 'mklink /J %s %s', - ProcessExecutor::escape(str_replace('/', DIRECTORY_SEPARATOR, $junction)), - ProcessExecutor::escape(realpath($target)) - ); + $cmd = ['mklink', '/J', str_replace('/', DIRECTORY_SEPARATOR, $junction), Platform::realpath($target)]; if ($this->getProcess()->execute($cmd, $output) !== 0) { throw new IOException(sprintf('Failed to create junction to "%s" at "%s".', $target, $junction), 0, null, $target); } diff --git a/app/vendor/composer/composer/src/Composer/Util/Git.php b/app/vendor/composer/composer/src/Composer/Util/Git.php index 64b643216..cf08c523e 100644 --- a/app/vendor/composer/composer/src/Composer/Util/Git.php +++ b/app/vendor/composer/composer/src/Composer/Util/Git.php @@ -32,6 +32,8 @@ class Git protected $process; /** @var Filesystem */ protected $filesystem; + /** @var HttpDownloader */ + protected $httpDownloader; public function __construct(IOInterface $io, Config $config, ProcessExecutor $process, Filesystem $fs) { @@ -42,26 +44,109 @@ public function __construct(IOInterface $io, Config $config, ProcessExecutor $pr } /** + * @param IOInterface|null $io If present, a warning is output there instead of throwing, so pass this in only for cases where this is a soft failure + */ + public static function checkForRepoOwnershipError(string $output, string $path, ?IOInterface $io = null): void + { + if (str_contains($output, 'fatal: detected dubious ownership')) { + $msg = 'The repository at "' . $path . '" does not have the correct ownership and git refuses to use it:' . PHP_EOL . PHP_EOL . $output; + if ($io === null) { + throw new \RuntimeException($msg); + } + $io->writeError(''.$msg.''); + } + } + + public function setHttpDownloader(HttpDownloader $httpDownloader): void + { + $this->httpDownloader = $httpDownloader; + } + + /** + * Runs a set of commands using the $url or a variation of it (with auth, ssh, ..) + * + * Commands should use %url% placeholders for the URL instead of inlining it to allow this function to do its job + * %sanitizedUrl% is also automatically replaced by the url without user/pass + * + * As soon as a single command fails it will halt, so assume the commands are run as && in bash + * + * @param non-empty-array> $commands + * @param mixed $commandOutput the output will be written into this var if passed by ref + * if a callable is passed it will be used as output handler + */ + public function runCommands(array $commands, string $url, ?string $cwd, bool $initialClone = false, &$commandOutput = null): void + { + $callables = []; + foreach ($commands as $cmd) { + $callables[] = static function (string $url) use ($cmd): array { + $map = [ + '%url%' => $url, + '%sanitizedUrl%' => Preg::replace('{://([^@]+?):(.+?)@}', '://', $url), + ]; + + return array_map(static function ($value) use ($map): string { + return $map[$value] ?? $value; + }, $cmd); + }; + } + + // @phpstan-ignore method.deprecated + $this->runCommand($callables, $url, $cwd, $initialClone, $commandOutput); + } + + /** + * @param callable|array $commandCallable * @param mixed $commandOutput the output will be written into this var if passed by ref * if a callable is passed it will be used as output handler + * @deprecated Use runCommands with placeholders instead of callbacks for simplicity */ - public function runCommand(callable $commandCallable, string $url, ?string $cwd, bool $initialClone = false, &$commandOutput = null): void + public function runCommand($commandCallable, string $url, ?string $cwd, bool $initialClone = false, &$commandOutput = null): void { + $commandCallables = is_callable($commandCallable) ? [$commandCallable] : $commandCallable; + $lastCommand = ''; + // Ensure we are allowed to use this URL by config $this->config->prohibitUrlByConfig($url, $this->io); if ($initialClone) { $origCwd = $cwd; - $cwd = null; } + $runCommands = function ($url) use ($commandCallables, $cwd, &$commandOutput, &$lastCommand, $initialClone) { + $collectOutputs = !is_callable($commandOutput); + $outputs = []; + + $status = 0; + $counter = 0; + foreach ($commandCallables as $callable) { + $lastCommand = $callable($url); + if ($collectOutputs) { + $outputs[] = ''; + $output = &$outputs[count($outputs) - 1]; + } else { + $output = &$commandOutput; + } + $status = $this->process->execute($lastCommand, $output, $initialClone && $counter === 0 ? null : $cwd); + if ($status !== 0) { + break; + } + $counter++; + } + + if ($collectOutputs) { + $commandOutput = implode('', $outputs); + } + + return $status; + }; + if (Preg::isMatch('{^ssh://[^@]+@[^:]+:[^0-9]+}', $url)) { throw new \InvalidArgumentException('The source URL ' . $url . ' is invalid, ssh URLs should have a port number after ":".' . "\n" . 'Use ssh://git@example.com:22/path or just git@example.com:path if you do not want to provide a password or custom port.'); } if (!$initialClone) { // capture username/password from URL if there is one and we have no auth configured yet - $this->process->execute('git remote -v', $output, $cwd); + $this->process->execute(['git', 'remote', '-v'], $output, $cwd); if (Preg::isMatchStrictGroups('{^(?:composer|origin)\s+https?://(.+):(.+)@([^/]+)}im', $output, $match) && !$this->io->hasAuthentication($match[3])) { $this->io->setAuthentication($match[3], rawurldecode($match[1]), rawurldecode($match[2])); } @@ -69,6 +154,7 @@ public function runCommand(callable $commandCallable, string $url, ?string $cwd, $protocols = $this->config->get('github-protocols'); // public github, autoswitch protocols + // @phpstan-ignore composerPcre.maybeUnsafeStrictGroups if (Preg::isMatchStrictGroups('{^(?:https?|git)://' . self::getGitHubDomainsRegex($this->config) . '/(.*)}', $url, $match)) { $messages = []; foreach ($protocols as $protocol) { @@ -78,7 +164,7 @@ public function runCommand(callable $commandCallable, string $url, ?string $cwd, $protoUrl = $protocol . "://" . $match[1] . "/" . $match[2]; } - if (0 === $this->process->execute($commandCallable($protoUrl), $commandOutput, $cwd)) { + if (0 === $runCommands($protoUrl)) { return; } $messages[] = '- ' . $protoUrl . "\n" . Preg::replace('#^#m', ' ', $this->process->getErrorOutput()); @@ -97,14 +183,14 @@ public function runCommand(callable $commandCallable, string $url, ?string $cwd, // if we have a private github url and the ssh protocol is disabled then we skip it and directly fallback to https $bypassSshForGitHub = Preg::isMatch('{^git@' . self::getGitHubDomainsRegex($this->config) . ':(.+?)\.git$}i', $url) && !in_array('ssh', $protocols, true); - $command = $commandCallable($url); - $auth = null; $credentials = []; - if ($bypassSshForGitHub || 0 !== $this->process->execute($command, $commandOutput, $cwd)) { + if ($bypassSshForGitHub || 0 !== $runCommands($url)) { $errorMsg = $this->process->getErrorOutput(); // private github repository without ssh key access, try https with auth + // @phpstan-ignore composerPcre.maybeUnsafeStrictGroups if (Preg::isMatchStrictGroups('{^git@' . self::getGitHubDomainsRegex($this->config) . ':(.+?)\.git$}i', $url, $match) + // @phpstan-ignore composerPcre.maybeUnsafeStrictGroups || Preg::isMatchStrictGroups('{^https?://' . self::getGitHubDomainsRegex($this->config) . '/(.*?)(?:\.git)?$}i', $url, $match) ) { if (!$this->io->hasAuthentication($match[1])) { @@ -119,60 +205,78 @@ public function runCommand(callable $commandCallable, string $url, ?string $cwd, if ($this->io->hasAuthentication($match[1])) { $auth = $this->io->getAuthentication($match[1]); $authUrl = 'https://' . rawurlencode($auth['username']) . ':' . rawurlencode($auth['password']) . '@' . $match[1] . '/' . $match[2] . '.git'; - $command = $commandCallable($authUrl); - if (0 === $this->process->execute($command, $commandOutput, $cwd)) { + if (0 === $runCommands($authUrl)) { return; } $credentials = [rawurlencode($auth['username']), rawurlencode($auth['password'])]; $errorMsg = $this->process->getErrorOutput(); } - } elseif (Preg::isMatchStrictGroups('{^https://(bitbucket\.org)/(.*?)(?:\.git)?$}i', $url, $match)) { //bitbucket oauth - $bitbucketUtil = new Bitbucket($this->io, $this->config, $this->process); - - if (!$this->io->hasAuthentication($match[1])) { + // @phpstan-ignore composerPcre.maybeUnsafeStrictGroups + } elseif ( + Preg::isMatchStrictGroups('{^(https?)://(bitbucket\.org)/(.*?)(?:\.git)?$}i', $url, $match) + || Preg::isMatchStrictGroups('{^(git)@(bitbucket\.org):(.+?\.git)$}i', $url, $match) + ) { //bitbucket either through oauth or app password, with fallback to ssh. + $bitbucketUtil = new Bitbucket($this->io, $this->config, $this->process, $this->httpDownloader); + + $domain = $match[2]; + $repo_with_git_part = $match[3]; + if (!str_ends_with($repo_with_git_part, '.git')) { + $repo_with_git_part .= '.git'; + } + if (!$this->io->hasAuthentication($domain)) { $message = 'Enter your Bitbucket credentials to access private repos'; - if (!$bitbucketUtil->authorizeOAuth($match[1]) && $this->io->isInteractive()) { - $bitbucketUtil->authorizeOAuthInteractively($match[1], $message); + if (!$bitbucketUtil->authorizeOAuth($domain) && $this->io->isInteractive()) { + $bitbucketUtil->authorizeOAuthInteractively($domain, $message); $accessToken = $bitbucketUtil->getToken(); - $this->io->setAuthentication($match[1], 'x-token-auth', $accessToken); + $this->io->setAuthentication($domain, 'x-token-auth', $accessToken); + } + } + + // First we try to authenticate with whatever we have stored. + // This will be successful if there is for example an app + // password in there. + if ($this->io->hasAuthentication($domain)) { + $auth = $this->io->getAuthentication($domain); + $authUrl = 'https://' . rawurlencode($auth['username']) . ':' . rawurlencode($auth['password']) . '@' . $domain . '/' . $repo_with_git_part; + + if (0 === $runCommands($authUrl)) { + // Well if that succeeded on our first try, let's just + // take the win. + return; } - } else { //We're authenticating with a locally stored consumer. - $auth = $this->io->getAuthentication($match[1]); //We already have an access_token from a previous request. if ($auth['username'] !== 'x-token-auth') { - $accessToken = $bitbucketUtil->requestToken($match[1], $auth['username'], $auth['password']); + $accessToken = $bitbucketUtil->requestToken($domain, $auth['username'], $auth['password']); if (!empty($accessToken)) { - $this->io->setAuthentication($match[1], 'x-token-auth', $accessToken); + $this->io->setAuthentication($domain, 'x-token-auth', $accessToken); } } } - if ($this->io->hasAuthentication($match[1])) { - $auth = $this->io->getAuthentication($match[1]); - $authUrl = 'https://' . rawurlencode($auth['username']) . ':' . rawurlencode($auth['password']) . '@' . $match[1] . '/' . $match[2] . '.git'; - - $command = $commandCallable($authUrl); - if (0 === $this->process->execute($command, $commandOutput, $cwd)) { + if ($this->io->hasAuthentication($domain)) { + $auth = $this->io->getAuthentication($domain); + $authUrl = 'https://' . rawurlencode($auth['username']) . ':' . rawurlencode($auth['password']) . '@' . $domain . '/' . $repo_with_git_part; + if (0 === $runCommands($authUrl)) { return; } $credentials = [rawurlencode($auth['username']), rawurlencode($auth['password'])]; - $errorMsg = $this->process->getErrorOutput(); - } else { // Falling back to ssh - $sshUrl = 'git@bitbucket.org:' . $match[2] . '.git'; - $this->io->writeError(' No bitbucket authentication configured. Falling back to ssh.'); - $command = $commandCallable($sshUrl); - if (0 === $this->process->execute($command, $commandOutput, $cwd)) { - return; - } - - $errorMsg = $this->process->getErrorOutput(); } + //Falling back to ssh + $sshUrl = 'git@bitbucket.org:' . $repo_with_git_part; + $this->io->writeError(' No bitbucket authentication configured. Falling back to ssh.'); + if (0 === $runCommands($sshUrl)) { + return; + } + + $errorMsg = $this->process->getErrorOutput(); } elseif ( + // @phpstan-ignore composerPcre.maybeUnsafeStrictGroups Preg::isMatchStrictGroups('{^(git)@' . self::getGitLabDomainsRegex($this->config) . ':(.+?\.git)$}i', $url, $match) + // @phpstan-ignore composerPcre.maybeUnsafeStrictGroups || Preg::isMatchStrictGroups('{^(https?)://' . self::getGitLabDomainsRegex($this->config) . '/(.*)}i', $url, $match) ) { if ($match[1] === 'git') { @@ -191,21 +295,20 @@ public function runCommand(callable $commandCallable, string $url, ?string $cwd, if ($this->io->hasAuthentication($match[2])) { $auth = $this->io->getAuthentication($match[2]); if ($auth['password'] === 'private-token' || $auth['password'] === 'oauth2' || $auth['password'] === 'gitlab-ci-token') { - $authUrl = $match[1] . '://' . rawurlencode($auth['password']) . ':' . rawurlencode($auth['username']) . '@' . $match[2] . '/' . $match[3]; // swap username and password + $authUrl = $match[1] . '://' . rawurlencode($auth['password']) . ':' . rawurlencode((string) $auth['username']) . '@' . $match[2] . '/' . $match[3]; // swap username and password } else { - $authUrl = $match[1] . '://' . rawurlencode($auth['username']) . ':' . rawurlencode($auth['password']) . '@' . $match[2] . '/' . $match[3]; + $authUrl = $match[1] . '://' . rawurlencode((string) $auth['username']) . ':' . rawurlencode((string) $auth['password']) . '@' . $match[2] . '/' . $match[3]; } - $command = $commandCallable($authUrl); - if (0 === $this->process->execute($command, $commandOutput, $cwd)) { + if (0 === $runCommands($authUrl)) { return; } - $credentials = [rawurlencode($auth['username']), rawurlencode($auth['password'])]; + $credentials = [rawurlencode((string) $auth['username']), rawurlencode((string) $auth['password'])]; $errorMsg = $this->process->getErrorOutput(); } - } elseif ($this->isAuthenticationFailure($url, $match)) { // private non-github/gitlab/bitbucket repo that failed to authenticate - if (strpos($match[2], '@')) { + } elseif (null !== ($match = $this->getAuthenticationFailure($url))) { // private non-github/gitlab/bitbucket repo that failed to authenticate + if (str_contains($match[2], '@')) { [$authParts, $match[2]] = explode('@', $match[2], 2); } @@ -214,8 +317,8 @@ public function runCommand(callable $commandCallable, string $url, ?string $cwd, $auth = $this->io->getAuthentication($match[2]); } elseif ($this->io->isInteractive()) { $defaultUsername = null; - if (isset($authParts) && $authParts) { - if (false !== strpos($authParts, ':')) { + if (isset($authParts) && $authParts !== '') { + if (str_contains($authParts, ':')) { [$defaultUsername, ] = explode(':', $authParts, 2); } else { $defaultUsername = $authParts; @@ -232,10 +335,9 @@ public function runCommand(callable $commandCallable, string $url, ?string $cwd, } if (null !== $auth) { - $authUrl = $match[1] . rawurlencode($auth['username']) . ':' . rawurlencode($auth['password']) . '@' . $match[2] . $match[3]; + $authUrl = $match[1] . rawurlencode((string) $auth['username']) . ':' . rawurlencode((string) $auth['password']) . '@' . $match[2] . $match[3]; - $command = $commandCallable($authUrl); - if (0 === $this->process->execute($command, $commandOutput, $cwd)) { + if (0 === $runCommands($authUrl)) { $this->io->setAuthentication($match[2], $auth['username'], $auth['password']); $authHelper = new AuthHelper($this->io, $this->config); $authHelper->storeAuth($match[2], $storeAuth); @@ -243,7 +345,7 @@ public function runCommand(callable $commandCallable, string $url, ?string $cwd, return; } - $credentials = [rawurlencode($auth['username']), rawurlencode($auth['password'])]; + $credentials = [rawurlencode((string) $auth['username']), rawurlencode((string) $auth['password'])]; $errorMsg = $this->process->getErrorOutput(); } } @@ -252,31 +354,34 @@ public function runCommand(callable $commandCallable, string $url, ?string $cwd, $this->filesystem->removeDirectory($origCwd); } + $lastCommand = implode(' ', $lastCommand); if (count($credentials) > 0) { - $command = $this->maskCredentials($command, $credentials); + $lastCommand = $this->maskCredentials($lastCommand, $credentials); $errorMsg = $this->maskCredentials($errorMsg, $credentials); } - $this->throwException('Failed to execute ' . $command . "\n\n" . $errorMsg, $url); + $this->throwException('Failed to execute ' . $lastCommand . "\n\n" . $errorMsg, $url); } } public function syncMirror(string $url, string $dir): bool { - if (Platform::getEnv('COMPOSER_DISABLE_NETWORK') && Platform::getEnv('COMPOSER_DISABLE_NETWORK') !== 'prime') { + if ((bool) Platform::getEnv('COMPOSER_DISABLE_NETWORK') && Platform::getEnv('COMPOSER_DISABLE_NETWORK') !== 'prime') { $this->io->writeError('Aborting git mirror sync of '.$url.' as network is disabled'); return false; } // update the repo if it is a valid git repository - if (is_dir($dir) && 0 === $this->process->execute('git rev-parse --git-dir', $output, $dir) && trim($output) === '.') { + if (is_dir($dir) && 0 === $this->process->execute(['git', 'rev-parse', '--git-dir'], $output, $dir) && trim($output) === '.') { try { - $commandCallable = static function ($url): string { - $sanitizedUrl = Preg::replace('{://([^@]+?):(.+?)@}', '://', $url); - - return sprintf('git remote set-url origin -- %s && git remote update --prune origin && git remote set-url origin -- %s && git gc --auto', ProcessExecutor::escape($url), ProcessExecutor::escape($sanitizedUrl)); - }; - $this->runCommand($commandCallable, $url, $dir); + $commands = [ + ['git', 'remote', 'set-url', 'origin', '--', '%url%'], + ['git', 'remote', 'update', '--prune', 'origin'], + ['git', 'remote', 'set-url', 'origin', '--', '%sanitizedUrl%'], + ['git', 'gc', '--auto'], + ]; + + $this->runCommands($commands, $url, $dir); } catch (\Exception $e) { $this->io->writeError('Sync mirror failed: ' . $e->getMessage() . '', true, IOInterface::DEBUG); @@ -285,15 +390,12 @@ public function syncMirror(string $url, string $dir): bool return true; } + self::checkForRepoOwnershipError($this->process->getErrorOutput(), $dir); // clean up directory and do a fresh clone into it $this->filesystem->removeDirectory($dir); - $commandCallable = static function ($url) use ($dir): string { - return sprintf('git clone --mirror -- %s %s', ProcessExecutor::escape($url), ProcessExecutor::escape($dir)); - }; - - $this->runCommand($commandCallable, $url, $dir, true); + $this->runCommands([['git', 'clone', '--mirror', '--', '%url%', $dir]], $url, $dir, true); return true; } @@ -305,10 +407,10 @@ public function fetchRefOrSyncMirror(string $url, string $dir, string $ref, ?str $branch = Preg::replace('{(?:^dev-|(?:\.x)?-dev$)}i', '', $prettyVersion); $branches = null; $tags = null; - if (0 === $this->process->execute('git branch', $output, $dir)) { + if (0 === $this->process->execute(['git', 'branch'], $output, $dir)) { $branches = $output; } - if (0 === $this->process->execute('git tag', $output, $dir)) { + if (0 === $this->process->execute(['git', 'tag'], $output, $dir)) { $tags = $output; } @@ -336,34 +438,46 @@ public function fetchRefOrSyncMirror(string $url, string $dir, string $ref, ?str public static function getNoShowSignatureFlag(ProcessExecutor $process): string { $gitVersion = self::getVersion($process); - if ($gitVersion && version_compare($gitVersion, '2.10.0-rc0', '>=')) { + if ($gitVersion !== null && version_compare($gitVersion, '2.10.0-rc0', '>=')) { return ' --no-show-signature'; } return ''; } + /** + * @return list + */ + public static function getNoShowSignatureFlags(ProcessExecutor $process): array + { + $flags = static::getNoShowSignatureFlag($process); + if ('' === $flags) { + return []; + } + + return explode(' ', substr($flags, 1)); + } + private function checkRefIsInMirror(string $dir, string $ref): bool { - if (is_dir($dir) && 0 === $this->process->execute('git rev-parse --git-dir', $output, $dir) && trim($output) === '.') { - $escapedRef = ProcessExecutor::escape($ref.'^{commit}'); - $exitCode = $this->process->execute(sprintf('git rev-parse --quiet --verify %s', $escapedRef), $ignoredOutput, $dir); + if (is_dir($dir) && 0 === $this->process->execute(['git', 'rev-parse', '--git-dir'], $output, $dir) && trim($output) === '.') { + $exitCode = $this->process->execute(['git', 'rev-parse', '--quiet', '--verify', $ref.'^{commit}'], $ignoredOutput, $dir); if ($exitCode === 0) { return true; } } + self::checkForRepoOwnershipError($this->process->getErrorOutput(), $dir); return false; } /** - * @param array $match - * @param-out array $match + * @return array|null */ - private function isAuthenticationFailure(string $url, array &$match): bool + private function getAuthenticationFailure(string $url): ?array { if (!Preg::isMatchStrictGroups('{^(https?://)([^/]+)(.*)$}i', $url, $match)) { - return false; + return null; } $authFailures = [ @@ -377,11 +491,11 @@ private function isAuthenticationFailure(string $url, array &$match): bool $errorOutput = $this->process->getErrorOutput(); foreach ($authFailures as $authFailure) { if (strpos($errorOutput, $authFailure) !== false) { - return true; + return $match; } } - return false; + return null; } public function getMirrorDefaultBranch(string $url, string $dir, bool $isLocalPathRepository): ?string @@ -392,20 +506,20 @@ public function getMirrorDefaultBranch(string $url, string $dir, bool $isLocalPa try { if ($isLocalPathRepository) { - $this->process->execute('git remote show origin', $output, $dir); + $this->process->execute(['git', 'remote', 'show', 'origin'], $output, $dir); } else { - $commandCallable = static function ($url): string { - $sanitizedUrl = Preg::replace('{://([^@]+?):(.+?)@}', '://', $url); - - return sprintf('git remote set-url origin -- %s && git remote show origin && git remote set-url origin -- %s', ProcessExecutor::escape($url), ProcessExecutor::escape($sanitizedUrl)); - }; + $commands = [ + ['git', 'remote', 'set-url', 'origin', '--', '%url%'], + ['git', 'remote', 'show', 'origin'], + ['git', 'remote', 'set-url', 'origin', '--', '%sanitizedUrl%'], + ]; - $this->runCommand($commandCallable, $url, $dir, false, $output); + $this->runCommands($commands, $url, $dir, false, $output); } $lines = $this->process->splitLines($output); foreach ($lines as $line) { - if (Preg::match('{^\s*HEAD branch:\s(.+)\s*$}m', $line, $matches) > 0) { + if (Preg::isMatch('{^\s*HEAD branch:\s(.+)\s*$}m', $line, $matches)) { return $matches[1]; } } @@ -418,9 +532,17 @@ public function getMirrorDefaultBranch(string $url, string $dir, bool $isLocalPa public static function cleanEnv(): void { - // added in git 1.7.1, prevents prompting the user for username/password - if (Platform::getEnv('GIT_ASKPASS') !== 'echo') { - Platform::putEnv('GIT_ASKPASS', 'echo'); + $gitVersion = self::getVersion(new ProcessExecutor()); + if ($gitVersion !== null && version_compare($gitVersion, '2.3.0', '>=')) { + // added in git 2.3.0, prevents prompting the user for username/password + if (Platform::getEnv('GIT_TERMINAL_PROMPT') !== '0') { + Platform::putEnv('GIT_TERMINAL_PROMPT', '0'); + } + } else { + // added in git 1.7.1, prevents prompting the user for username/password + if (Platform::getEnv('GIT_ASKPASS') !== 'echo') { + Platform::putEnv('GIT_ASKPASS', 'echo'); + } } // clean up rogue git env vars in case this is running in a git hook @@ -466,7 +588,7 @@ private function throwException($message, string $url): void // git might delete a directory when it fails and php will not know clearstatcache(); - if (0 !== $this->process->execute('git --version', $ignoredOutput)) { + if (0 !== $this->process->execute(['git', '--version'], $ignoredOutput)) { throw new \RuntimeException(Url::sanitize('Failed to clone ' . $url . ', git was not found, check that it is installed and in your PATH env.' . "\n\n" . $this->process->getErrorOutput())); } @@ -482,7 +604,7 @@ public static function getVersion(ProcessExecutor $process): ?string { if (false === self::$version) { self::$version = null; - if (0 === $process->execute('git --version', $output) && Preg::isMatch('/^git version (\d+(?:\.\d+)+)/m', $output, $matches)) { + if (0 === $process->execute(['git', '--version'], $output) && Preg::isMatch('/^git version (\d+(?:\.\d+)+)/m', $output, $matches)) { self::$version = $matches[1]; } } diff --git a/app/vendor/composer/composer/src/Composer/Util/GitHub.php b/app/vendor/composer/composer/src/Composer/Util/GitHub.php index 3574e5183..64ee4f559 100644 --- a/app/vendor/composer/composer/src/Composer/Util/GitHub.php +++ b/app/vendor/composer/composer/src/Composer/Util/GitHub.php @@ -61,7 +61,7 @@ public function authorizeOAuth(string $originUrl): bool } // if available use token from git config - if (0 === $this->process->execute('git config github.accesstoken', $output)) { + if (0 === $this->process->execute(['git', 'config', 'github.accesstoken'], $output)) { $this->io->setAuthentication($originUrl, trim($output), 'x-oauth-basic'); return true; @@ -86,7 +86,7 @@ public function authorizeOAuthInteractively(string $originUrl, ?string $message } $note = 'Composer'; - if ($this->config->get('github-expose-hostname') === true && 0 === $this->process->execute('hostname', $output)) { + if ($this->config->get('github-expose-hostname') === true && 0 === $this->process->execute(['hostname'], $output)) { $note .= ' on ' . trim($output); } $note .= ' ' . date('Y-m-d Hi'); diff --git a/app/vendor/composer/composer/src/Composer/Util/GitLab.php b/app/vendor/composer/composer/src/Composer/Util/GitLab.php index e5985c2db..b727dd91b 100644 --- a/app/vendor/composer/composer/src/Composer/Util/GitLab.php +++ b/app/vendor/composer/composer/src/Composer/Util/GitLab.php @@ -65,14 +65,14 @@ public function authorizeOAuth(string $originUrl): bool } // if available use token from git config - if (0 === $this->process->execute('git config gitlab.accesstoken', $output)) { + if (0 === $this->process->execute(['git', 'config', 'gitlab.accesstoken'], $output)) { $this->io->setAuthentication($originUrl, trim($output), 'oauth2'); return true; } // if available use deploy token from git config - if (0 === $this->process->execute('git config gitlab.deploytoken.user', $tokenUser) && 0 === $this->process->execute('git config gitlab.deploytoken.token', $tokenPassword)) { + if (0 === $this->process->execute(['git', 'config', 'gitlab.deploytoken.user'], $tokenUser) && 0 === $this->process->execute(['git', 'config', 'gitlab.deploytoken.token'], $tokenPassword)) { $this->io->setAuthentication($originUrl, trim($tokenUser), trim($tokenPassword)); return true; @@ -126,8 +126,8 @@ public function authorizeOAuthInteractively(string $scheme, string $originUrl, ? } $localAuthConfig = $this->config->getLocalAuthConfigSource(); - $personalAccessTokenLink = $scheme.'://'.$originUrl.'/-/profile/personal_access_tokens'; - $revokeLink = $scheme.'://'.$originUrl.'/-/profile/applications'; + $personalAccessTokenLink = $scheme.'://'.$originUrl.'/-/user_settings/personal_access_tokens'; + $revokeLink = $scheme.'://'.$originUrl.'/-/user_settings/applications'; $this->io->writeError(sprintf('A token will be created and stored in "%s", your password will never be stored', ($localAuthConfig !== null ? $localAuthConfig->getName() . ' OR ' : '') . $this->config->getAuthConfigSource()->getName())); $this->io->writeError('To revoke access to this token you can visit:'); $this->io->writeError($revokeLink); @@ -163,7 +163,7 @@ public function authorizeOAuthInteractively(string $scheme, string $originUrl, ? } $this->io->writeError('You can also manually create a personal access token enabling the "read_api" scope at:'); - $this->io->writeError($scheme.'://'.$originUrl.'/profile/personal_access_tokens'); + $this->io->writeError($personalAccessTokenLink); $this->io->writeError('Add it using "composer config --global --auth gitlab-token.'.$originUrl.' "'); continue; @@ -312,7 +312,7 @@ private function refreshToken(string $scheme, string $originUrl): array $token = $this->httpDownloader->get($scheme.'://'.$originUrl.'/oauth/token', $options)->decodeJson(); $this->io->writeError('GitLab token successfully refreshed', true, IOInterface::VERY_VERBOSE); - $this->io->writeError('To revoke access to this token you can visit '.$scheme.'://'.$originUrl.'/-/profile/applications', true, IOInterface::VERY_VERBOSE); + $this->io->writeError('To revoke access to this token you can visit '.$scheme.'://'.$originUrl.'/-/user_settings/applications', true, IOInterface::VERY_VERBOSE); return $token; } diff --git a/app/vendor/composer/composer/src/Composer/Util/Hg.php b/app/vendor/composer/composer/src/Composer/Util/Hg.php index c687542e0..34b4796fa 100644 --- a/app/vendor/composer/composer/src/Composer/Util/Hg.php +++ b/app/vendor/composer/composer/src/Composer/Util/Hg.php @@ -60,17 +60,17 @@ public function runCommand(callable $commandCallable, string $url, ?string $cwd) // Try with the authentication information available if ( Preg::isMatch('{^(?Pssh|https?)://(?:(?P[^:@]+)(?::(?P[^:@]+))?@)?(?P[^/]+)(?P/.*)?}mi', $url, $matches) - && $this->io->hasAuthentication((string) $matches['host']) + && $this->io->hasAuthentication($matches['host']) ) { if ($matches['proto'] === 'ssh') { $user = ''; - if ($matches['user'] !== '' && $matches['user'] !== null) { + if ($matches['user'] !== null) { $user = rawurlencode($matches['user']) . '@'; } $authenticatedUrl = $matches['proto'] . '://' . $user . $matches['host'] . $matches['path']; } else { - $auth = $this->io->getAuthentication((string) $matches['host']); - $authenticatedUrl = $matches['proto'] . '://' . rawurlencode($auth['username']) . ':' . rawurlencode($auth['password']) . '@' . $matches['host'] . $matches['path']; + $auth = $this->io->getAuthentication($matches['host']); + $authenticatedUrl = $matches['proto'] . '://' . rawurlencode((string) $auth['username']) . ':' . rawurlencode((string) $auth['password']) . '@' . $matches['host'] . $matches['path']; } $command = $commandCallable($authenticatedUrl); @@ -111,7 +111,7 @@ public static function getVersion(ProcessExecutor $process): ?string { if (false === self::$version) { self::$version = null; - if (0 === $process->execute('hg --version', $output) && Preg::isMatch('/^.+? (\d+(?:\.\d+)+)(?:\+.*?)?\)?\r?\n/', $output, $matches)) { + if (0 === $process->execute(['hg', '--version'], $output) && Preg::isMatch('/^.+? (\d+(?:\.\d+)+)(?:\+.*?)?\)?\r?\n/', $output, $matches)) { self::$version = $matches[1]; } } diff --git a/app/vendor/composer/composer/src/Composer/Util/Http/CurlDownloader.php b/app/vendor/composer/composer/src/Composer/Util/Http/CurlDownloader.php index 827d2a369..0216597d2 100644 --- a/app/vendor/composer/composer/src/Composer/Util/Http/CurlDownloader.php +++ b/app/vendor/composer/composer/src/Composer/Util/Http/CurlDownloader.php @@ -34,9 +34,17 @@ */ class CurlDownloader { - /** @var ?resource */ + /** + * Known libcurl's broken versions when proxy is in use with HTTP/2 + * multiplexing. + * + * @var list + */ + private const BAD_MULTIPLEXING_CURL_VERSIONS = ['7.87.0', '7.88.0', '7.88.1']; + + /** @var \CurlMultiHandle */ private $multiHandle; - /** @var ?resource */ + /** @var \CurlShareHandle */ private $shareHandle; /** @var Job[] */ private $jobs = []; @@ -99,7 +107,18 @@ public function __construct(IOInterface $io, Config $config, array $options = [] $this->multiHandle = $mh = curl_multi_init(); if (function_exists('curl_multi_setopt')) { - curl_multi_setopt($mh, CURLMOPT_PIPELINING, PHP_VERSION_ID >= 70400 ? /* CURLPIPE_MULTIPLEX */ 2 : /*CURLPIPE_HTTP1 | CURLPIPE_MULTIPLEX*/ 3); + if (ProxyManager::getInstance()->hasProxy() && ($version = curl_version()) !== false && in_array($version['version'], self::BAD_MULTIPLEXING_CURL_VERSIONS, true)) { + /** + * Disable HTTP/2 multiplexing for some broken versions of libcurl. + * + * In certain versions of libcurl when proxy is in use with HTTP/2 + * multiplexing, connections will continue stacking up. This was + * fixed in libcurl 8.0.0 in curl/curl@821f6e2a89de8aec1c7da3c0f381b92b2b801efc + */ + curl_multi_setopt($mh, CURLMOPT_PIPELINING, /* CURLPIPE_NOTHING */ 0); + } else { + curl_multi_setopt($mh, CURLMOPT_PIPELINING, \PHP_VERSION_ID >= 70400 ? /* CURLPIPE_MULTIPLEX */ 2 : /*CURLPIPE_HTTP1 | CURLPIPE_MULTIPLEX*/ 3); + } if (defined('CURLMOPT_MAX_HOST_CONNECTIONS') && !defined('HHVM_VERSION')) { curl_multi_setopt($mh, CURLMOPT_MAX_HOST_CONNECTIONS, 8); } @@ -176,12 +195,13 @@ private function initDownload(callable $resolve, callable $reject, string $origi } $errorMessage = ''; - // @phpstan-ignore-next-line - set_error_handler(static function ($code, $msg) use (&$errorMessage): void { + set_error_handler(static function (int $code, string $msg) use (&$errorMessage): bool { if ($errorMessage) { $errorMessage .= "\n"; } $errorMessage .= Preg::replace('{^fopen\(.*?\): }', '', $msg); + + return true; }); $bodyHandle = fopen($bodyTarget, 'w+b'); restore_error_handler(); @@ -362,7 +382,7 @@ public function tick(): void continue; } - if ($errno === 28 /* CURLE_OPERATION_TIMEDOUT */ && PHP_VERSION_ID >= 70300 && $progress['namelookup_time'] === 0.0 && !$timeoutWarning) { + if ($errno === 28 /* CURLE_OPERATION_TIMEDOUT */ && \PHP_VERSION_ID >= 70300 && $progress['namelookup_time'] === 0.0 && !$timeoutWarning) { $timeoutWarning = true; $this->io->writeError('A connection timeout was encountered. If you intend to run Composer without connecting to the internet, run the command again prefixed with COMPOSER_DISABLE_NETWORK=1 to make Composer run in offline mode.'); } @@ -406,7 +426,7 @@ public function tick(): void } fclose($job['bodyHandle']); - if ($response->getStatusCode() >= 400 && $response->getHeader('content-type') === 'application/json') { + if ($response->getStatusCode() >= 300 && $response->getHeader('content-type') === 'application/json') { HttpDownloader::outputWarnings($this->io, $job['origin'], json_decode($response->getBody(), true)); } @@ -492,7 +512,7 @@ public function tick(): void is_callable($this->jobs[$i]['options']['prevent_ip_access_callable']) && $this->jobs[$i]['options']['prevent_ip_access_callable']($progress['primary_ip']) ) { - throw new TransportException(sprintf('IP "%s" is blocked for "%s".', $progress['primary_ip'], $progress['url'])); + $this->rejectJob($this->jobs[$i], new TransportException(sprintf('IP "%s" is blocked for "%s".', $progress['primary_ip'], $progress['url']))); } $this->jobs[$i]['primaryIp'] = (string) $progress['primary_ip']; diff --git a/app/vendor/composer/composer/src/Composer/Util/Http/ProxyManager.php b/app/vendor/composer/composer/src/Composer/Util/Http/ProxyManager.php index 0571780fe..3747cedaa 100644 --- a/app/vendor/composer/composer/src/Composer/Util/Http/ProxyManager.php +++ b/app/vendor/composer/composer/src/Composer/Util/Http/ProxyManager.php @@ -33,20 +33,8 @@ class ProxyManager /** @var ?self */ private static $instance = null; - /** The following 3 properties can be removed after the transition period */ - - /** @var bool */ - private $ignoreHttpsProxy = false; - /** @var bool */ - private $isTransitional = false; - /** @var bool */ - private $needsTransitionWarning = false; - private function __construct() { - // this can be removed after the transition period - $this->isTransitional = true; - try { $this->getProxyData(); } catch (\RuntimeException $e) { @@ -71,6 +59,11 @@ public static function reset(): void self::$instance = null; } + public function hasProxy(): bool + { + return $this->httpProxy !== null || $this->httpsProxy !== null; + } + /** * Returns a RequestProxy instance for the request url * @@ -96,16 +89,6 @@ public function getProxyForRequest(string $requestUrl): RequestProxy return $proxy->toRequestProxy($scheme); } - /** - * Returns true if the user needs to set an https_proxy environment variable - * - * This method can be removed after the transition period - */ - public function needsTransitionWarning(): bool - { - return $this->needsTransitionWarning; - } - /** * Returns a ProxyItem if one is set for the scheme, otherwise null */ @@ -116,15 +99,6 @@ private function getProxyForScheme(string $scheme): ?ProxyItem } if ($scheme === 'https') { - // this can be removed after the transition period - if ($this->isTransitional && $this->httpsProxy === null) { - if ($this->httpProxy !== null && !$this->ignoreHttpsProxy) { - $this->needsTransitionWarning = true; - - return $this->httpProxy; - } - } - return $this->httpsProxy; } @@ -179,11 +153,6 @@ private function getProxyEnv(string $envName): array if ($_SERVER[$name] !== '') { return [$_SERVER[$name], $name]; } - // this can be removed after the transition period - if ($this->isTransitional && strtolower($name) === 'https_proxy') { - $this->ignoreHttpsProxy = true; - break; - } } } diff --git a/app/vendor/composer/composer/src/Composer/Util/Http/Response.php b/app/vendor/composer/composer/src/Composer/Util/Http/Response.php index 5e5d18a2e..e355f256a 100644 --- a/app/vendor/composer/composer/src/Composer/Util/Http/Response.php +++ b/app/vendor/composer/composer/src/Composer/Util/Http/Response.php @@ -36,7 +36,7 @@ class Response */ public function __construct(array $request, ?int $code, array $headers, ?string $body) { - if (!isset($request['url'])) { // @phpstan-ignore-line + if (!isset($request['url'])) { throw new \LogicException('url key missing from request array'); } $this->request = $request; @@ -101,8 +101,7 @@ public function decodeJson() */ public function collect(): void { - /** @phpstan-ignore-next-line */ - $this->request = $this->code = $this->headers = $this->body = null; + unset($this->request, $this->code, $this->headers, $this->body); } /** diff --git a/app/vendor/composer/composer/src/Composer/Util/Perforce.php b/app/vendor/composer/composer/src/Composer/Util/Perforce.php index d24209a42..bfed834b1 100644 --- a/app/vendor/composer/composer/src/Composer/Util/Perforce.php +++ b/app/vendor/composer/composer/src/Composer/Util/Perforce.php @@ -14,6 +14,7 @@ use Composer\IO\IOInterface; use Composer\Pcre\Preg; +use Symfony\Component\Process\ExecutableFinder; use Symfony\Component\Process\Process; /** @@ -81,7 +82,7 @@ public static function create($repoConfig, string $port, string $path, ProcessEx public static function checkServerExists(string $url, ProcessExecutor $processExecutor): bool { - return 0 === $processExecutor->execute('p4 -p ' . ProcessExecutor::escape($url) . ' info -s', $ignoredOutput); + return 0 === $processExecutor->execute(['p4', '-p', $url, 'info', '-s'], $ignoredOutput); } /** @@ -248,7 +249,7 @@ public function queryP4User(): void } $this->p4User = $this->io->ask('Enter P4 User:'); if ($this->windowsFlag) { - $command = 'p4 set P4USER=' . $this->p4User; + $command = $this->getP4Executable().' set P4USER=' . $this->p4User; } else { $command = 'export P4USER=' . $this->p4User; } @@ -261,7 +262,7 @@ public function queryP4User(): void protected function getP4variable(string $name): ?string { if ($this->windowsFlag) { - $command = 'p4 set'; + $command = $this->getP4Executable().' set'; $this->executeCommand($command); $result = trim($this->commandResult); $resArray = explode(PHP_EOL, $result); @@ -309,7 +310,7 @@ public function queryP4Password(): ?string */ public function generateP4Command(string $command, bool $useClient = true): string { - $p4Command = 'p4 '; + $p4Command = $this->getP4Executable().' '; $p4Command .= '-u ' . $this->getUser() . ' '; if ($useClient) { $p4Command .= '-c ' . $this->getClient() . ' '; @@ -342,7 +343,7 @@ public function isLoggedIn(): bool public function connectClient(): void { $p4CreateClientCommand = $this->generateP4Command( - 'client -i < ' . str_replace(" ", "\\ ", $this->getP4ClientSpec()) + 'client -i < ' . ProcessExecutor::escape($this->getP4ClientSpec()) ); $this->executeCommand($p4CreateClientCommand); } @@ -620,4 +621,17 @@ public function setFilesystem(Filesystem $fs): void { $this->filesystem = $fs; } + + private function getP4Executable(): string + { + static $p4Executable; + + if ($p4Executable) { + return $p4Executable; + } + + $finder = new ExecutableFinder(); + + return $p4Executable = $finder->find('p4') ?? 'p4'; + } } diff --git a/app/vendor/composer/composer/src/Composer/Util/Platform.php b/app/vendor/composer/composer/src/Composer/Util/Platform.php index 45060c85c..85ab6d9d9 100644 --- a/app/vendor/composer/composer/src/Composer/Util/Platform.php +++ b/app/vendor/composer/composer/src/Composer/Util/Platform.php @@ -25,6 +25,8 @@ class Platform private static $isVirtualBoxGuest = null; /** @var ?bool */ private static $isWindowsSubsystemForLinux = null; + /** @var ?bool */ + private static $isDocker = null; /** * getcwd() equivalent which always returns a string @@ -52,6 +54,19 @@ public static function getCwd(bool $allowEmpty = false): string return $cwd; } + /** + * Infallible realpath version that falls back on the given $path if realpath is not working + */ + public static function realpath(string $path): string + { + $realPath = realpath($path); + if ($realPath === false) { + return $path; + } + + return $realPath; + } + /** * getenv() equivalent but reads from the runtime global variables first * @@ -76,7 +91,6 @@ public static function getEnv(string $name) */ public static function putEnv(string $name, string $value): void { - $value = (string) $value; putenv($name . '=' . $value); $_SERVER[$name] = $_ENV[$name] = $value; } @@ -100,12 +114,12 @@ public static function expandPath(string $path): string } return Preg::replaceCallback('#^(\$|(?P%))(?P\w++)(?(percent)%)(?P.*)#', static function ($matches): string { - assert(is_string($matches['var'])); - assert('' !== $matches['var']); - // Treat HOME as an alias for USERPROFILE on Windows for legacy reasons if (Platform::isWindows() && $matches['var'] === 'HOME') { - return (Platform::getEnv('HOME') ?: Platform::getEnv('USERPROFILE')) . $matches['path']; + if ((bool) Platform::getEnv('HOME')) { + return Platform::getEnv('HOME') . $matches['path']; + } + return Platform::getEnv('USERPROFILE') . $matches['path']; } return Platform::getEnv($matches['var']) . $matches['path']; @@ -129,7 +143,9 @@ public static function getUserDirectory(): string if (\function_exists('posix_getuid') && \function_exists('posix_getpwuid')) { $info = posix_getpwuid(posix_getuid()); - return $info['dir']; + if (is_array($info)) { + return $info['dir']; + } } throw new \RuntimeException('Could not determine user directory'); @@ -149,12 +165,10 @@ public static function isWindowsSubsystemForLinux(): bool } if ( - !ini_get('open_basedir') + !(bool) ini_get('open_basedir') && is_readable('/proc/version') && false !== stripos((string)Silencer::call('file_get_contents', '/proc/version'), 'microsoft') - && !file_exists('/.dockerenv') // Docker and Podman running inside WSL should not be seen as WSL - && !file_exists('/run/.containerenv') - && !file_exists('/var/run/.containerenv') + && !self::isDocker() // Docker and Podman running inside WSL should not be seen as WSL ) { return self::$isWindowsSubsystemForLinux = true; } @@ -171,6 +185,50 @@ public static function isWindows(): bool return \defined('PHP_WINDOWS_VERSION_BUILD'); } + public static function isDocker(): bool + { + if (null !== self::$isDocker) { + return self::$isDocker; + } + + // cannot check so assume no + if ((bool) ini_get('open_basedir')) { + return self::$isDocker = false; + } + + // .dockerenv and .containerenv are present in some cases but not reliably + if (file_exists('/.dockerenv') || file_exists('/run/.containerenv') || file_exists('/var/run/.containerenv')) { + return self::$isDocker = true; + } + + // see https://www.baeldung.com/linux/is-process-running-inside-container + $cgroups = [ + '/proc/self/mountinfo', // cgroup v2 + '/proc/1/cgroup', // cgroup v1 + ]; + foreach ($cgroups as $cgroup) { + if (!is_readable($cgroup)) { + continue; + } + // suppress errors as some environments have these files as readable but system restrictions prevent the read from succeeding + // see https://github.com/composer/composer/issues/12095 + try { + $data = @file_get_contents($cgroup); + } catch (\Throwable $e) { + break; + } + if (!is_string($data)) { + continue; + } + // detect default mount points created by Docker/containerd + if (str_contains($data, '/var/lib/docker/') || str_contains($data, '/io.containerd.snapshotter')) { + return self::$isDocker = true; + } + } + + return self::$isDocker = false; + } + /** * @return int return a guaranteed binary length of the string, regardless of silly mbstring configs */ @@ -178,7 +236,7 @@ public static function strlen(string $str): int { static $useMbString = null; if (null === $useMbString) { - $useMbString = \function_exists('mb_strlen') && ini_get('mbstring.func_overload'); + $useMbString = \function_exists('mb_strlen') && (bool) ini_get('mbstring.func_overload'); } if ($useMbString) { @@ -202,7 +260,7 @@ public static function isTty($fd = null): bool // detect msysgit/mingw and assume this is a tty because detection // does not work correctly, see https://github.com/composer/composer/issues/9690 - if (in_array(strtoupper(self::getEnv('MSYSTEM') ?: ''), ['MINGW32', 'MINGW64'], true)) { + if (in_array(strtoupper((string) self::getEnv('MSYSTEM')), ['MINGW32', 'MINGW64'], true)) { return true; } @@ -218,8 +276,11 @@ public static function isTty($fd = null): bool } $stat = @fstat($fd); + if ($stat === false) { + return false; + } // Check if formatted mode is S_IFCHR - return $stat ? 0020000 === ($stat['mode'] & 0170000) : false; + return 0020000 === ($stat['mode'] & 0170000); } /** @@ -252,7 +313,7 @@ private static function isVirtualBoxGuest(): bool if (function_exists('posix_getpwuid') && function_exists('posix_geteuid')) { $processUser = posix_getpwuid(posix_geteuid()); - if ($processUser && $processUser['name'] === 'vagrant') { + if (is_array($processUser) && $processUser['name'] === 'vagrant') { return self::$isVirtualBoxGuest = true; } } @@ -264,7 +325,7 @@ private static function isVirtualBoxGuest(): bool if (defined('PHP_OS_FAMILY') && PHP_OS_FAMILY === 'Linux') { $process = new ProcessExecutor(); try { - if (0 === $process->execute('lsmod | grep vboxguest', $ignoredOutput)) { + if (0 === $process->execute(['lsmod'], $output) && str_contains($output, 'vboxguest')) { return self::$isVirtualBoxGuest = true; } } catch (\Exception $e) { diff --git a/app/vendor/composer/composer/src/Composer/Util/ProcessExecutor.php b/app/vendor/composer/composer/src/Composer/Util/ProcessExecutor.php index 25e4c903b..11db709ee 100644 --- a/app/vendor/composer/composer/src/Composer/Util/ProcessExecutor.php +++ b/app/vendor/composer/composer/src/Composer/Util/ProcessExecutor.php @@ -20,6 +20,7 @@ use Symfony\Component\Process\Exception\RuntimeException; use React\Promise\Promise; use React\Promise\PromiseInterface; +use Symfony\Component\Process\ExecutableFinder; /** * @author Robert Schönthal @@ -33,6 +34,21 @@ class ProcessExecutor private const STATUS_FAILED = 4; private const STATUS_ABORTED = 5; + private const BUILTIN_CMD_COMMANDS = [ + 'assoc', 'break', 'call', 'cd', 'chdir', 'cls', 'color', 'copy', 'date', + 'del', 'dir', 'echo', 'endlocal', 'erase', 'exit', 'for', 'ftype', 'goto', + 'help', 'if', 'label', 'md', 'mkdir', 'mklink', 'move', 'path', 'pause', + 'popd', 'prompt', 'pushd', 'rd', 'rem', 'ren', 'rename', 'rmdir', 'set', + 'setlocal', 'shift', 'start', 'time', 'title', 'type', 'ver', 'vol', + ]; + + private const GIT_CMDS_NEED_GIT_DIR = [ + ['show'], + ['log'], + ['branch'], + ['remote', 'set-url'] + ]; + /** @var int */ protected static $timeout = 300; @@ -56,15 +72,19 @@ class ProcessExecutor /** @var bool */ private $allowAsync = false; + /** @var array */ + private static $executables = []; + public function __construct(?IOInterface $io = null) { $this->io = $io; + $this->resetMaxJobs(); } /** * runs a process on the commandline * - * @param string|list $command the command to execute + * @param string|non-empty-list $command the command to execute * @param mixed $output the output will be written into this var if passed by ref * if a callable is passed it will be used as output handler * @param null|string $cwd the working directory @@ -82,7 +102,7 @@ public function execute($command, &$output = null, ?string $cwd = null): int /** * runs a process on the commandline in TTY mode * - * @param string|list $command the command to execute + * @param string|non-empty-list $command the command to execute * @param null|string $cwd the working directory * @return int statuscode */ @@ -96,23 +116,30 @@ public function executeTty($command, ?string $cwd = null): int } /** - * @param string|list $command + * @param string|non-empty-list $command + * @param array|null $env * @param mixed $output */ - private function doExecute($command, ?string $cwd, bool $tty, &$output = null): int + private function runProcess($command, ?string $cwd, ?array $env, bool $tty, &$output = null): ?int { - $this->outputCommandRun($command, $cwd, false); - - $this->captureOutput = func_num_args() > 3; - $this->errorOutput = ''; + // On Windows, we don't rely on the OS to find the executable if possible to avoid lookups + // in the current directory which could be untrusted. Instead we use the ExecutableFinder. if (is_string($command)) { - $process = Process::fromShellCommandline($command, $cwd, null, null, static::getTimeout()); + if (Platform::isWindows() && Preg::isMatch('{^([^:/\\\\]++) }', $command, $match)) { + $command = substr_replace($command, self::escape(self::getExecutable($match[1])), 0, strlen($match[1])); + } + + $process = Process::fromShellCommandline($command, $cwd, $env, null, static::getTimeout()); } else { - $process = new Process($command, $cwd, null, null, static::getTimeout()); + if (Platform::isWindows() && \strlen($command[0]) === strcspn($command[0], ':/\\')) { + $command[0] = self::getExecutable($command[0]); + } + + $process = new Process($command, $cwd, $env, null, static::getTimeout()); } - if (!Platform::isWindows() && $tty) { + if (! Platform::isWindows() && $tty) { try { $process->setTty(true); } catch (RuntimeException $e) { @@ -124,11 +151,18 @@ private function doExecute($command, ?string $cwd, bool $tty, &$output = null): $this->outputHandler($type, $buffer); }; - $signalHandler = SignalHandler::create([SignalHandler::SIGINT, SignalHandler::SIGTERM, SignalHandler::SIGHUP], function (string $signal) { - if ($this->io !== null) { - $this->io->writeError('Received '.$signal.', aborting when child process is done', true, IOInterface::DEBUG); + $signalHandler = SignalHandler::create( + [SignalHandler::SIGINT, SignalHandler::SIGTERM, SignalHandler::SIGHUP], + function (string $signal) { + if ($this->io !== null) { + $this->io->writeError( + 'Received '.$signal.', aborting when child process is done', + true, + IOInterface::DEBUG + ); + } } - }); + ); try { $process->run($callback); @@ -150,6 +184,35 @@ private function doExecute($command, ?string $cwd, bool $tty, &$output = null): return $process->getExitCode(); } + /** + * @param string|non-empty-list $command + * @param mixed $output + */ + private function doExecute($command, ?string $cwd, bool $tty, &$output = null): int + { + $this->outputCommandRun($command, $cwd, false); + + $this->captureOutput = func_num_args() > 3; + $this->errorOutput = ''; + + $env = null; + + $requiresGitDirEnv = $this->requiresGitDirEnv($command); + if ($cwd !== null && $requiresGitDirEnv) { + $isBareRepository = !is_dir(sprintf('%s/.git', rtrim($cwd, '/'))); + if ($isBareRepository) { + $configValue = ''; + $this->runProcess(['git', 'config', 'safe.bareRepository'], $cwd, ['GIT_DIR' => $cwd], $tty, $configValue); + $configValue = trim($configValue); + if ($configValue === 'explicit') { + $env = ['GIT_DIR' => $cwd]; + } + } + } + + return $this->runProcess($command, $cwd, $env, $tty, $output); + } + /** * starts a process on the commandline in async mode * @@ -288,7 +351,11 @@ public function setMaxJobs(int $maxJobs): void public function resetMaxJobs(): void { - $this->maxJobs = 10; + if (is_numeric($maxJobs = Platform::getEnv('COMPOSER_MAX_PARALLEL_PROCESSES'))) { + $this->maxJobs = max(1, min(50, (int) $maxJobs)); + } else { + $this->maxJobs = 10; + } } /** @@ -416,8 +483,6 @@ private function outputCommandRun($command, ?string $cwd, bool $async): void $commandString = is_string($command) ? $command : implode(' ', array_map(self::class.'::escape', $command)); $safeCommand = Preg::replaceCallback('{://(?P[^:/\s]+):(?P[^@\s/]+)@}i', static function ($m): string { - assert(is_string($m['user'])); - // if the username looks like a long (12char+) hex string, or a modern github token (e.g. ghp_xxx) we obfuscate that if (Preg::isMatch('{^([a-f0-9]{12,}|gh[a-z]_[a-zA-Z0-9_]+)$}', $m['user'])) { return '://***:***@'; @@ -456,7 +521,23 @@ private static function escapeArgument($argument): string } // New lines break cmd.exe command parsing - $argument = strtr($argument, "\n", ' '); + // and special chars like the fullwidth quote can be used to break out + // of parameter encoding via "Best Fit" encoding conversion + $argument = strtr($argument, [ + "\n" => ' ', + "\u{ff02}" => '"', + "\u{02ba}" => '"', + "\u{301d}" => '"', + "\u{301e}" => '"', + "\u{030e}" => '"', + "\u{ff1a}" => ':', + "\u{0589}" => ':', + "\u{2236}" => ':', + "\u{ff0f}" => '/', + "\u{2044}" => '/', + "\u{2215}" => '/', + "\u{00b4}" => '/', + ]); // In addition to whitespace, commas need quoting to preserve paths $quote = strpbrk($argument, " \t,") !== false; @@ -478,4 +559,42 @@ private static function escapeArgument($argument): string return $argument; } + + /** + * @param string[]|string $command + */ + public function requiresGitDirEnv($command): bool + { + $cmd = !is_array($command) ? explode(' ', $command) : $command; + if ($cmd[0] !== 'git') { + return false; + } + + foreach (self::GIT_CMDS_NEED_GIT_DIR as $gitCmd) { + if (array_intersect($cmd, $gitCmd) === $gitCmd) { + return true; + } + } + + return false; + } + + /** + * Resolves executable paths on Windows + */ + private static function getExecutable(string $name): string + { + if (\in_array(strtolower($name), self::BUILTIN_CMD_COMMANDS, true)) { + return $name; + } + + if (!isset(self::$executables[$name])) { + $path = (new ExecutableFinder())->find($name, $name); + if ($path !== null) { + self::$executables[$name] = $path; + } + } + + return self::$executables[$name] ?? $name; + } } diff --git a/app/vendor/composer/composer/src/Composer/Util/RemoteFilesystem.php b/app/vendor/composer/composer/src/Composer/Util/RemoteFilesystem.php index 560ef35db..f22bf9856 100644 --- a/app/vendor/composer/composer/src/Composer/Util/RemoteFilesystem.php +++ b/app/vendor/composer/composer/src/Composer/Util/RemoteFilesystem.php @@ -12,6 +12,7 @@ namespace Composer\Util; +use Closure; use Composer\Config; use Composer\Downloader\MaxFileSizeExceededException; use Composer\IO\IOInterface; @@ -271,7 +272,7 @@ protected function get(string $originUrl, string $fileUrl, array $additionalOpti unset($options['max_file_size']); } - $ctx = StreamContextFactory::getContext($fileUrl, $options, ['notification' => [$this, 'callbackGet']]); + $ctx = StreamContextFactory::getContext($fileUrl, $options, ['notification' => Closure::fromCallable([$this, 'callbackGet'])]); $proxy = ProxyManager::getInstance()->getProxyForRequest($fileUrl); $usingProxy = $proxy->getStatus(' using proxy (%s)'); @@ -304,7 +305,7 @@ protected function get(string $originUrl, string $fileUrl, array $additionalOpti if (!empty($http_response_header[0])) { $statusCode = self::findStatusCode($http_response_header); - if ($statusCode >= 400 && Response::findHeaderValue($http_response_header, 'content-type') === 'application/json') { + if ($statusCode >= 300 && Response::findHeaderValue($http_response_header, 'content-type') === 'application/json') { HttpDownloader::outputWarnings($this->io, $originUrl, json_decode($result, true)); } @@ -533,7 +534,12 @@ protected function getRemoteContents(string $originUrl, string $fileUrl, $contex } // https://www.php.net/manual/en/reserved.variables.httpresponseheader.php - $responseHeaders = $http_response_header ?? []; + if (\PHP_VERSION_ID >= 80400) { + $responseHeaders = http_get_last_response_headers() ?? []; + http_clear_last_response_headers(); + } else { + $responseHeaders = $http_response_header ?? []; + } if (null !== $e) { throw $e; diff --git a/app/vendor/composer/composer/src/Composer/Util/Silencer.php b/app/vendor/composer/composer/src/Composer/Util/Silencer.php index f2b9f73fc..6dd0efb34 100644 --- a/app/vendor/composer/composer/src/Composer/Util/Silencer.php +++ b/app/vendor/composer/composer/src/Composer/Util/Silencer.php @@ -33,7 +33,7 @@ class Silencer public static function suppress(?int $mask = null): int { if (!isset($mask)) { - $mask = E_WARNING | E_NOTICE | E_USER_WARNING | E_USER_NOTICE | E_DEPRECATED | E_USER_DEPRECATED | E_STRICT; + $mask = E_WARNING | E_NOTICE | E_USER_WARNING | E_USER_NOTICE | E_DEPRECATED | E_USER_DEPRECATED; } $old = error_reporting(); self::$stack[] = $old; diff --git a/app/vendor/composer/composer/src/Composer/Util/Svn.php b/app/vendor/composer/composer/src/Composer/Util/Svn.php index ea7d5dbeb..506a14ec7 100644 --- a/app/vendor/composer/composer/src/Composer/Util/Svn.php +++ b/app/vendor/composer/composer/src/Composer/Util/Svn.php @@ -90,7 +90,7 @@ public static function cleanEnv(): void * Execute an SVN remote command and try to fix up the process with credentials * if necessary. * - * @param string $command SVN command to run + * @param non-empty-list $command SVN command to run * @param string $url SVN url * @param ?string $cwd Working directory * @param ?string $path Target for a checkout @@ -98,7 +98,7 @@ public static function cleanEnv(): void * * @throws \RuntimeException */ - public function execute(string $command, string $url, ?string $cwd = null, ?string $path = null, bool $verbose = false): string + public function execute(array $command, string $url, ?string $cwd = null, ?string $path = null, bool $verbose = false): string { // Ensure we are allowed to use this URL by config $this->config->prohibitUrlByConfig($url, $this->io); @@ -110,20 +110,23 @@ public function execute(string $command, string $url, ?string $cwd = null, ?stri * Execute an SVN local command and try to fix up the process with credentials * if necessary. * - * @param string $command SVN command to run + * @param non-empty-list $command SVN command to run * @param string $path Path argument passed thru to the command * @param string $cwd Working directory * @param bool $verbose Output all output to the user * * @throws \RuntimeException */ - public function executeLocal(string $command, string $path, ?string $cwd = null, bool $verbose = false): string + public function executeLocal(array $command, string $path, ?string $cwd = null, bool $verbose = false): string { // A local command has no remote url return $this->executeWithAuthRetry($command, $cwd, '', $path, $verbose); } - private function executeWithAuthRetry(string $svnCommand, ?string $cwd, string $url, ?string $path, bool $verbose): ?string + /** + * @param non-empty-list $svnCommand + */ + private function executeWithAuthRetry(array $svnCommand, ?string $cwd, string $url, ?string $path, bool $verbose): ?string { // Regenerate the command at each try, to use the newly user-provided credentials $command = $this->getCommand($svnCommand, $url, $path); @@ -209,22 +212,23 @@ protected function doAuthDance(): Svn /** * A method to create the svn commands run. * - * @param string $cmd Usually 'svn ls' or something like that. + * @param non-empty-list $cmd Usually 'svn ls' or something like that. * @param string $url Repo URL. * @param string $path Target for a checkout + * + * @return non-empty-list */ - protected function getCommand(string $cmd, string $url, ?string $path = null): string + protected function getCommand(array $cmd, string $url, ?string $path = null): array { - $cmd = sprintf( - '%s %s%s -- %s', + $cmd = array_merge( $cmd, - '--non-interactive ', - $this->getCredentialString(), - ProcessExecutor::escape($url) + ['--non-interactive'], + $this->getCredentialArgs(), + ['--', $url] ); - if ($path) { - $cmd .= ' ' . ProcessExecutor::escape($path); + if ($path !== null) { + $cmd[] = $path; } return $cmd; @@ -234,18 +238,18 @@ protected function getCommand(string $cmd, string $url, ?string $path = null): s * Return the credential string for the svn command. * * Adds --no-auth-cache when credentials are present. + * + * @return list */ - protected function getCredentialString(): string + protected function getCredentialArgs(): array { if (!$this->hasAuth()) { - return ''; + return []; } - return sprintf( - ' %s--username %s --password %s ', - $this->getAuthCache(), - ProcessExecutor::escape($this->getUsername()), - ProcessExecutor::escape($this->getPassword()) + return array_merge( + $this->getAuthCacheArgs(), + ['--username', $this->getUsername(), '--password', $this->getPassword()] ); } @@ -295,10 +299,12 @@ protected function hasAuth(): bool /** * Return the no-auth-cache switch. + * + * @return list */ - protected function getAuthCache(): string + protected function getAuthCacheArgs(): array { - return $this->cacheCredentials ? '' : '--no-auth-cache '; + return $this->cacheCredentials ? [] : ['--no-auth-cache']; } /** @@ -349,7 +355,7 @@ private function createAuthFromUrl(): bool public function binaryVersion(): ?string { if (!self::$version) { - if (0 === $this->process->execute('svn --version', $output)) { + if (0 === $this->process->execute(['svn', '--version'], $output)) { if (Preg::isMatch('{(\d+(?:\.\d+)+)}', $output, $match)) { self::$version = $match[1]; } diff --git a/app/vendor/composer/composer/src/Composer/Util/Tar.php b/app/vendor/composer/composer/src/Composer/Util/Tar.php index bb8c8c3d2..1fb608f65 100644 --- a/app/vendor/composer/composer/src/Composer/Util/Tar.php +++ b/app/vendor/composer/composer/src/Composer/Util/Tar.php @@ -50,7 +50,7 @@ private static function extractComposerJsonFromFolder(\PharData $phar): string } $composerJsonPath = key($topLevelPaths).'/composer.json'; - if ($topLevelPaths && isset($phar[$composerJsonPath])) { + if (\count($topLevelPaths) > 0 && isset($phar[$composerJsonPath])) { return $phar[$composerJsonPath]->getContent(); } diff --git a/app/vendor/composer/composer/src/Composer/Util/TlsHelper.php b/app/vendor/composer/composer/src/Composer/Util/TlsHelper.php index 5ab2bf9c9..da0801a1a 100644 --- a/app/vendor/composer/composer/src/Composer/Util/TlsHelper.php +++ b/app/vendor/composer/composer/src/Composer/Util/TlsHelper.php @@ -150,7 +150,7 @@ public static function getCertificateFingerprint(string $certificate): string $pemtrim = substr($pubkeypem, strpos($pubkeypem, $start) + strlen($start), (strlen($pubkeypem) - strpos($pubkeypem, $end)) * (-1)); $der = base64_decode($pemtrim); - return sha1($der); + return hash('sha1', $der); } /** diff --git a/app/vendor/composer/composer/src/Composer/Util/Url.php b/app/vendor/composer/composer/src/Composer/Util/Url.php index 5d703a20d..32f61347b 100644 --- a/app/vendor/composer/composer/src/Composer/Util/Url.php +++ b/app/vendor/composer/composer/src/Composer/Util/Url.php @@ -75,7 +75,7 @@ public static function getOrigin(Config $config, string $url): string $origin .= ':'.$port; } - if (strpos($origin, '.github.com') === (strlen($origin) - 11)) { + if (str_ends_with($origin, '.github.com') && $origin !== 'codeload.github.com') { return 'github.com'; } @@ -110,7 +110,6 @@ public static function sanitize(string $url): string $url = Preg::replace('{([&?]access_token=)[^&]+}', '$1***', $url); $url = Preg::replaceCallback('{^(?P[a-z0-9]+://)?(?P[^:/\s@]+):(?P[^@\s/]+)@}i', static function ($m): string { - assert(is_string($m['user'])); // if the username looks like a long (12char+) hex string, or a modern github token (e.g. ghp_xxx) we obfuscate that if (Preg::isMatch('{^([a-f0-9]{12,}|gh[a-z]_[a-zA-Z0-9_]+|github_pat_[a-zA-Z0-9_]+)$}', $m['user'])) { return $m['prefix'].'***:***@'; diff --git a/app/vendor/composer/installed.json b/app/vendor/composer/installed.json index fdbb72411..0dd45d612 100644 --- a/app/vendor/composer/installed.json +++ b/app/vendor/composer/installed.json @@ -114,21 +114,21 @@ }, { "name": "cakephp/cakephp", - "version": "4.6.0", - "version_normalized": "4.6.0.0", + "version": "4.6.2", + "version_normalized": "4.6.2.0", "source": { "type": "git", "url": "https://github.com/cakephp/cakephp.git", - "reference": "b8585672346c0654311c77500ce613cdf37687cc" + "reference": "db79f771fa3f0e7492840ad9fb5b89c01519a500" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/cakephp/zipball/b8585672346c0654311c77500ce613cdf37687cc", - "reference": "b8585672346c0654311c77500ce613cdf37687cc", + "url": "https://api.github.com/repos/cakephp/cakephp/zipball/db79f771fa3f0e7492840ad9fb5b89c01519a500", + "reference": "db79f771fa3f0e7492840ad9fb5b89c01519a500", "shasum": "" }, "require": { - "cakephp/chronos": "^2.4.0-RC2", + "cakephp/chronos": "^2.4.0", "composer/ca-bundle": "^1.2", "ext-intl": "*", "ext-json": "*", @@ -181,7 +181,7 @@ "lib-ICU": "To use locale-aware features in the I18n and Database packages", "paragonie/csp-builder": "CSP builder, to use the CSP Middleware" }, - "time": "2025-03-23T02:36:48+00:00", + "time": "2025-07-27T03:26:03+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -230,17 +230,17 @@ }, { "name": "cakephp/cakephp-codesniffer", - "version": "4.7.0", - "version_normalized": "4.7.0.0", + "version": "4.7.1", + "version_normalized": "4.7.1.0", "source": { "type": "git", "url": "https://github.com/cakephp/cakephp-codesniffer.git", - "reference": "24fa2321d54e5251ac2f59dd92dd2066f0b0bdae" + "reference": "d09f5945bec4bf82581c52eabe7cea7b92cba6e3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/cakephp-codesniffer/zipball/24fa2321d54e5251ac2f59dd92dd2066f0b0bdae", - "reference": "24fa2321d54e5251ac2f59dd92dd2066f0b0bdae", + "url": "https://api.github.com/repos/cakephp/cakephp-codesniffer/zipball/d09f5945bec4bf82581c52eabe7cea7b92cba6e3", + "reference": "d09f5945bec4bf82581c52eabe7cea7b92cba6e3", "shasum": "" }, "require": { @@ -251,7 +251,7 @@ "require-dev": { "phpunit/phpunit": "^7.1" }, - "time": "2023-04-10T06:35:04+00:00", + "time": "2025-07-05T09:11:50+00:00", "type": "phpcodesniffer-standard", "installation-source": "dist", "autoload": { @@ -531,25 +531,24 @@ }, { "name": "cakephp/twig-view", - "version": "1.3.0", - "version_normalized": "1.3.0.0", + "version": "1.3.1", + "version_normalized": "1.3.1.0", "source": { "type": "git", "url": "https://github.com/cakephp/twig-view.git", - "reference": "14df50360b809a171d0688020fbdfe513763f89b" + "reference": "e4a18e91e004730ccbaf796bde60612e8afac0e8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cakephp/twig-view/zipball/14df50360b809a171d0688020fbdfe513763f89b", - "reference": "14df50360b809a171d0688020fbdfe513763f89b", + "url": "https://api.github.com/repos/cakephp/twig-view/zipball/e4a18e91e004730ccbaf796bde60612e8afac0e8", + "reference": "e4a18e91e004730ccbaf796bde60612e8afac0e8", "shasum": "" }, "require": { "cakephp/cakephp": "^4.0", "jasny/twig-extensions": "^1.3", - "php": ">=7.2", "twig/markdown-extra": "^3.0", - "twig/twig": "^3.0" + "twig/twig": "^3.11.0" }, "conflict": { "wyrihaximus/twig-view": "*" @@ -562,7 +561,7 @@ "mikey179/vfsstream": "^1.6", "phpunit/phpunit": "^8.5 || ^9.3" }, - "time": "2021-09-17T14:07:52+00:00", + "time": "2024-10-11T06:25:59+00:00", "type": "cakephp-plugin", "installation-source": "dist", "autoload": { @@ -597,17 +596,17 @@ }, { "name": "composer/ca-bundle", - "version": "1.5.6", - "version_normalized": "1.5.6.0", + "version": "1.5.7", + "version_normalized": "1.5.7.0", "source": { "type": "git", "url": "https://github.com/composer/ca-bundle.git", - "reference": "f65c239c970e7f072f067ab78646e9f0b2935175" + "reference": "d665d22c417056996c59019579f1967dfe5c1e82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/ca-bundle/zipball/f65c239c970e7f072f067ab78646e9f0b2935175", - "reference": "f65c239c970e7f072f067ab78646e9f0b2935175", + "url": "https://api.github.com/repos/composer/ca-bundle/zipball/d665d22c417056996c59019579f1967dfe5c1e82", + "reference": "d665d22c417056996c59019579f1967dfe5c1e82", "shasum": "" }, "require": { @@ -621,7 +620,7 @@ "psr/log": "^1.0 || ^2.0 || ^3.0", "symfony/process": "^4.0 || ^5.0 || ^6.0 || ^7.0" }, - "time": "2025-03-06T14:30:56+00:00", + "time": "2025-05-26T15:08:54+00:00", "type": "library", "extra": { "branch-alias": { @@ -656,7 +655,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/ca-bundle/issues", - "source": "https://github.com/composer/ca-bundle/tree/1.5.6" + "source": "https://github.com/composer/ca-bundle/tree/1.5.7" }, "funding": [ { @@ -676,17 +675,17 @@ }, { "name": "composer/class-map-generator", - "version": "1.1.0", - "version_normalized": "1.1.0.0", + "version": "1.6.1", + "version_normalized": "1.6.1.0", "source": { "type": "git", "url": "https://github.com/composer/class-map-generator.git", - "reference": "953cc4ea32e0c31f2185549c7d216d7921f03da9" + "reference": "134b705ddb0025d397d8318a75825fe3c9d1da34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/class-map-generator/zipball/953cc4ea32e0c31f2185549c7d216d7921f03da9", - "reference": "953cc4ea32e0c31f2185549c7d216d7921f03da9", + "url": "https://api.github.com/repos/composer/class-map-generator/zipball/134b705ddb0025d397d8318a75825fe3c9d1da34", + "reference": "134b705ddb0025d397d8318a75825fe3c9d1da34", "shasum": "" }, "require": { @@ -695,14 +694,14 @@ "symfony/finder": "^4.4 || ^5.3 || ^6 || ^7" }, "require-dev": { - "phpstan/phpstan": "^1.6", - "phpstan/phpstan-deprecation-rules": "^1", - "phpstan/phpstan-phpunit": "^1", - "phpstan/phpstan-strict-rules": "^1.1", - "symfony/filesystem": "^5.4 || ^6", - "symfony/phpunit-bridge": "^5" - }, - "time": "2023-06-30T13:58:57+00:00", + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-deprecation-rules": "^1 || ^2", + "phpstan/phpstan-phpunit": "^1 || ^2", + "phpstan/phpstan-strict-rules": "^1.1 || ^2", + "phpunit/phpunit": "^8", + "symfony/filesystem": "^5.4 || ^6" + }, + "time": "2025-03-24T13:50:44+00:00", "type": "library", "extra": { "branch-alias": { @@ -732,7 +731,7 @@ ], "support": { "issues": "https://github.com/composer/class-map-generator/issues", - "source": "https://github.com/composer/class-map-generator/tree/1.1.0" + "source": "https://github.com/composer/class-map-generator/tree/1.6.1" }, "funding": [ { @@ -752,56 +751,56 @@ }, { "name": "composer/composer", - "version": "2.7.6", - "version_normalized": "2.7.6.0", + "version": "2.8.10", + "version_normalized": "2.8.10.0", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "fabd995783b633829fd4280e272284b39b6ae702" + "reference": "53834f587d7ab2527eb237459d7b94d1fb9d4c5a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/fabd995783b633829fd4280e272284b39b6ae702", - "reference": "fabd995783b633829fd4280e272284b39b6ae702", + "url": "https://api.github.com/repos/composer/composer/zipball/53834f587d7ab2527eb237459d7b94d1fb9d4c5a", + "reference": "53834f587d7ab2527eb237459d7b94d1fb9d4c5a", "shasum": "" }, "require": { - "composer/ca-bundle": "^1.0", - "composer/class-map-generator": "^1.0", + "composer/ca-bundle": "^1.5", + "composer/class-map-generator": "^1.4.0", "composer/metadata-minifier": "^1.0", - "composer/pcre": "^2.1 || ^3.1", - "composer/semver": "^3.2.5", + "composer/pcre": "^2.2 || ^3.2", + "composer/semver": "^3.3", "composer/spdx-licenses": "^1.5.7", "composer/xdebug-handler": "^2.0.2 || ^3.0.3", - "justinrainbow/json-schema": "^5.2.11", + "justinrainbow/json-schema": "^6.3.1", "php": "^7.2.5 || ^8.0", "psr/log": "^1.0 || ^2.0 || ^3.0", - "react/promise": "^2.8 || ^3", + "react/promise": "^2.11 || ^3.2", "seld/jsonlint": "^1.4", "seld/phar-utils": "^1.2", "seld/signal-handler": "^2.0", - "symfony/console": "^5.4.11 || ^6.0.11 || ^7", - "symfony/filesystem": "^5.4 || ^6.0 || ^7", - "symfony/finder": "^5.4 || ^6.0 || ^7", + "symfony/console": "^5.4.35 || ^6.3.12 || ^7.0.3", + "symfony/filesystem": "^5.4.35 || ^6.3.12 || ^7.0.3", + "symfony/finder": "^5.4.35 || ^6.3.12 || ^7.0.3", "symfony/polyfill-php73": "^1.24", "symfony/polyfill-php80": "^1.24", "symfony/polyfill-php81": "^1.24", - "symfony/process": "^5.4 || ^6.0 || ^7" + "symfony/process": "^5.4.35 || ^6.3.12 || ^7.0.3" }, "require-dev": { - "phpstan/phpstan": "^1.9.3", - "phpstan/phpstan-deprecation-rules": "^1", - "phpstan/phpstan-phpunit": "^1.0", - "phpstan/phpstan-strict-rules": "^1", - "phpstan/phpstan-symfony": "^1.2.10", - "symfony/phpunit-bridge": "^6.4.1 || ^7.0.1" + "phpstan/phpstan": "^1.11.8", + "phpstan/phpstan-deprecation-rules": "^1.2.0", + "phpstan/phpstan-phpunit": "^1.4.0", + "phpstan/phpstan-strict-rules": "^1.6.0", + "phpstan/phpstan-symfony": "^1.4.0", + "symfony/phpunit-bridge": "^6.4.3 || ^7.0.1" }, "suggest": { "ext-openssl": "Enabling the openssl extension allows you to access https URLs for repositories and packages", "ext-zip": "Enabling the zip extension allows you to unzip archives", "ext-zlib": "Allow gzip compression of HTTP requests" }, - "time": "2024-05-04T21:03:15+00:00", + "time": "2025-07-10T17:08:33+00:00", "bin": [ "bin/composer" ], @@ -813,7 +812,7 @@ ] }, "branch-alias": { - "dev-main": "2.7-dev" + "dev-main": "2.8-dev" } }, "installation-source": "dist", @@ -849,7 +848,7 @@ "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/composer/issues", "security": "https://github.com/composer/composer/security/policy", - "source": "https://github.com/composer/composer/tree/2.7.6" + "source": "https://github.com/composer/composer/tree/2.8.10" }, "funding": [ { @@ -941,30 +940,38 @@ }, { "name": "composer/pcre", - "version": "3.1.1", - "version_normalized": "3.1.1.0", + "version": "3.3.2", + "version_normalized": "3.3.2.0", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9" + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/00104306927c7a0919b4ced2aaa6782c1e61a3c9", - "reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9", + "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", "shasum": "" }, "require": { "php": "^7.4 || ^8.0" }, + "conflict": { + "phpstan/phpstan": "<1.11.10" + }, "require-dev": { - "phpstan/phpstan": "^1.3", - "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^5" + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-strict-rules": "^1 || ^2", + "phpunit/phpunit": "^8 || ^9" }, - "time": "2023-10-11T07:11:09+00:00", + "time": "2024-11-12T16:29:46+00:00", "type": "library", "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + }, "branch-alias": { "dev-main": "3.x-dev" } @@ -995,7 +1002,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.1.1" + "source": "https://github.com/composer/pcre/tree/3.3.2" }, "funding": [ { @@ -1015,27 +1022,27 @@ }, { "name": "composer/semver", - "version": "3.4.0", - "version_normalized": "3.4.0.0", + "version": "3.4.3", + "version_normalized": "3.4.3.0", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32" + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32", - "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32", + "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", "shasum": "" }, "require": { "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^1.4", - "symfony/phpunit-bridge": "^4.2 || ^5" + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" }, - "time": "2023-08-31T09:50:34+00:00", + "time": "2024-09-19T14:15:21+00:00", "type": "library", "extra": { "branch-alias": { @@ -1079,7 +1086,7 @@ "support": { "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.4.0" + "source": "https://github.com/composer/semver/tree/3.4.3" }, "funding": [ { @@ -1099,27 +1106,27 @@ }, { "name": "composer/spdx-licenses", - "version": "1.5.8", - "version_normalized": "1.5.8.0", + "version": "1.5.9", + "version_normalized": "1.5.9.0", "source": { "type": "git", "url": "https://github.com/composer/spdx-licenses.git", - "reference": "560bdcf8deb88ae5d611c80a2de8ea9d0358cc0a" + "reference": "edf364cefe8c43501e21e88110aac10b284c3c9f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/560bdcf8deb88ae5d611c80a2de8ea9d0358cc0a", - "reference": "560bdcf8deb88ae5d611c80a2de8ea9d0358cc0a", + "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/edf364cefe8c43501e21e88110aac10b284c3c9f", + "reference": "edf364cefe8c43501e21e88110aac10b284c3c9f", "shasum": "" }, "require": { "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^0.12.55", - "symfony/phpunit-bridge": "^4.2 || ^5" + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" }, - "time": "2023-11-20T07:44:33+00:00", + "time": "2025-05-12T21:07:07+00:00", "type": "library", "extra": { "branch-alias": { @@ -1162,7 +1169,7 @@ "support": { "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/spdx-licenses/issues", - "source": "https://github.com/composer/spdx-licenses/tree/1.5.8" + "source": "https://github.com/composer/spdx-licenses/tree/1.5.9" }, "funding": [ { @@ -1182,17 +1189,17 @@ }, { "name": "composer/xdebug-handler", - "version": "3.0.3", - "version_normalized": "3.0.3.0", + "version": "3.0.5", + "version_normalized": "3.0.5.0", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "ced299686f41dce890debac69273b47ffe98a40c" + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/ced299686f41dce890debac69273b47ffe98a40c", - "reference": "ced299686f41dce890debac69273b47ffe98a40c", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef", "shasum": "" }, "require": { @@ -1203,9 +1210,9 @@ "require-dev": { "phpstan/phpstan": "^1.0", "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^6.0" + "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5" }, - "time": "2022-02-25T21:32:43+00:00", + "time": "2024-05-06T16:37:16+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1229,9 +1236,9 @@ "performance" ], "support": { - "irc": "irc://irc.freenode.org/composer", + "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/3.0.3" + "source": "https://github.com/composer/xdebug-handler/tree/3.0.5" }, "funding": [ { @@ -1251,33 +1258,33 @@ }, { "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v1.0.0", - "version_normalized": "1.0.0.0", + "version": "v1.1.2", + "version_normalized": "1.1.2.0", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/composer-installer.git", - "reference": "4be43904336affa5c2f70744a348312336afd0da" + "reference": "e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/4be43904336affa5c2f70744a348312336afd0da", - "reference": "4be43904336affa5c2f70744a348312336afd0da", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1", + "reference": "e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1", "shasum": "" }, "require": { - "composer-plugin-api": "^1.0 || ^2.0", + "composer-plugin-api": "^2.2", "php": ">=5.4", "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" }, "require-dev": { - "composer/composer": "*", + "composer/composer": "^2.2", "ext-json": "*", "ext-zip": "*", - "php-parallel-lint/php-parallel-lint": "^1.3.1", + "php-parallel-lint/php-parallel-lint": "^1.4.0", "phpcompatibility/php-compatibility": "^9.0", "yoast/phpunit-polyfills": "^1.0" }, - "time": "2023-01-05T11:28:13+00:00", + "time": "2025-07-17T20:45:56+00:00", "type": "composer-plugin", "extra": { "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" @@ -1295,9 +1302,9 @@ "authors": [ { "name": "Franck Nijhof", - "email": "franck.nijhof@dealerdirect.com", - "homepage": "http://www.frenck.nl", - "role": "Developer / IT Manager" + "email": "opensource@frenck.dev", + "homepage": "https://frenck.dev", + "role": "Open source developer" }, { "name": "Contributors", @@ -1305,7 +1312,6 @@ } ], "description": "PHP_CodeSniffer Standards Composer Installer Plugin", - "homepage": "http://www.dealerdirect.com", "keywords": [ "PHPCodeSniffer", "PHP_CodeSniffer", @@ -1326,148 +1332,72 @@ ], "support": { "issues": "https://github.com/PHPCSStandards/composer-installer/issues", + "security": "https://github.com/PHPCSStandards/composer-installer/security/policy", "source": "https://github.com/PHPCSStandards/composer-installer" }, - "install-path": "../dealerdirect/phpcodesniffer-composer-installer" - }, - { - "name": "doctrine/cache", - "version": "2.2.0", - "version_normalized": "2.2.0.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/cache.git", - "reference": "1ca8f21980e770095a31456042471a57bc4c68fb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/1ca8f21980e770095a31456042471a57bc4c68fb", - "reference": "1ca8f21980e770095a31456042471a57bc4c68fb", - "shasum": "" - }, - "require": { - "php": "~7.1 || ^8.0" - }, - "conflict": { - "doctrine/common": ">2.2,<2.4" - }, - "require-dev": { - "cache/integration-tests": "dev-master", - "doctrine/coding-standard": "^9", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "psr/cache": "^1.0 || ^2.0 || ^3.0", - "symfony/cache": "^4.4 || ^5.4 || ^6", - "symfony/var-exporter": "^4.4 || ^5.4 || ^6" - }, - "time": "2022-05-20T20:07:39+00:00", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, + "funding": [ { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" + "url": "https://github.com/PHPCSStandards", + "type": "github" }, { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.", - "homepage": "https://www.doctrine-project.org/projects/cache.html", - "keywords": [ - "abstraction", - "apcu", - "cache", - "caching", - "couchdb", - "memcached", - "php", - "redis", - "xcache" - ], - "support": { - "issues": "https://github.com/doctrine/cache/issues", - "source": "https://github.com/doctrine/cache/tree/2.2.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" + "url": "https://github.com/jrfnl", + "type": "github" }, { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" }, { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcache", - "type": "tidelift" + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" } ], - "install-path": "../doctrine/cache" + "install-path": "../dealerdirect/phpcodesniffer-composer-installer" }, { "name": "doctrine/dbal", - "version": "3.8.2", - "version_normalized": "3.8.2.0", + "version": "3.10.0", + "version_normalized": "3.10.0.0", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "a19a1d05ca211f41089dffcc387733a6875196cb" + "reference": "1cf840d696373ea0d58ad0a8875c0fadcfc67214" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/a19a1d05ca211f41089dffcc387733a6875196cb", - "reference": "a19a1d05ca211f41089dffcc387733a6875196cb", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/1cf840d696373ea0d58ad0a8875c0fadcfc67214", + "reference": "1cf840d696373ea0d58ad0a8875c0fadcfc67214", "shasum": "" }, "require": { "composer-runtime-api": "^2", - "doctrine/cache": "^1.11|^2.0", "doctrine/deprecations": "^0.5.3|^1", "doctrine/event-manager": "^1|^2", "php": "^7.4 || ^8.0", "psr/cache": "^1|^2|^3", "psr/log": "^1|^2|^3" }, + "conflict": { + "doctrine/cache": "< 1.11" + }, "require-dev": { - "doctrine/coding-standard": "12.0.0", + "doctrine/cache": "^1.11|^2.0", + "doctrine/coding-standard": "13.0.0", "fig/log-test": "^1", "jetbrains/phpstorm-stubs": "2023.1", - "phpstan/phpstan": "1.10.57", - "phpstan/phpstan-strict-rules": "^1.5", - "phpunit/phpunit": "9.6.16", - "psalm/plugin-phpunit": "0.18.4", - "slevomat/coding-standard": "8.13.1", - "squizlabs/php_codesniffer": "3.8.1", + "phpstan/phpstan": "2.1.17", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "9.6.23", + "slevomat/coding-standard": "8.16.2", + "squizlabs/php_codesniffer": "3.13.1", "symfony/cache": "^5.4|^6.0|^7.0", - "symfony/console": "^4.4|^5.4|^6.0|^7.0", - "vimeo/psalm": "4.30.0" + "symfony/console": "^4.4|^5.4|^6.0|^7.0" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." }, - "time": "2024-02-12T18:36:36+00:00", + "time": "2025-07-10T21:11:04+00:00", "bin": [ "bin/doctrine-dbal" ], @@ -1524,7 +1454,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.8.2" + "source": "https://github.com/doctrine/dbal/tree/3.10.0" }, "funding": [ { @@ -1544,40 +1474,41 @@ }, { "name": "doctrine/deprecations", - "version": "1.1.3", - "version_normalized": "1.1.3.0", + "version": "1.1.5", + "version_normalized": "1.1.5.0", "source": { "type": "git", "url": "https://github.com/doctrine/deprecations.git", - "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab" + "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", - "reference": "dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab", + "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", + "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", "shasum": "" }, "require": { "php": "^7.1 || ^8.0" }, + "conflict": { + "phpunit/phpunit": "<=7.5 || >=13" + }, "require-dev": { - "doctrine/coding-standard": "^9", - "phpstan/phpstan": "1.4.10 || 1.10.15", - "phpstan/phpstan-phpunit": "^1.0", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "psalm/plugin-phpunit": "0.18.4", - "psr/log": "^1 || ^2 || ^3", - "vimeo/psalm": "4.30.0 || 5.12.0" + "doctrine/coding-standard": "^9 || ^12 || ^13", + "phpstan/phpstan": "1.4.10 || 2.1.11", + "phpstan/phpstan-phpunit": "^1.0 || ^2", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12", + "psr/log": "^1 || ^2 || ^3" }, "suggest": { "psr/log": "Allows logging deprecations via PSR-3 logger implementation" }, - "time": "2024-01-30T19:34:25+00:00", + "time": "2025-04-07T20:06:18+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-4": { - "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + "Doctrine\\Deprecations\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -1588,23 +1519,23 @@ "homepage": "https://www.doctrine-project.org/", "support": { "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.3" + "source": "https://github.com/doctrine/deprecations/tree/1.1.5" }, "install-path": "../doctrine/deprecations" }, { "name": "doctrine/event-manager", - "version": "2.0.0", - "version_normalized": "2.0.0.0", + "version": "2.0.1", + "version_normalized": "2.0.1.0", "source": { "type": "git", "url": "https://github.com/doctrine/event-manager.git", - "reference": "750671534e0241a7c50ea5b43f67e23eb5c96f32" + "reference": "b680156fa328f1dfd874fd48c7026c41570b9c6e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/event-manager/zipball/750671534e0241a7c50ea5b43f67e23eb5c96f32", - "reference": "750671534e0241a7c50ea5b43f67e23eb5c96f32", + "url": "https://api.github.com/repos/doctrine/event-manager/zipball/b680156fa328f1dfd874fd48c7026c41570b9c6e", + "reference": "b680156fa328f1dfd874fd48c7026c41570b9c6e", "shasum": "" }, "require": { @@ -1614,12 +1545,12 @@ "doctrine/common": "<2.9" }, "require-dev": { - "doctrine/coding-standard": "^10", + "doctrine/coding-standard": "^12", "phpstan/phpstan": "^1.8.8", - "phpunit/phpunit": "^9.5", - "vimeo/psalm": "^4.28" + "phpunit/phpunit": "^10.5", + "vimeo/psalm": "^5.24" }, - "time": "2022-10-12T20:59:15+00:00", + "time": "2024-05-22T20:47:39+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1668,7 +1599,7 @@ ], "support": { "issues": "https://github.com/doctrine/event-manager/issues", - "source": "https://github.com/doctrine/event-manager/tree/2.0.0" + "source": "https://github.com/doctrine/event-manager/tree/2.0.1" }, "funding": [ { @@ -1761,26 +1692,29 @@ }, { "name": "doctrine/sql-formatter", - "version": "1.2.0", - "version_normalized": "1.2.0.0", + "version": "1.5.2", + "version_normalized": "1.5.2.0", "source": { "type": "git", "url": "https://github.com/doctrine/sql-formatter.git", - "reference": "a321d114e0a18e6497f8a2cd6f890e000cc17ecc" + "reference": "d6d00aba6fd2957fe5216fe2b7673e9985db20c8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/sql-formatter/zipball/a321d114e0a18e6497f8a2cd6f890e000cc17ecc", - "reference": "a321d114e0a18e6497f8a2cd6f890e000cc17ecc", + "url": "https://api.github.com/repos/doctrine/sql-formatter/zipball/d6d00aba6fd2957fe5216fe2b7673e9985db20c8", + "reference": "d6d00aba6fd2957fe5216fe2b7673e9985db20c8", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0" + "php": "^8.1" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.4" + "doctrine/coding-standard": "^12", + "ergebnis/phpunit-slow-test-detector": "^2.14", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.5" }, - "time": "2023-08-16T21:49:04+00:00", + "time": "2025-01-24T11:45:48+00:00", "bin": [ "bin/sql-formatter" ], @@ -1810,40 +1744,42 @@ ], "support": { "issues": "https://github.com/doctrine/sql-formatter/issues", - "source": "https://github.com/doctrine/sql-formatter/tree/1.2.0" + "source": "https://github.com/doctrine/sql-formatter/tree/1.5.2" }, "install-path": "../doctrine/sql-formatter" }, { "name": "jasny/twig-extensions", - "version": "v1.3.0", - "version_normalized": "1.3.0.0", + "version": "v1.3.1", + "version_normalized": "1.3.1.0", "source": { "type": "git", "url": "https://github.com/jasny/twig-extensions.git", - "reference": "a694eb02f6fc14ff8e2fceb8b80882c0c926102b" + "reference": "8a5ca5f49317bf421a519556ad2e876820d41e01" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jasny/twig-extensions/zipball/a694eb02f6fc14ff8e2fceb8b80882c0c926102b", - "reference": "a694eb02f6fc14ff8e2fceb8b80882c0c926102b", + "url": "https://api.github.com/repos/jasny/twig-extensions/zipball/8a5ca5f49317bf421a519556ad2e876820d41e01", + "reference": "8a5ca5f49317bf421a519556ad2e876820d41e01", "shasum": "" }, "require": { - "php": ">=7.0.0", - "twig/twig": "^2.0 | ^3.0" + "php": ">=7.4.0", + "twig/twig": "^2.7 | ^3.0" }, "require-dev": { "ext-intl": "*", + "ext-json": "*", "ext-pcre": "*", - "jasny/php-code-quality": "^2.5", - "php": ">=7.2.0" + "phpstan/phpstan": "^1.12.0", + "phpunit/phpunit": "^9.6", + "squizlabs/php_codesniffer": "^3.10" }, "suggest": { "ext-intl": "Required for the use of the LocalDate Twig extension", "ext-pcre": "Required for the use of the PCRE Twig extension" }, - "time": "2019-12-10T16:04:23+00:00", + "time": "2024-09-03T09:04:53+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -1943,35 +1879,40 @@ }, { "name": "justinrainbow/json-schema", - "version": "v5.2.13", - "version_normalized": "5.2.13.0", + "version": "6.4.2", + "version_normalized": "6.4.2.0", "source": { "type": "git", - "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "fbbe7e5d79f618997bc3332a6f49246036c45793" + "url": "https://github.com/jsonrainbow/json-schema.git", + "reference": "ce1fd2d47799bb60668643bc6220f6278a4c1d02" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/fbbe7e5d79f618997bc3332a6f49246036c45793", - "reference": "fbbe7e5d79f618997bc3332a6f49246036c45793", + "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/ce1fd2d47799bb60668643bc6220f6278a4c1d02", + "reference": "ce1fd2d47799bb60668643bc6220f6278a4c1d02", "shasum": "" }, "require": { - "php": ">=5.3.3" + "ext-json": "*", + "marc-mabe/php-enum": "^4.0", + "php": "^7.2 || ^8.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1", + "friendsofphp/php-cs-fixer": "3.3.0", "json-schema/json-schema-test-suite": "1.2.0", - "phpunit/phpunit": "^4.8.35" + "marc-mabe/php-enum-phpstan": "^2.0", + "phpspec/prophecy": "^1.19", + "phpstan/phpstan": "^1.12", + "phpunit/phpunit": "^8.5" }, - "time": "2023-09-26T02:20:38+00:00", + "time": "2025-06-03T18:27:04+00:00", "bin": [ "bin/validate-json" ], "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0.x-dev" + "dev-master": "6.x-dev" } }, "installation-source": "dist", @@ -2003,14 +1944,14 @@ } ], "description": "A library to validate a json schema.", - "homepage": "https://github.com/justinrainbow/json-schema", + "homepage": "https://github.com/jsonrainbow/json-schema", "keywords": [ "json", "schema" ], "support": { - "issues": "https://github.com/justinrainbow/json-schema/issues", - "source": "https://github.com/justinrainbow/json-schema/tree/v5.2.13" + "issues": "https://github.com/jsonrainbow/json-schema/issues", + "source": "https://github.com/jsonrainbow/json-schema/tree/6.4.2" }, "install-path": "../justinrainbow/json-schema" }, @@ -2116,17 +2057,17 @@ }, { "name": "laminas/laminas-httphandlerrunner", - "version": "2.11.0", - "version_normalized": "2.11.0.0", + "version": "2.12.0", + "version_normalized": "2.12.0.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-httphandlerrunner.git", - "reference": "c428d9f67f280d155637cbe2b7245b5188c8cdae" + "reference": "b14da3519c650e9436e410cfedee6f860312eff9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-httphandlerrunner/zipball/c428d9f67f280d155637cbe2b7245b5188c8cdae", - "reference": "c428d9f67f280d155637cbe2b7245b5188c8cdae", + "url": "https://api.github.com/repos/laminas/laminas-httphandlerrunner/zipball/b14da3519c650e9436e410cfedee6f860312eff9", + "reference": "b14da3519c650e9436e410cfedee6f860312eff9", "shasum": "" }, "require": { @@ -2136,13 +2077,13 @@ "psr/http-server-handler": "^1.0" }, "require-dev": { - "laminas/laminas-coding-standard": "~3.0.0", - "laminas/laminas-diactoros": "^3.4.0", - "phpunit/phpunit": "^10.5.36", - "psalm/plugin-phpunit": "^0.19.0", - "vimeo/psalm": "^5.26.1" + "laminas/laminas-coding-standard": "~3.1.0", + "laminas/laminas-diactoros": "^3.6.0", + "phpunit/phpunit": "^10.5.46", + "psalm/plugin-phpunit": "^0.19.5", + "vimeo/psalm": "^6.10.3" }, - "time": "2024-10-17T20:37:17+00:00", + "time": "2025-05-13T21:21:16+00:00", "type": "library", "extra": { "laminas": { @@ -2186,17 +2127,17 @@ }, { "name": "league/container", - "version": "4.2.0", - "version_normalized": "4.2.0.0", + "version": "4.2.5", + "version_normalized": "4.2.5.0", "source": { "type": "git", "url": "https://github.com/thephpleague/container.git", - "reference": "375d13cb828649599ef5d48a339c4af7a26cd0ab" + "reference": "d3cebb0ff4685ff61c749e54b27db49319e2ec00" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/container/zipball/375d13cb828649599ef5d48a339c4af7a26cd0ab", - "reference": "375d13cb828649599ef5d48a339c4af7a26cd0ab", + "url": "https://api.github.com/repos/thephpleague/container/zipball/d3cebb0ff4685ff61c749e54b27db49319e2ec00", + "reference": "d3cebb0ff4685ff61c749e54b27db49319e2ec00", "shasum": "" }, "require": { @@ -2218,15 +2159,15 @@ "scrutinizer/ocular": "^1.8", "squizlabs/php_codesniffer": "^3.6" }, - "time": "2021-11-16T10:29:06+00:00", + "time": "2025-05-20T12:55:37+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "4.x-dev", - "dev-4.x": "4.x-dev", - "dev-3.x": "3.x-dev", + "dev-1.x": "1.x-dev", "dev-2.x": "2.x-dev", - "dev-1.x": "1.x-dev" + "dev-3.x": "3.x-dev", + "dev-4.x": "4.x-dev", + "dev-master": "4.x-dev" } }, "installation-source": "dist", @@ -2259,7 +2200,7 @@ ], "support": { "issues": "https://github.com/thephpleague/container/issues", - "source": "https://github.com/thephpleague/container/tree/4.2.0" + "source": "https://github.com/thephpleague/container/tree/4.2.5" }, "funding": [ { @@ -2514,19 +2455,95 @@ }, "install-path": "../m1/env" }, + { + "name": "marc-mabe/php-enum", + "version": "v4.7.1", + "version_normalized": "4.7.1.0", + "source": { + "type": "git", + "url": "https://github.com/marc-mabe/php-enum.git", + "reference": "7159809e5cfa041dca28e61f7f7ae58063aae8ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/marc-mabe/php-enum/zipball/7159809e5cfa041dca28e61f7f7ae58063aae8ed", + "reference": "7159809e5cfa041dca28e61f7f7ae58063aae8ed", + "shasum": "" + }, + "require": { + "ext-reflection": "*", + "php": "^7.1 | ^8.0" + }, + "require-dev": { + "phpbench/phpbench": "^0.16.10 || ^1.0.4", + "phpstan/phpstan": "^1.3.1", + "phpunit/phpunit": "^7.5.20 | ^8.5.22 | ^9.5.11", + "vimeo/psalm": "^4.17.0 | ^5.26.1" + }, + "time": "2024-11-28T04:54:44+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-3.x": "3.2-dev", + "dev-master": "4.7-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "MabeEnum\\": "src/" + }, + "classmap": [ + "stubs/Stringable.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Marc Bennewitz", + "email": "dev@mabe.berlin", + "homepage": "https://mabe.berlin/", + "role": "Lead" + } + ], + "description": "Simple and fast implementation of enumerations with native PHP", + "homepage": "https://github.com/marc-mabe/php-enum", + "keywords": [ + "enum", + "enum-map", + "enum-set", + "enumeration", + "enumerator", + "enummap", + "enumset", + "map", + "set", + "type", + "type-hint", + "typehint" + ], + "support": { + "issues": "https://github.com/marc-mabe/php-enum/issues", + "source": "https://github.com/marc-mabe/php-enum/tree/v4.7.1" + }, + "install-path": "../marc-mabe/php-enum" + }, { "name": "masterminds/html5", - "version": "2.9.0", - "version_normalized": "2.9.0.0", + "version": "2.10.0", + "version_normalized": "2.10.0.0", "source": { "type": "git", "url": "https://github.com/Masterminds/html5-php.git", - "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6" + "reference": "fcf91eb64359852f00d921887b219479b4f21251" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/f5ac2c0b0a2eefca70b2ce32a5809992227e75a6", - "reference": "f5ac2c0b0a2eefca70b2ce32a5809992227e75a6", + "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/fcf91eb64359852f00d921887b219479b4f21251", + "reference": "fcf91eb64359852f00d921887b219479b4f21251", "shasum": "" }, "require": { @@ -2536,7 +2553,7 @@ "require-dev": { "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8 || ^9" }, - "time": "2024-03-31T07:05:07+00:00", + "time": "2025-07-25T09:04:22+00:00", "type": "library", "extra": { "branch-alias": { @@ -2580,7 +2597,7 @@ ], "support": { "issues": "https://github.com/Masterminds/html5-php/issues", - "source": "https://github.com/Masterminds/html5-php/tree/2.9.0" + "source": "https://github.com/Masterminds/html5-php/tree/2.10.0" }, "install-path": "../masterminds/html5" }, @@ -2651,17 +2668,17 @@ }, { "name": "myclabs/deep-copy", - "version": "1.11.1", - "version_normalized": "1.11.1.0", + "version": "1.13.4", + "version_normalized": "1.13.4.0", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", - "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", "shasum": "" }, "require": { @@ -2669,14 +2686,15 @@ }, "conflict": { "doctrine/collections": "<1.6.8", - "doctrine/common": "<2.13.3 || >=3,<3.2.2" + "doctrine/common": "<2.13.3 || >=3 <3.2.2" }, "require-dev": { "doctrine/collections": "^1.6.8", "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, - "time": "2023-03-08T13:26:56+00:00", + "time": "2025-08-01T08:46:24+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -2701,7 +2719,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" }, "funding": [ { @@ -2713,28 +2731,28 @@ }, { "name": "nikic/php-parser", - "version": "v4.18.0", - "version_normalized": "4.18.0.0", + "version": "v4.19.4", + "version_normalized": "4.19.4.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999" + "reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999", - "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/715f4d25e225bc47b293a8b997fe6ce99bf987d2", + "reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2", "shasum": "" }, "require": { "ext-tokenizer": "*", - "php": ">=7.0" + "php": ">=7.1" }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, - "time": "2023-12-10T21:03:43+00:00", + "time": "2024-09-29T15:01:53+00:00", "bin": [ "bin/php-parse" ], @@ -2766,7 +2784,7 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.4" }, "install-path": "../nikic/php-parser" }, @@ -2896,34 +2914,34 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "1.26.0", - "version_normalized": "1.26.0.0", + "version": "2.2.0", + "version_normalized": "2.2.0.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "231e3186624c03d7e7c890ec662b81e6b0405227" + "reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/231e3186624c03d7e7c890ec662b81e6b0405227", - "reference": "231e3186624c03d7e7c890ec662b81e6b0405227", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/b9e61a61e39e02dd90944e9115241c7f7e76bfd8", + "reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "php": "^7.4 || ^8.0" }, "require-dev": { "doctrine/annotations": "^2.0", - "nikic/php-parser": "^4.15", + "nikic/php-parser": "^5.3.0", "php-parallel-lint/php-parallel-lint": "^1.2", "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^1.5", - "phpstan/phpstan-phpunit": "^1.1", - "phpstan/phpstan-strict-rules": "^1.0", - "phpunit/phpunit": "^9.5", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.6", "symfony/process": "^5.2" }, - "time": "2024-02-23T16:05:55+00:00", + "time": "2025-07-13T07:04:09+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -2940,52 +2958,52 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/1.26.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.2.0" }, "install-path": "../phpstan/phpdoc-parser" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.31", - "version_normalized": "9.2.31.0", + "version": "9.2.32", + "version_normalized": "9.2.32.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965" + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/48c34b5d8d983006bd2adc2d0de92963b9155965", - "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5", + "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.18 || ^5.0", + "nikic/php-parser": "^4.19.1 || ^5.1.0", "php": ">=7.3", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-text-template": "^2.0.2", - "sebastian/code-unit-reverse-lookup": "^2.0.2", - "sebastian/complexity": "^2.0", - "sebastian/environment": "^5.1.2", - "sebastian/lines-of-code": "^1.0.3", - "sebastian/version": "^3.0.1", - "theseer/tokenizer": "^1.2.0" + "phpunit/php-file-iterator": "^3.0.6", + "phpunit/php-text-template": "^2.0.4", + "sebastian/code-unit-reverse-lookup": "^2.0.3", + "sebastian/complexity": "^2.0.3", + "sebastian/environment": "^5.1.5", + "sebastian/lines-of-code": "^1.0.4", + "sebastian/version": "^3.0.2", + "theseer/tokenizer": "^1.2.3" }, "require-dev": { - "phpunit/phpunit": "^9.3" + "phpunit/phpunit": "^9.6" }, "suggest": { "ext-pcov": "PHP extension that provides line coverage", "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, - "time": "2024-03-02T06:37:42+00:00", + "time": "2024-08-22T04:23:01+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "9.2-dev" + "dev-main": "9.2.x-dev" } }, "installation-source": "dist", @@ -3015,7 +3033,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.31" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.32" }, "funding": [ { @@ -3280,53 +3298,53 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.17", - "version_normalized": "9.6.17.0", + "version": "9.6.23", + "version_normalized": "9.6.23.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "1a156980d78a6666721b7e8e8502fe210b587fcd" + "reference": "43d2cb18d0675c38bd44982a5d1d88f6d53d8d95" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1a156980d78a6666721b7e8e8502fe210b587fcd", - "reference": "1a156980d78a6666721b7e8e8502fe210b587fcd", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/43d2cb18d0675c38bd44982a5d1d88f6d53d8d95", + "reference": "43d2cb18d0675c38bd44982a5d1d88f6d53d8d95", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.3.1 || ^2", + "doctrine/instantiator": "^1.5.0 || ^2", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.3", - "phar-io/version": "^3.0.2", + "myclabs/deep-copy": "^1.13.1", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.28", - "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-code-coverage": "^9.2.32", + "phpunit/php-file-iterator": "^3.0.6", "phpunit/php-invoker": "^3.1.1", - "phpunit/php-text-template": "^2.0.3", - "phpunit/php-timer": "^5.0.2", - "sebastian/cli-parser": "^1.0.1", - "sebastian/code-unit": "^1.0.6", + "phpunit/php-text-template": "^2.0.4", + "phpunit/php-timer": "^5.0.3", + "sebastian/cli-parser": "^1.0.2", + "sebastian/code-unit": "^1.0.8", "sebastian/comparator": "^4.0.8", - "sebastian/diff": "^4.0.3", - "sebastian/environment": "^5.1.3", - "sebastian/exporter": "^4.0.5", - "sebastian/global-state": "^5.0.1", - "sebastian/object-enumerator": "^4.0.3", - "sebastian/resource-operations": "^3.0.3", - "sebastian/type": "^3.2", + "sebastian/diff": "^4.0.6", + "sebastian/environment": "^5.1.5", + "sebastian/exporter": "^4.0.6", + "sebastian/global-state": "^5.0.7", + "sebastian/object-enumerator": "^4.0.4", + "sebastian/resource-operations": "^3.0.4", + "sebastian/type": "^3.2.1", "sebastian/version": "^3.0.2" }, "suggest": { "ext-soap": "To be able to generate mocks based on WSDL files", "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, - "time": "2024-02-23T13:14:51+00:00", + "time": "2025-05-02T06:40:34+00:00", "bin": [ "phpunit" ], @@ -3366,7 +3384,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.17" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.23" }, "funding": [ { @@ -3377,6 +3395,14 @@ "url": "https://github.com/sebastianbergmann", "type": "github" }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, { "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", "type": "tidelift" @@ -3889,17 +3915,17 @@ }, { "name": "psy/psysh", - "version": "v0.12.0", - "version_normalized": "0.12.0.0", + "version": "v0.12.9", + "version_normalized": "0.12.9.0", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "750bf031a48fd07c673dbe3f11f72362ea306d0d" + "reference": "1b801844becfe648985372cb4b12ad6840245ace" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/750bf031a48fd07c673dbe3f11f72362ea306d0d", - "reference": "750bf031a48fd07c673dbe3f11f72362ea306d0d", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/1b801844becfe648985372cb4b12ad6840245ace", + "reference": "1b801844becfe648985372cb4b12ad6840245ace", "shasum": "" }, "require": { @@ -3921,18 +3947,18 @@ "ext-pdo-sqlite": "The doc command requires SQLite to work.", "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well." }, - "time": "2023-12-20T15:28:09+00:00", + "time": "2025-06-23T02:35:06+00:00", "bin": [ "bin/psysh" ], "type": "library", "extra": { - "branch-alias": { - "dev-main": "0.12.x-dev" - }, "bamarni-bin": { "bin-links": false, "forward-command": false + }, + "branch-alias": { + "dev-main": "0.12.x-dev" } }, "installation-source": "dist", @@ -3965,23 +3991,23 @@ ], "support": { "issues": "https://github.com/bobthecow/psysh/issues", - "source": "https://github.com/bobthecow/psysh/tree/v0.12.0" + "source": "https://github.com/bobthecow/psysh/tree/v0.12.9" }, "install-path": "../psy/psysh" }, { "name": "react/promise", - "version": "v3.1.0", - "version_normalized": "3.1.0.0", + "version": "v3.2.0", + "version_normalized": "3.2.0.0", "source": { "type": "git", "url": "https://github.com/reactphp/promise.git", - "reference": "e563d55d1641de1dea9f5e84f3cccc66d2bfe02c" + "reference": "8a164643313c71354582dc850b42b33fa12a4b63" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/promise/zipball/e563d55d1641de1dea9f5e84f3cccc66d2bfe02c", - "reference": "e563d55d1641de1dea9f5e84f3cccc66d2bfe02c", + "url": "https://api.github.com/repos/reactphp/promise/zipball/8a164643313c71354582dc850b42b33fa12a4b63", + "reference": "8a164643313c71354582dc850b42b33fa12a4b63", "shasum": "" }, "require": { @@ -3991,7 +4017,7 @@ "phpstan/phpstan": "1.10.39 || 1.4.10", "phpunit/phpunit": "^9.6 || ^7.5" }, - "time": "2023-11-16T16:21:57+00:00", + "time": "2024-05-24T10:39:05+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -4035,7 +4061,7 @@ ], "support": { "issues": "https://github.com/reactphp/promise/issues", - "source": "https://github.com/reactphp/promise/tree/v3.1.0" + "source": "https://github.com/reactphp/promise/tree/v3.2.0" }, "funding": [ { @@ -4975,17 +5001,17 @@ }, { "name": "sebastian/resource-operations", - "version": "3.0.3", - "version_normalized": "3.0.3.0", + "version": "3.0.4", + "version_normalized": "3.0.4.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e", + "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e", "shasum": "" }, "require": { @@ -4994,11 +5020,11 @@ "require-dev": { "phpunit/phpunit": "^9.0" }, - "time": "2020-09-28T06:45:17+00:00", + "time": "2024-03-14T16:00:52+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-main": "3.0-dev" } }, "installation-source": "dist", @@ -5020,8 +5046,7 @@ "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", "support": { - "issues": "https://github.com/sebastianbergmann/resource-operations/issues", - "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4" }, "funding": [ { @@ -5148,27 +5173,27 @@ }, { "name": "seld/jsonlint", - "version": "1.10.2", - "version_normalized": "1.10.2.0", + "version": "1.11.0", + "version_normalized": "1.11.0.0", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "9bb7db07b5d66d90f6ebf542f09fc67d800e5259" + "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/9bb7db07b5d66d90f6ebf542f09fc67d800e5259", - "reference": "9bb7db07b5d66d90f6ebf542f09fc67d800e5259", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/1748aaf847fc731cfad7725aec413ee46f0cc3a2", + "reference": "1748aaf847fc731cfad7725aec413ee46f0cc3a2", "shasum": "" }, "require": { "php": "^5.3 || ^7.0 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^1.5", + "phpstan/phpstan": "^1.11", "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^8.5.13" }, - "time": "2024-02-07T12:57:50+00:00", + "time": "2024-07-11T14:55:45+00:00", "bin": [ "bin/jsonlint" ], @@ -5199,7 +5224,7 @@ ], "support": { "issues": "https://github.com/Seldaek/jsonlint/issues", - "source": "https://github.com/Seldaek/jsonlint/tree/1.10.2" + "source": "https://github.com/Seldaek/jsonlint/tree/1.11.0" }, "funding": [ { @@ -5330,35 +5355,35 @@ }, { "name": "slevomat/coding-standard", - "version": "8.14.1", - "version_normalized": "8.14.1.0", + "version": "8.20.0", + "version_normalized": "8.20.0.0", "source": { "type": "git", "url": "https://github.com/slevomat/coding-standard.git", - "reference": "fea1fd6f137cc84f9cba0ae30d549615dbc6a926" + "reference": "b4f9f02edd4e6a586777f0cabe8d05574323f3eb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/fea1fd6f137cc84f9cba0ae30d549615dbc6a926", - "reference": "fea1fd6f137cc84f9cba0ae30d549615dbc6a926", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/b4f9f02edd4e6a586777f0cabe8d05574323f3eb", + "reference": "b4f9f02edd4e6a586777f0cabe8d05574323f3eb", "shasum": "" }, "require": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.0", - "php": "^7.2 || ^8.0", - "phpstan/phpdoc-parser": "^1.23.1", - "squizlabs/php_codesniffer": "^3.7.1" + "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.1.2", + "php": "^7.4 || ^8.0", + "phpstan/phpdoc-parser": "^2.2.0", + "squizlabs/php_codesniffer": "^3.13.2" }, "require-dev": { - "phing/phing": "2.17.4", - "php-parallel-lint/php-parallel-lint": "1.3.2", - "phpstan/phpstan": "1.10.37", - "phpstan/phpstan-deprecation-rules": "1.1.4", - "phpstan/phpstan-phpunit": "1.3.14", - "phpstan/phpstan-strict-rules": "1.5.1", - "phpunit/phpunit": "8.5.21|9.6.8|10.3.5" - }, - "time": "2023-10-08T07:28:08+00:00", + "phing/phing": "3.0.1|3.1.0", + "php-parallel-lint/php-parallel-lint": "1.4.0", + "phpstan/phpstan": "2.1.19", + "phpstan/phpstan-deprecation-rules": "2.0.3", + "phpstan/phpstan-phpunit": "2.0.7", + "phpstan/phpstan-strict-rules": "2.0.6", + "phpunit/phpunit": "9.6.8|10.5.48|11.4.4|11.5.27|12.2.7" + }, + "time": "2025-07-26T15:35:10+00:00", "type": "phpcodesniffer-standard", "extra": { "branch-alias": { @@ -5382,7 +5407,7 @@ ], "support": { "issues": "https://github.com/slevomat/coding-standard/issues", - "source": "https://github.com/slevomat/coding-standard/tree/8.14.1" + "source": "https://github.com/slevomat/coding-standard/tree/8.20.0" }, "funding": [ { @@ -5398,17 +5423,17 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.9.0", - "version_normalized": "3.9.0.0", + "version": "3.13.2", + "version_normalized": "3.13.2.0", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "d63cee4890a8afaf86a22e51ad4d97c91dd4579b" + "reference": "5b5e3821314f947dd040c70f7992a64eac89025c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/d63cee4890a8afaf86a22e51ad4d97c91dd4579b", - "reference": "d63cee4890a8afaf86a22e51ad4d97c91dd4579b", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/5b5e3821314f947dd040c70f7992a64eac89025c", + "reference": "5b5e3821314f947dd040c70f7992a64eac89025c", "shasum": "" }, "require": { @@ -5420,7 +5445,7 @@ "require-dev": { "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" }, - "time": "2024-02-16T15:06:51+00:00", + "time": "2025-06-17T22:17:01+00:00", "bin": [ "bin/phpcbf", "bin/phpcs" @@ -5475,23 +5500,27 @@ { "url": "https://opencollective.com/php_codesniffer", "type": "open_collective" + }, + { + "url": "https://thanks.dev/u/gh/phpcsstandards", + "type": "thanks_dev" } ], "install-path": "../squizlabs/php_codesniffer" }, { "name": "symfony/config", - "version": "v6.4.4", - "version_normalized": "6.4.4.0", + "version": "v6.4.24", + "version_normalized": "6.4.24.0", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "6ea4affc27f2086c9d16b92ab5429ce1e3c38047" + "reference": "80e2cf005cf17138c97193be0434cdcfd1b2212e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/6ea4affc27f2086c9d16b92ab5429ce1e3c38047", - "reference": "6ea4affc27f2086c9d16b92ab5429ce1e3c38047", + "url": "https://api.github.com/repos/symfony/config/zipball/80e2cf005cf17138c97193be0434cdcfd1b2212e", + "reference": "80e2cf005cf17138c97193be0434cdcfd1b2212e", "shasum": "" }, "require": { @@ -5511,7 +5540,7 @@ "symfony/service-contracts": "^2.5|^3", "symfony/yaml": "^5.4|^6.0|^7.0" }, - "time": "2024-02-26T07:52:26+00:00", + "time": "2025-07-26T13:50:30+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -5539,7 +5568,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v6.4.4" + "source": "https://github.com/symfony/config/tree/v6.4.24" }, "funding": [ { @@ -5550,6 +5579,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -5559,17 +5592,17 @@ }, { "name": "symfony/console", - "version": "v6.4.4", - "version_normalized": "6.4.4.0", + "version": "v6.4.24", + "version_normalized": "6.4.24.0", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "0d9e4eb5ad413075624378f474c4167ea202de78" + "reference": "59266a5bf6a596e3e0844fd95e6ad7ea3c1d3350" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/0d9e4eb5ad413075624378f474c4167ea202de78", - "reference": "0d9e4eb5ad413075624378f474c4167ea202de78", + "url": "https://api.github.com/repos/symfony/console/zipball/59266a5bf6a596e3e0844fd95e6ad7ea3c1d3350", + "reference": "59266a5bf6a596e3e0844fd95e6ad7ea3c1d3350", "shasum": "" }, "require": { @@ -5602,7 +5635,7 @@ "symfony/stopwatch": "^5.4|^6.0|^7.0", "symfony/var-dumper": "^5.4|^6.0|^7.0" }, - "time": "2024-02-22T20:27:10+00:00", + "time": "2025-07-30T10:38:54+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -5636,7 +5669,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.4" + "source": "https://github.com/symfony/console/tree/v6.4.24" }, "funding": [ { @@ -5647,6 +5680,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -5656,31 +5693,31 @@ }, { "name": "symfony/deprecation-contracts", - "version": "v3.4.0", - "version_normalized": "3.4.0.0", + "version": "v3.6.0", + "version_normalized": "3.6.0.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", "shasum": "" }, "require": { "php": ">=8.1" }, - "time": "2023-05-23T14:45:45+00:00", + "time": "2024-09-25T14:21:43+00:00", "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.4-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" } }, "installation-source": "dist", @@ -5706,7 +5743,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" }, "funding": [ { @@ -5726,17 +5763,17 @@ }, { "name": "symfony/filesystem", - "version": "v7.0.3", - "version_normalized": "7.0.3.0", + "version": "v7.3.2", + "version_normalized": "7.3.2.0", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "2890e3a825bc0c0558526c04499c13f83e1b6b12" + "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/2890e3a825bc0c0558526c04499c13f83e1b6b12", - "reference": "2890e3a825bc0c0558526c04499c13f83e1b6b12", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/edcbb768a186b5c3f25d0643159a787d3e63b7fd", + "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd", "shasum": "" }, "require": { @@ -5744,7 +5781,10 @@ "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.8" }, - "time": "2024-01-23T15:02:46+00:00", + "require-dev": { + "symfony/process": "^6.4|^7.0" + }, + "time": "2025-07-07T08:17:47+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -5772,7 +5812,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.0.3" + "source": "https://github.com/symfony/filesystem/tree/v7.3.2" }, "funding": [ { @@ -5783,6 +5823,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -5792,17 +5836,17 @@ }, { "name": "symfony/finder", - "version": "v7.0.0", - "version_normalized": "7.0.0.0", + "version": "v7.3.2", + "version_normalized": "7.3.2.0", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "6e5688d69f7cfc4ed4a511e96007e06c2d34ce56" + "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/6e5688d69f7cfc4ed4a511e96007e06c2d34ce56", - "reference": "6e5688d69f7cfc4ed4a511e96007e06c2d34ce56", + "url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe", + "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe", "shasum": "" }, "require": { @@ -5811,7 +5855,7 @@ "require-dev": { "symfony/filesystem": "^6.4|^7.0" }, - "time": "2023-10-31T17:59:56+00:00", + "time": "2025-07-15T13:41:35+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -5839,7 +5883,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v7.0.0" + "source": "https://github.com/symfony/finder/tree/v7.3.2" }, "funding": [ { @@ -5850,6 +5894,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -5859,17 +5907,17 @@ }, { "name": "symfony/html-sanitizer", - "version": "v7.2.2", - "version_normalized": "7.2.2.0", + "version": "v7.3.2", + "version_normalized": "7.3.2.0", "source": { "type": "git", "url": "https://github.com/symfony/html-sanitizer.git", - "reference": "f6bc679b024e30f27e33815930a5b8b304c79813" + "reference": "3388e208450fcac57d24aef4d5ae41037b663630" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/html-sanitizer/zipball/f6bc679b024e30f27e33815930a5b8b304c79813", - "reference": "f6bc679b024e30f27e33815930a5b8b304c79813", + "url": "https://api.github.com/repos/symfony/html-sanitizer/zipball/3388e208450fcac57d24aef4d5ae41037b663630", + "reference": "3388e208450fcac57d24aef4d5ae41037b663630", "shasum": "" }, "require": { @@ -5878,7 +5926,7 @@ "masterminds/html5": "^2.7.2", "php": ">=8.2" }, - "time": "2024-12-30T18:35:15+00:00", + "time": "2025-07-10T08:29:33+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -5911,7 +5959,7 @@ "sanitizer" ], "support": { - "source": "https://github.com/symfony/html-sanitizer/tree/v7.2.2" + "source": "https://github.com/symfony/html-sanitizer/tree/v7.3.2" }, "funding": [ { @@ -5922,6 +5970,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -5931,21 +5983,21 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.29.0", - "version_normalized": "1.29.0.0", + "version": "v1.32.0", + "version_normalized": "1.32.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4" + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4", - "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-ctype": "*" @@ -5953,12 +6005,12 @@ "suggest": { "ext-ctype": "For best performance" }, - "time": "2024-01-29T20:11:03+00:00", + "time": "2024-09-09T11:45:10+00:00", "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "installation-source": "dist", @@ -5993,7 +6045,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0" }, "funding": [ { @@ -6013,31 +6065,31 @@ }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.29.0", - "version_normalized": "1.29.0.0", + "version": "v1.32.0", + "version_normalized": "1.32.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f" + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/32a9da87d7b3245e09ac426c83d334ae9f06f80f", - "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" }, - "time": "2024-01-29T20:11:03+00:00", + "time": "2024-09-09T11:45:10+00:00", "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "installation-source": "dist", @@ -6074,7 +6126,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0" }, "funding": [ { @@ -6094,31 +6146,31 @@ }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.29.0", - "version_normalized": "1.29.0.0", + "version": "v1.32.0", + "version_normalized": "1.32.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "bc45c394692b948b4d383a08d7753968bed9a83d" + "reference": "3833d7255cc303546435cb650316bff708a1c75c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d", - "reference": "bc45c394692b948b4d383a08d7753968bed9a83d", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" }, - "time": "2024-01-29T20:11:03+00:00", + "time": "2024-09-09T11:45:10+00:00", "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "installation-source": "dist", @@ -6158,7 +6210,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0" }, "funding": [ { @@ -6178,21 +6230,22 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.29.0", - "version_normalized": "1.29.0.0", + "version": "v1.32.0", + "version_normalized": "1.32.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec" + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec", - "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", "shasum": "" }, "require": { - "php": ">=7.1" + "ext-iconv": "*", + "php": ">=7.2" }, "provide": { "ext-mbstring": "*" @@ -6200,12 +6253,12 @@ "suggest": { "ext-mbstring": "For best performance" }, - "time": "2024-01-29T20:11:03+00:00", + "time": "2024-12-23T08:48:59+00:00", "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "installation-source": "dist", @@ -6241,7 +6294,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0" }, "funding": [ { @@ -6261,28 +6314,28 @@ }, { "name": "symfony/polyfill-php73", - "version": "v1.29.0", - "version_normalized": "1.29.0.0", + "version": "v1.32.0", + "version_normalized": "1.32.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "21bd091060673a1177ae842c0ef8fe30893114d2" + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/21bd091060673a1177ae842c0ef8fe30893114d2", - "reference": "21bd091060673a1177ae842c0ef8fe30893114d2", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f68c03565dcaaf25a890667542e8bd75fe7e5bb", + "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, - "time": "2024-01-29T20:11:03+00:00", + "time": "2024-09-09T11:45:10+00:00", "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "installation-source": "dist", @@ -6320,7 +6373,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.32.0" }, "funding": [ { @@ -6340,28 +6393,28 @@ }, { "name": "symfony/polyfill-php80", - "version": "v1.29.0", - "version_normalized": "1.29.0.0", + "version": "v1.32.0", + "version_normalized": "1.32.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b" + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", - "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, - "time": "2024-01-29T20:11:03+00:00", + "time": "2025-01-02T08:10:11+00:00", "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "installation-source": "dist", @@ -6403,7 +6456,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.32.0" }, "funding": [ { @@ -6423,28 +6476,28 @@ }, { "name": "symfony/polyfill-php81", - "version": "v1.29.0", - "version_normalized": "1.29.0.0", + "version": "v1.32.0", + "version_normalized": "1.32.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "c565ad1e63f30e7477fc40738343c62b40bc672d" + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/c565ad1e63f30e7477fc40738343c62b40bc672d", - "reference": "c565ad1e63f30e7477fc40738343c62b40bc672d", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, - "time": "2024-01-29T20:11:03+00:00", + "time": "2024-09-09T11:45:10+00:00", "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "installation-source": "dist", @@ -6482,7 +6535,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.32.0" }, "funding": [ { @@ -6502,23 +6555,23 @@ }, { "name": "symfony/process", - "version": "v7.2.5", - "version_normalized": "7.2.5.0", + "version": "v7.3.0", + "version_normalized": "7.3.0.0", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "87b7c93e57df9d8e39a093d32587702380ff045d" + "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/87b7c93e57df9d8e39a093d32587702380ff045d", - "reference": "87b7c93e57df9d8e39a093d32587702380ff045d", + "url": "https://api.github.com/repos/symfony/process/zipball/40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", + "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", "shasum": "" }, "require": { "php": ">=8.2" }, - "time": "2025-03-13T12:21:46+00:00", + "time": "2025-04-17T09:11:12+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -6546,7 +6599,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.2.5" + "source": "https://github.com/symfony/process/tree/v7.3.0" }, "funding": [ { @@ -6566,35 +6619,36 @@ }, { "name": "symfony/service-contracts", - "version": "v3.4.1", - "version_normalized": "3.4.1.0", + "version": "v3.6.0", + "version_normalized": "3.6.0.0", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0" + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/fe07cbc8d837f60caf7018068e350cc5163681a0", - "reference": "fe07cbc8d837f60caf7018068e350cc5163681a0", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", "shasum": "" }, "require": { "php": ">=8.1", - "psr/container": "^1.1|^2.0" + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" }, "conflict": { "ext-psr": "<1.1|>=2" }, - "time": "2023-12-26T14:02:43+00:00", + "time": "2025-04-25T09:37:31+00:00", "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.4-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" } }, "installation-source": "dist", @@ -6631,7 +6685,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.4.1" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" }, "funding": [ { @@ -6651,17 +6705,17 @@ }, { "name": "symfony/string", - "version": "v7.0.4", - "version_normalized": "7.0.4.0", + "version": "v7.3.2", + "version_normalized": "7.3.2.0", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "f5832521b998b0bec40bee688ad5de98d4cf111b" + "reference": "42f505aff654e62ac7ac2ce21033818297ca89ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/f5832521b998b0bec40bee688ad5de98d4cf111b", - "reference": "f5832521b998b0bec40bee688ad5de98d4cf111b", + "url": "https://api.github.com/repos/symfony/string/zipball/42f505aff654e62ac7ac2ce21033818297ca89ca", + "reference": "42f505aff654e62ac7ac2ce21033818297ca89ca", "shasum": "" }, "require": { @@ -6675,13 +6729,14 @@ "symfony/translation-contracts": "<2.5" }, "require-dev": { + "symfony/emoji": "^7.1", "symfony/error-handler": "^6.4|^7.0", "symfony/http-client": "^6.4|^7.0", "symfony/intl": "^6.4|^7.0", "symfony/translation-contracts": "^2.5|^3.0", "symfony/var-exporter": "^6.4|^7.0" }, - "time": "2024-02-01T13:17:36+00:00", + "time": "2025-07-10T08:47:49+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -6720,7 +6775,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.0.4" + "source": "https://github.com/symfony/string/tree/v7.3.2" }, "funding": [ { @@ -6731,6 +6786,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -6740,35 +6799,35 @@ }, { "name": "symfony/var-dumper", - "version": "v7.0.4", - "version_normalized": "7.0.4.0", + "version": "v7.3.2", + "version_normalized": "7.3.2.0", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "e03ad7c1535e623edbb94c22cc42353e488c6670" + "reference": "53205bea27450dc5c65377518b3275e126d45e75" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/e03ad7c1535e623edbb94c22cc42353e488c6670", - "reference": "e03ad7c1535e623edbb94c22cc42353e488c6670", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/53205bea27450dc5c65377518b3275e126d45e75", + "reference": "53205bea27450dc5c65377518b3275e126d45e75", "shasum": "" }, "require": { "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0" }, "conflict": { "symfony/console": "<6.4" }, "require-dev": { - "ext-iconv": "*", "symfony/console": "^6.4|^7.0", "symfony/http-kernel": "^6.4|^7.0", "symfony/process": "^6.4|^7.0", "symfony/uid": "^6.4|^7.0", - "twig/twig": "^3.0.4" + "twig/twig": "^3.12" }, - "time": "2024-02-15T11:33:06+00:00", + "time": "2025-07-29T20:02:46+00:00", "bin": [ "Resources/bin/var-dump-server" ], @@ -6806,7 +6865,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.0.4" + "source": "https://github.com/symfony/var-dumper/tree/v7.3.2" }, "funding": [ { @@ -6817,6 +6876,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -6879,34 +6942,38 @@ }, { "name": "twig/markdown-extra", - "version": "v3.8.0", - "version_normalized": "3.8.0.0", + "version": "v3.21.0", + "version_normalized": "3.21.0.0", "source": { "type": "git", "url": "https://github.com/twigphp/markdown-extra.git", - "reference": "b6e4954ab60030233df5d293886b5404558daac8" + "reference": "f4616e1dd375209dacf6026f846e6b537d036ce4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/markdown-extra/zipball/b6e4954ab60030233df5d293886b5404558daac8", - "reference": "b6e4954ab60030233df5d293886b5404558daac8", + "url": "https://api.github.com/repos/twigphp/markdown-extra/zipball/f4616e1dd375209dacf6026f846e6b537d036ce4", + "reference": "f4616e1dd375209dacf6026f846e6b537d036ce4", "shasum": "" }, "require": { - "php": ">=7.2.5", - "twig/twig": "^3.0" + "php": ">=8.1.0", + "symfony/deprecation-contracts": "^2.5|^3", + "twig/twig": "^3.13|^4.0" }, "require-dev": { - "erusev/parsedown": "^1.7", + "erusev/parsedown": "dev-master as 1.x-dev", "league/commonmark": "^1.0|^2.0", "league/html-to-markdown": "^4.8|^5.0", "michelf/php-markdown": "^1.8|^2.0", "symfony/phpunit-bridge": "^6.4|^7.0" }, - "time": "2023-11-21T14:02:01+00:00", + "time": "2025-01-31T20:45:36+00:00", "type": "library", "installation-source": "dist", "autoload": { + "files": [ + "Resources/functions.php" + ], "psr-4": { "Twig\\Extra\\Markdown\\": "" }, @@ -6934,7 +7001,7 @@ "twig" ], "support": { - "source": "https://github.com/twigphp/markdown-extra/tree/v3.8.0" + "source": "https://github.com/twigphp/markdown-extra/tree/v3.21.0" }, "funding": [ { @@ -6950,17 +7017,17 @@ }, { "name": "twig/twig", - "version": "v3.20.0", - "version_normalized": "3.20.0.0", + "version": "v3.21.1", + "version_normalized": "3.21.1.0", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "3468920399451a384bef53cf7996965f7cd40183" + "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/3468920399451a384bef53cf7996965f7cd40183", - "reference": "3468920399451a384bef53cf7996965f7cd40183", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/285123877d4dd97dd7c11842ac5fb7e86e60d81d", + "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d", "shasum": "" }, "require": { @@ -6974,7 +7041,7 @@ "psr/container": "^1.0|^2.0", "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" }, - "time": "2025-02-13T08:34:43+00:00", + "time": "2025-05-03T07:21:55+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -7016,7 +7083,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.20.0" + "source": "https://github.com/twigphp/Twig/tree/v3.21.1" }, "funding": [ { @@ -7052,6 +7119,7 @@ "josegonzalez/dotenv", "justinrainbow/json-schema", "m1/env", + "marc-mabe/php-enum", "myclabs/deep-copy", "nikic/php-parser", "phar-io/manifest", diff --git a/app/vendor/composer/installed.php b/app/vendor/composer/installed.php index f84ac603a..c9966e3b1 100644 --- a/app/vendor/composer/installed.php +++ b/app/vendor/composer/installed.php @@ -3,7 +3,7 @@ 'name' => 'cakephp/app', 'pretty_version' => 'dev-develop', 'version' => 'dev-develop', - 'reference' => 'c74c4238cec5e773ee785ea12ff87f2e2d371be0', + 'reference' => '4d0ed8e6d8dc3b8ed3ad71cea95fb4d4e015eeb0', 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -22,7 +22,7 @@ 'cakephp/app' => array( 'pretty_version' => 'dev-develop', 'version' => 'dev-develop', - 'reference' => 'c74c4238cec5e773ee785ea12ff87f2e2d371be0', + 'reference' => '4d0ed8e6d8dc3b8ed3ad71cea95fb4d4e015eeb0', 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -40,22 +40,22 @@ 'cakephp/cache' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '4.6.0', + 0 => '4.6.2', ), ), 'cakephp/cakephp' => array( - 'pretty_version' => '4.6.0', - 'version' => '4.6.0.0', - 'reference' => 'b8585672346c0654311c77500ce613cdf37687cc', + 'pretty_version' => '4.6.2', + 'version' => '4.6.2.0', + 'reference' => 'db79f771fa3f0e7492840ad9fb5b89c01519a500', 'type' => 'library', 'install_path' => __DIR__ . '/../cakephp/cakephp', 'aliases' => array(), 'dev_requirement' => false, ), 'cakephp/cakephp-codesniffer' => array( - 'pretty_version' => '4.7.0', - 'version' => '4.7.0.0', - 'reference' => '24fa2321d54e5251ac2f59dd92dd2066f0b0bdae', + 'pretty_version' => '4.7.1', + 'version' => '4.7.1.0', + 'reference' => 'd09f5945bec4bf82581c52eabe7cea7b92cba6e3', 'type' => 'phpcodesniffer-standard', 'install_path' => __DIR__ . '/../cakephp/cakephp-codesniffer', 'aliases' => array(), @@ -73,31 +73,31 @@ 'cakephp/collection' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '4.6.0', + 0 => '4.6.2', ), ), 'cakephp/console' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '4.6.0', + 0 => '4.6.2', ), ), 'cakephp/core' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '4.6.0', + 0 => '4.6.2', ), ), 'cakephp/database' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '4.6.0', + 0 => '4.6.2', ), ), 'cakephp/datasource' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '4.6.0', + 0 => '4.6.2', ), ), 'cakephp/debug_kit' => array( @@ -112,37 +112,37 @@ 'cakephp/event' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '4.6.0', + 0 => '4.6.2', ), ), 'cakephp/filesystem' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '4.6.0', + 0 => '4.6.2', ), ), 'cakephp/form' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '4.6.0', + 0 => '4.6.2', ), ), 'cakephp/http' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '4.6.0', + 0 => '4.6.2', ), ), 'cakephp/i18n' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '4.6.0', + 0 => '4.6.2', ), ), 'cakephp/log' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '4.6.0', + 0 => '4.6.2', ), ), 'cakephp/migrations' => array( @@ -157,7 +157,7 @@ 'cakephp/orm' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '4.6.0', + 0 => '4.6.2', ), ), 'cakephp/plugin-installer' => array( @@ -170,9 +170,9 @@ 'dev_requirement' => false, ), 'cakephp/twig-view' => array( - 'pretty_version' => '1.3.0', - 'version' => '1.3.0.0', - 'reference' => '14df50360b809a171d0688020fbdfe513763f89b', + 'pretty_version' => '1.3.1', + 'version' => '1.3.1.0', + 'reference' => 'e4a18e91e004730ccbaf796bde60612e8afac0e8', 'type' => 'cakephp-plugin', 'install_path' => __DIR__ . '/../cakephp/twig-view', 'aliases' => array(), @@ -181,37 +181,37 @@ 'cakephp/utility' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '4.6.0', + 0 => '4.6.2', ), ), 'cakephp/validation' => array( 'dev_requirement' => false, 'replaced' => array( - 0 => '4.6.0', + 0 => '4.6.2', ), ), 'composer/ca-bundle' => array( - 'pretty_version' => '1.5.6', - 'version' => '1.5.6.0', - 'reference' => 'f65c239c970e7f072f067ab78646e9f0b2935175', + 'pretty_version' => '1.5.7', + 'version' => '1.5.7.0', + 'reference' => 'd665d22c417056996c59019579f1967dfe5c1e82', 'type' => 'library', 'install_path' => __DIR__ . '/./ca-bundle', 'aliases' => array(), 'dev_requirement' => false, ), 'composer/class-map-generator' => array( - 'pretty_version' => '1.1.0', - 'version' => '1.1.0.0', - 'reference' => '953cc4ea32e0c31f2185549c7d216d7921f03da9', + 'pretty_version' => '1.6.1', + 'version' => '1.6.1.0', + 'reference' => '134b705ddb0025d397d8318a75825fe3c9d1da34', 'type' => 'library', 'install_path' => __DIR__ . '/./class-map-generator', 'aliases' => array(), 'dev_requirement' => true, ), 'composer/composer' => array( - 'pretty_version' => '2.7.6', - 'version' => '2.7.6.0', - 'reference' => 'fabd995783b633829fd4280e272284b39b6ae702', + 'pretty_version' => '2.8.10', + 'version' => '2.8.10.0', + 'reference' => '53834f587d7ab2527eb237459d7b94d1fb9d4c5a', 'type' => 'library', 'install_path' => __DIR__ . '/./composer', 'aliases' => array(), @@ -227,81 +227,72 @@ 'dev_requirement' => true, ), 'composer/pcre' => array( - 'pretty_version' => '3.1.1', - 'version' => '3.1.1.0', - 'reference' => '00104306927c7a0919b4ced2aaa6782c1e61a3c9', + 'pretty_version' => '3.3.2', + 'version' => '3.3.2.0', + 'reference' => 'b2bed4734f0cc156ee1fe9c0da2550420d99a21e', 'type' => 'library', 'install_path' => __DIR__ . '/./pcre', 'aliases' => array(), 'dev_requirement' => true, ), 'composer/semver' => array( - 'pretty_version' => '3.4.0', - 'version' => '3.4.0.0', - 'reference' => '35e8d0af4486141bc745f23a29cc2091eb624a32', + 'pretty_version' => '3.4.3', + 'version' => '3.4.3.0', + 'reference' => '4313d26ada5e0c4edfbd1dc481a92ff7bff91f12', 'type' => 'library', 'install_path' => __DIR__ . '/./semver', 'aliases' => array(), 'dev_requirement' => true, ), 'composer/spdx-licenses' => array( - 'pretty_version' => '1.5.8', - 'version' => '1.5.8.0', - 'reference' => '560bdcf8deb88ae5d611c80a2de8ea9d0358cc0a', + 'pretty_version' => '1.5.9', + 'version' => '1.5.9.0', + 'reference' => 'edf364cefe8c43501e21e88110aac10b284c3c9f', 'type' => 'library', 'install_path' => __DIR__ . '/./spdx-licenses', 'aliases' => array(), 'dev_requirement' => true, ), 'composer/xdebug-handler' => array( - 'pretty_version' => '3.0.3', - 'version' => '3.0.3.0', - 'reference' => 'ced299686f41dce890debac69273b47ffe98a40c', + 'pretty_version' => '3.0.5', + 'version' => '3.0.5.0', + 'reference' => '6c1925561632e83d60a44492e0b344cf48ab85ef', 'type' => 'library', 'install_path' => __DIR__ . '/./xdebug-handler', 'aliases' => array(), 'dev_requirement' => true, ), 'dealerdirect/phpcodesniffer-composer-installer' => array( - 'pretty_version' => 'v1.0.0', - 'version' => '1.0.0.0', - 'reference' => '4be43904336affa5c2f70744a348312336afd0da', + 'pretty_version' => 'v1.1.2', + 'version' => '1.1.2.0', + 'reference' => 'e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1', 'type' => 'composer-plugin', 'install_path' => __DIR__ . '/../dealerdirect/phpcodesniffer-composer-installer', 'aliases' => array(), 'dev_requirement' => true, ), - 'doctrine/cache' => array( - 'pretty_version' => '2.2.0', - 'version' => '2.2.0.0', - 'reference' => '1ca8f21980e770095a31456042471a57bc4c68fb', - 'type' => 'library', - 'install_path' => __DIR__ . '/../doctrine/cache', - 'aliases' => array(), - 'dev_requirement' => false, - ), 'doctrine/dbal' => array( - 'pretty_version' => '3.8.2', - 'version' => '3.8.2.0', - 'reference' => 'a19a1d05ca211f41089dffcc387733a6875196cb', + 'pretty_version' => '3.10.0', + 'version' => '3.10.0.0', + 'reference' => '1cf840d696373ea0d58ad0a8875c0fadcfc67214', 'type' => 'library', 'install_path' => __DIR__ . '/../doctrine/dbal', 'aliases' => array(), 'dev_requirement' => false, ), 'doctrine/deprecations' => array( - 'pretty_version' => '1.1.3', - 'version' => '1.1.3.0', - 'reference' => 'dfbaa3c2d2e9a9df1118213f3b8b0c597bb99fab', + 'pretty_version' => '1.1.5', + 'version' => '1.1.5.0', + 'reference' => '459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38', 'type' => 'library', 'install_path' => __DIR__ . '/../doctrine/deprecations', 'aliases' => array(), 'dev_requirement' => false, ), 'doctrine/event-manager' => array( - 'pretty_version' => '2.0.0', - 'version' => '2.0.0.0', - 'reference' => '750671534e0241a7c50ea5b43f67e23eb5c96f32', + 'pretty_version' => '2.0.1', + 'version' => '2.0.1.0', + 'reference' => 'b680156fa328f1dfd874fd48c7026c41570b9c6e', 'type' => 'library', 'install_path' => __DIR__ . '/../doctrine/event-manager', 'aliases' => array(), @@ -317,18 +308,18 @@ 'dev_requirement' => true, ), 'doctrine/sql-formatter' => array( - 'pretty_version' => '1.2.0', - 'version' => '1.2.0.0', - 'reference' => 'a321d114e0a18e6497f8a2cd6f890e000cc17ecc', + 'pretty_version' => '1.5.2', + 'version' => '1.5.2.0', + 'reference' => 'd6d00aba6fd2957fe5216fe2b7673e9985db20c8', 'type' => 'library', 'install_path' => __DIR__ . '/../doctrine/sql-formatter', 'aliases' => array(), 'dev_requirement' => true, ), 'jasny/twig-extensions' => array( - 'pretty_version' => 'v1.3.0', - 'version' => '1.3.0.0', - 'reference' => 'a694eb02f6fc14ff8e2fceb8b80882c0c926102b', + 'pretty_version' => 'v1.3.1', + 'version' => '1.3.1.0', + 'reference' => '8a5ca5f49317bf421a519556ad2e876820d41e01', 'type' => 'library', 'install_path' => __DIR__ . '/../jasny/twig-extensions', 'aliases' => array(), @@ -344,9 +335,9 @@ 'dev_requirement' => true, ), 'justinrainbow/json-schema' => array( - 'pretty_version' => 'v5.2.13', - 'version' => '5.2.13.0', - 'reference' => 'fbbe7e5d79f618997bc3332a6f49246036c45793', + 'pretty_version' => '6.4.2', + 'version' => '6.4.2.0', + 'reference' => 'ce1fd2d47799bb60668643bc6220f6278a4c1d02', 'type' => 'library', 'install_path' => __DIR__ . '/../justinrainbow/json-schema', 'aliases' => array(), @@ -362,18 +353,18 @@ 'dev_requirement' => false, ), 'laminas/laminas-httphandlerrunner' => array( - 'pretty_version' => '2.11.0', - 'version' => '2.11.0.0', - 'reference' => 'c428d9f67f280d155637cbe2b7245b5188c8cdae', + 'pretty_version' => '2.12.0', + 'version' => '2.12.0.0', + 'reference' => 'b14da3519c650e9436e410cfedee6f860312eff9', 'type' => 'library', 'install_path' => __DIR__ . '/../laminas/laminas-httphandlerrunner', 'aliases' => array(), 'dev_requirement' => false, ), 'league/container' => array( - 'pretty_version' => '4.2.0', - 'version' => '4.2.0.0', - 'reference' => '375d13cb828649599ef5d48a339c4af7a26cd0ab', + 'pretty_version' => '4.2.5', + 'version' => '4.2.5.0', + 'reference' => 'd3cebb0ff4685ff61c749e54b27db49319e2ec00', 'type' => 'library', 'install_path' => __DIR__ . '/../league/container', 'aliases' => array(), @@ -406,10 +397,19 @@ 'aliases' => array(), 'dev_requirement' => true, ), + 'marc-mabe/php-enum' => array( + 'pretty_version' => 'v4.7.1', + 'version' => '4.7.1.0', + 'reference' => '7159809e5cfa041dca28e61f7f7ae58063aae8ed', + 'type' => 'library', + 'install_path' => __DIR__ . '/../marc-mabe/php-enum', + 'aliases' => array(), + 'dev_requirement' => true, + ), 'masterminds/html5' => array( - 'pretty_version' => '2.9.0', - 'version' => '2.9.0.0', - 'reference' => 'f5ac2c0b0a2eefca70b2ce32a5809992227e75a6', + 'pretty_version' => '2.10.0', + 'version' => '2.10.0.0', + 'reference' => 'fcf91eb64359852f00d921887b219479b4f21251', 'type' => 'library', 'install_path' => __DIR__ . '/../masterminds/html5', 'aliases' => array(), @@ -425,18 +425,18 @@ 'dev_requirement' => false, ), 'myclabs/deep-copy' => array( - 'pretty_version' => '1.11.1', - 'version' => '1.11.1.0', - 'reference' => '7284c22080590fb39f2ffa3e9057f10a4ddd0e0c', + 'pretty_version' => '1.13.4', + 'version' => '1.13.4.0', + 'reference' => '07d290f0c47959fd5eed98c95ee5602db07e0b6a', 'type' => 'library', 'install_path' => __DIR__ . '/../myclabs/deep-copy', 'aliases' => array(), 'dev_requirement' => true, ), 'nikic/php-parser' => array( - 'pretty_version' => 'v4.18.0', - 'version' => '4.18.0.0', - 'reference' => '1bcbb2179f97633e98bbbc87044ee2611c7d7999', + 'pretty_version' => 'v4.19.4', + 'version' => '4.19.4.0', + 'reference' => '715f4d25e225bc47b293a8b997fe6ce99bf987d2', 'type' => 'library', 'install_path' => __DIR__ . '/../nikic/php-parser', 'aliases' => array(), @@ -467,18 +467,18 @@ 'dev_requirement' => true, ), 'phpstan/phpdoc-parser' => array( - 'pretty_version' => '1.26.0', - 'version' => '1.26.0.0', - 'reference' => '231e3186624c03d7e7c890ec662b81e6b0405227', + 'pretty_version' => '2.2.0', + 'version' => '2.2.0.0', + 'reference' => 'b9e61a61e39e02dd90944e9115241c7f7e76bfd8', 'type' => 'library', 'install_path' => __DIR__ . '/../phpstan/phpdoc-parser', 'aliases' => array(), 'dev_requirement' => true, ), 'phpunit/php-code-coverage' => array( - 'pretty_version' => '9.2.31', - 'version' => '9.2.31.0', - 'reference' => '48c34b5d8d983006bd2adc2d0de92963b9155965', + 'pretty_version' => '9.2.32', + 'version' => '9.2.32.0', + 'reference' => '85402a822d1ecf1db1096959413d35e1c37cf1a5', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/php-code-coverage', 'aliases' => array(), @@ -521,9 +521,9 @@ 'dev_requirement' => true, ), 'phpunit/phpunit' => array( - 'pretty_version' => '9.6.17', - 'version' => '9.6.17.0', - 'reference' => '1a156980d78a6666721b7e8e8502fe210b587fcd', + 'pretty_version' => '9.6.23', + 'version' => '9.6.23.0', + 'reference' => '43d2cb18d0675c38bd44982a5d1d88f6d53d8d95', 'type' => 'library', 'install_path' => __DIR__ . '/../phpunit/phpunit', 'aliases' => array(), @@ -550,8 +550,8 @@ 'psr/container-implementation' => array( 'dev_requirement' => false, 'provided' => array( - 0 => '^1.0 || ^2.0', - 1 => '^1.0', + 0 => '^1.0', + 1 => '^1.0 || ^2.0', ), ), 'psr/http-client' => array( @@ -641,8 +641,8 @@ 'psr/log-implementation' => array( 'dev_requirement' => false, 'provided' => array( - 0 => '^1.0 || ^2.0', - 1 => '1.0|2.0|3.0', + 0 => '1.0|2.0|3.0', + 1 => '^1.0 || ^2.0', ), ), 'psr/simple-cache' => array( @@ -661,18 +661,18 @@ ), ), 'psy/psysh' => array( - 'pretty_version' => 'v0.12.0', - 'version' => '0.12.0.0', - 'reference' => '750bf031a48fd07c673dbe3f11f72362ea306d0d', + 'pretty_version' => 'v0.12.9', + 'version' => '0.12.9.0', + 'reference' => '1b801844becfe648985372cb4b12ad6840245ace', 'type' => 'library', 'install_path' => __DIR__ . '/../psy/psysh', 'aliases' => array(), 'dev_requirement' => true, ), 'react/promise' => array( - 'pretty_version' => 'v3.1.0', - 'version' => '3.1.0.0', - 'reference' => 'e563d55d1641de1dea9f5e84f3cccc66d2bfe02c', + 'pretty_version' => 'v3.2.0', + 'version' => '3.2.0.0', + 'reference' => '8a164643313c71354582dc850b42b33fa12a4b63', 'type' => 'library', 'install_path' => __DIR__ . '/../react/promise', 'aliases' => array(), @@ -805,9 +805,9 @@ 'dev_requirement' => true, ), 'sebastian/resource-operations' => array( - 'pretty_version' => '3.0.3', - 'version' => '3.0.3.0', - 'reference' => '0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8', + 'pretty_version' => '3.0.4', + 'version' => '3.0.4.0', + 'reference' => '05d5692a7993ecccd56a03e40cd7e5b09b1d404e', 'type' => 'library', 'install_path' => __DIR__ . '/../sebastian/resource-operations', 'aliases' => array(), @@ -832,9 +832,9 @@ 'dev_requirement' => true, ), 'seld/jsonlint' => array( - 'pretty_version' => '1.10.2', - 'version' => '1.10.2.0', - 'reference' => '9bb7db07b5d66d90f6ebf542f09fc67d800e5259', + 'pretty_version' => '1.11.0', + 'version' => '1.11.0.0', + 'reference' => '1748aaf847fc731cfad7725aec413ee46f0cc3a2', 'type' => 'library', 'install_path' => __DIR__ . '/../seld/jsonlint', 'aliases' => array(), @@ -859,171 +859,171 @@ 'dev_requirement' => true, ), 'slevomat/coding-standard' => array( - 'pretty_version' => '8.14.1', - 'version' => '8.14.1.0', - 'reference' => 'fea1fd6f137cc84f9cba0ae30d549615dbc6a926', + 'pretty_version' => '8.20.0', + 'version' => '8.20.0.0', + 'reference' => 'b4f9f02edd4e6a586777f0cabe8d05574323f3eb', 'type' => 'phpcodesniffer-standard', 'install_path' => __DIR__ . '/../slevomat/coding-standard', 'aliases' => array(), 'dev_requirement' => true, ), 'squizlabs/php_codesniffer' => array( - 'pretty_version' => '3.9.0', - 'version' => '3.9.0.0', - 'reference' => 'd63cee4890a8afaf86a22e51ad4d97c91dd4579b', + 'pretty_version' => '3.13.2', + 'version' => '3.13.2.0', + 'reference' => '5b5e3821314f947dd040c70f7992a64eac89025c', 'type' => 'library', 'install_path' => __DIR__ . '/../squizlabs/php_codesniffer', 'aliases' => array(), 'dev_requirement' => true, ), 'symfony/config' => array( - 'pretty_version' => 'v6.4.4', - 'version' => '6.4.4.0', - 'reference' => '6ea4affc27f2086c9d16b92ab5429ce1e3c38047', + 'pretty_version' => 'v6.4.24', + 'version' => '6.4.24.0', + 'reference' => '80e2cf005cf17138c97193be0434cdcfd1b2212e', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/config', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/console' => array( - 'pretty_version' => 'v6.4.4', - 'version' => '6.4.4.0', - 'reference' => '0d9e4eb5ad413075624378f474c4167ea202de78', + 'pretty_version' => 'v6.4.24', + 'version' => '6.4.24.0', + 'reference' => '59266a5bf6a596e3e0844fd95e6ad7ea3c1d3350', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/console', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/deprecation-contracts' => array( - 'pretty_version' => 'v3.4.0', - 'version' => '3.4.0.0', - 'reference' => '7c3aff79d10325257a001fcf92d991f24fc967cf', + 'pretty_version' => 'v3.6.0', + 'version' => '3.6.0.0', + 'reference' => '63afe740e99a13ba87ec199bb07bbdee937a5b62', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/deprecation-contracts', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/filesystem' => array( - 'pretty_version' => 'v7.0.3', - 'version' => '7.0.3.0', - 'reference' => '2890e3a825bc0c0558526c04499c13f83e1b6b12', + 'pretty_version' => 'v7.3.2', + 'version' => '7.3.2.0', + 'reference' => 'edcbb768a186b5c3f25d0643159a787d3e63b7fd', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/filesystem', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/finder' => array( - 'pretty_version' => 'v7.0.0', - 'version' => '7.0.0.0', - 'reference' => '6e5688d69f7cfc4ed4a511e96007e06c2d34ce56', + 'pretty_version' => 'v7.3.2', + 'version' => '7.3.2.0', + 'reference' => '2a6614966ba1074fa93dae0bc804227422df4dfe', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/finder', 'aliases' => array(), 'dev_requirement' => true, ), 'symfony/html-sanitizer' => array( - 'pretty_version' => 'v7.2.2', - 'version' => '7.2.2.0', - 'reference' => 'f6bc679b024e30f27e33815930a5b8b304c79813', + 'pretty_version' => 'v7.3.2', + 'version' => '7.3.2.0', + 'reference' => '3388e208450fcac57d24aef4d5ae41037b663630', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/html-sanitizer', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/polyfill-ctype' => array( - 'pretty_version' => 'v1.29.0', - 'version' => '1.29.0.0', - 'reference' => 'ef4d7e442ca910c4764bce785146269b30cb5fc4', + 'pretty_version' => 'v1.32.0', + 'version' => '1.32.0.0', + 'reference' => 'a3cc8b044a6ea513310cbd48ef7333b384945638', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-ctype', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/polyfill-intl-grapheme' => array( - 'pretty_version' => 'v1.29.0', - 'version' => '1.29.0.0', - 'reference' => '32a9da87d7b3245e09ac426c83d334ae9f06f80f', + 'pretty_version' => 'v1.32.0', + 'version' => '1.32.0.0', + 'reference' => 'b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-grapheme', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/polyfill-intl-normalizer' => array( - 'pretty_version' => 'v1.29.0', - 'version' => '1.29.0.0', - 'reference' => 'bc45c394692b948b4d383a08d7753968bed9a83d', + 'pretty_version' => 'v1.32.0', + 'version' => '1.32.0.0', + 'reference' => '3833d7255cc303546435cb650316bff708a1c75c', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/polyfill-mbstring' => array( - 'pretty_version' => 'v1.29.0', - 'version' => '1.29.0.0', - 'reference' => '9773676c8a1bb1f8d4340a62efe641cf76eda7ec', + 'pretty_version' => 'v1.32.0', + 'version' => '1.32.0.0', + 'reference' => '6d857f4d76bd4b343eac26d6b539585d2bc56493', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-mbstring', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/polyfill-php73' => array( - 'pretty_version' => 'v1.29.0', - 'version' => '1.29.0.0', - 'reference' => '21bd091060673a1177ae842c0ef8fe30893114d2', + 'pretty_version' => 'v1.32.0', + 'version' => '1.32.0.0', + 'reference' => '0f68c03565dcaaf25a890667542e8bd75fe7e5bb', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-php73', 'aliases' => array(), 'dev_requirement' => true, ), 'symfony/polyfill-php80' => array( - 'pretty_version' => 'v1.29.0', - 'version' => '1.29.0.0', - 'reference' => '87b68208d5c1188808dd7839ee1e6c8ec3b02f1b', + 'pretty_version' => 'v1.32.0', + 'version' => '1.32.0.0', + 'reference' => '0cc9dd0f17f61d8131e7df6b84bd344899fe2608', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-php80', 'aliases' => array(), 'dev_requirement' => true, ), 'symfony/polyfill-php81' => array( - 'pretty_version' => 'v1.29.0', - 'version' => '1.29.0.0', - 'reference' => 'c565ad1e63f30e7477fc40738343c62b40bc672d', + 'pretty_version' => 'v1.32.0', + 'version' => '1.32.0.0', + 'reference' => '4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-php81', 'aliases' => array(), 'dev_requirement' => true, ), 'symfony/process' => array( - 'pretty_version' => 'v7.2.5', - 'version' => '7.2.5.0', - 'reference' => '87b7c93e57df9d8e39a093d32587702380ff045d', + 'pretty_version' => 'v7.3.0', + 'version' => '7.3.0.0', + 'reference' => '40c295f2deb408d5e9d2d32b8ba1dd61e36f05af', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/process', 'aliases' => array(), 'dev_requirement' => true, ), 'symfony/service-contracts' => array( - 'pretty_version' => 'v3.4.1', - 'version' => '3.4.1.0', - 'reference' => 'fe07cbc8d837f60caf7018068e350cc5163681a0', + 'pretty_version' => 'v3.6.0', + 'version' => '3.6.0.0', + 'reference' => 'f021b05a130d35510bd6b25fe9053c2a8a15d5d4', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/service-contracts', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/string' => array( - 'pretty_version' => 'v7.0.4', - 'version' => '7.0.4.0', - 'reference' => 'f5832521b998b0bec40bee688ad5de98d4cf111b', + 'pretty_version' => 'v7.3.2', + 'version' => '7.3.2.0', + 'reference' => '42f505aff654e62ac7ac2ce21033818297ca89ca', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/string', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/var-dumper' => array( - 'pretty_version' => 'v7.0.4', - 'version' => '7.0.4.0', - 'reference' => 'e03ad7c1535e623edbb94c22cc42353e488c6670', + 'pretty_version' => 'v7.3.2', + 'version' => '7.3.2.0', + 'reference' => '53205bea27450dc5c65377518b3275e126d45e75', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/var-dumper', 'aliases' => array(), @@ -1039,18 +1039,18 @@ 'dev_requirement' => true, ), 'twig/markdown-extra' => array( - 'pretty_version' => 'v3.8.0', - 'version' => '3.8.0.0', - 'reference' => 'b6e4954ab60030233df5d293886b5404558daac8', + 'pretty_version' => 'v3.21.0', + 'version' => '3.21.0.0', + 'reference' => 'f4616e1dd375209dacf6026f846e6b537d036ce4', 'type' => 'library', 'install_path' => __DIR__ . '/../twig/markdown-extra', 'aliases' => array(), 'dev_requirement' => true, ), 'twig/twig' => array( - 'pretty_version' => 'v3.20.0', - 'version' => '3.20.0.0', - 'reference' => '3468920399451a384bef53cf7996965f7cd40183', + 'pretty_version' => 'v3.21.1', + 'version' => '3.21.1.0', + 'reference' => '285123877d4dd97dd7c11842ac5fb7e86e60d81d', 'type' => 'library', 'install_path' => __DIR__ . '/../twig/twig', 'aliases' => array(), diff --git a/app/vendor/composer/pcre/README.md b/app/vendor/composer/pcre/README.md index 973b17d8d..490651499 100644 --- a/app/vendor/composer/pcre/README.md +++ b/app/vendor/composer/pcre/README.md @@ -12,7 +12,8 @@ to understand the implications. It thus makes it easier to work with static analysis tools like PHPStan or Psalm as it simplifies and reduces the possible return values from all the `preg_*` functions which -are quite packed with edge cases. +are quite packed with edge cases. As of v2.2.0 / v3.2.0 the library also comes with a +[PHPStan extension](#phpstan-extension) for parsing regular expressions and giving you even better output types. This library is a thin wrapper around `preg_*` functions with [some limitations](#restrictions--limitations). If you are looking for a richer API to handle regular expressions have a look at @@ -175,6 +176,13 @@ preg_match('/(a)(b)*(c)(d)*/', 'ac', $matches, $flags); | group 2 (any unmatched group preceding one that matched) is set to `''`. You cannot tell if it matched an empty string or did not match at all | group 2 is `null` when unmatched and a string if it matched, easy to check for | | group 4 (any optional group without a matching one following) is missing altogether. So you have to check with `isset()`, but really you want `isset($m[4]) && $m[4] !== ''` for safety unless you are very careful to check that a non-optional group follows it | group 4 is always set, and null in this case as there was no match, easy to check for with `$m[4] !== null` | +PHPStan Extension +----------------- + +To use the PHPStan extension if you do not use `phpstan/extension-installer` you can include `vendor/composer/pcre/extension.neon` in your PHPStan config. + +The extension provides much better type information for $matches as well as regex validation where possible. + License ------- diff --git a/app/vendor/composer/pcre/composer.json b/app/vendor/composer/pcre/composer.json index 40477ff4e..d3a7e67cb 100644 --- a/app/vendor/composer/pcre/composer.json +++ b/app/vendor/composer/pcre/composer.json @@ -20,9 +20,12 @@ "php": "^7.4 || ^8.0" }, "require-dev": { - "symfony/phpunit-bridge": "^5", - "phpstan/phpstan": "^1.3", - "phpstan/phpstan-strict-rules": "^1.1" + "phpunit/phpunit": "^8 || ^9", + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-strict-rules": "^1 || ^2" + }, + "conflict": { + "phpstan/phpstan": "<1.11.10" }, "autoload": { "psr-4": { @@ -37,10 +40,15 @@ "extra": { "branch-alias": { "dev-main": "3.x-dev" + }, + "phpstan": { + "includes": [ + "extension.neon" + ] } }, "scripts": { - "test": "vendor/bin/simple-phpunit", - "phpstan": "phpstan analyse" + "test": "@php vendor/bin/phpunit", + "phpstan": "@php phpstan analyse" } } diff --git a/app/vendor/composer/pcre/extension.neon b/app/vendor/composer/pcre/extension.neon new file mode 100644 index 000000000..b9cea113f --- /dev/null +++ b/app/vendor/composer/pcre/extension.neon @@ -0,0 +1,22 @@ +# composer/pcre PHPStan extensions +# +# These can be reused by third party packages by including 'vendor/composer/pcre/extension.neon' +# in your phpstan config + +services: + - + class: Composer\Pcre\PHPStan\PregMatchParameterOutTypeExtension + tags: + - phpstan.staticMethodParameterOutTypeExtension + - + class: Composer\Pcre\PHPStan\PregMatchTypeSpecifyingExtension + tags: + - phpstan.typeSpecifier.staticMethodTypeSpecifyingExtension + - + class: Composer\Pcre\PHPStan\PregReplaceCallbackClosureTypeExtension + tags: + - phpstan.staticMethodParameterClosureTypeExtension + +rules: + - Composer\Pcre\PHPStan\UnsafeStrictGroupsCallRule + - Composer\Pcre\PHPStan\InvalidRegexPatternRule diff --git a/app/vendor/composer/pcre/src/MatchAllResult.php b/app/vendor/composer/pcre/src/MatchAllResult.php index 4310c5366..b22b52d6e 100644 --- a/app/vendor/composer/pcre/src/MatchAllResult.php +++ b/app/vendor/composer/pcre/src/MatchAllResult.php @@ -35,7 +35,7 @@ final class MatchAllResult /** * @param 0|positive-int $count - * @param array> $matches + * @param array> $matches */ public function __construct(int $count, array $matches) { diff --git a/app/vendor/composer/pcre/src/MatchAllStrictGroupsResult.php b/app/vendor/composer/pcre/src/MatchAllStrictGroupsResult.php index 69dcd0625..b7ec39743 100644 --- a/app/vendor/composer/pcre/src/MatchAllStrictGroupsResult.php +++ b/app/vendor/composer/pcre/src/MatchAllStrictGroupsResult.php @@ -35,7 +35,7 @@ final class MatchAllStrictGroupsResult /** * @param 0|positive-int $count - * @param array> $matches + * @param array> $matches */ public function __construct(int $count, array $matches) { diff --git a/app/vendor/composer/pcre/src/PHPStan/InvalidRegexPatternRule.php b/app/vendor/composer/pcre/src/PHPStan/InvalidRegexPatternRule.php new file mode 100644 index 000000000..8a05fb24a --- /dev/null +++ b/app/vendor/composer/pcre/src/PHPStan/InvalidRegexPatternRule.php @@ -0,0 +1,142 @@ + + */ +class InvalidRegexPatternRule implements Rule +{ + public function getNodeType(): string + { + return StaticCall::class; + } + + public function processNode(Node $node, Scope $scope): array + { + $patterns = $this->extractPatterns($node, $scope); + + $errors = []; + foreach ($patterns as $pattern) { + $errorMessage = $this->validatePattern($pattern); + if ($errorMessage === null) { + continue; + } + + $errors[] = RuleErrorBuilder::message(sprintf('Regex pattern is invalid: %s', $errorMessage))->identifier('regexp.pattern')->build(); + } + + return $errors; + } + + /** + * @return string[] + */ + private function extractPatterns(StaticCall $node, Scope $scope): array + { + if (!$node->class instanceof FullyQualified) { + return []; + } + $isRegex = $node->class->toString() === Regex::class; + $isPreg = $node->class->toString() === Preg::class; + if (!$isRegex && !$isPreg) { + return []; + } + if (!$node->name instanceof Node\Identifier || !Preg::isMatch('{^(match|isMatch|grep|replace|split)}', $node->name->name)) { + return []; + } + + $functionName = $node->name->name; + if (!isset($node->getArgs()[0])) { + return []; + } + + $patternNode = $node->getArgs()[0]->value; + $patternType = $scope->getType($patternNode); + + $patternStrings = []; + + foreach ($patternType->getConstantStrings() as $constantStringType) { + if ($functionName === 'replaceCallbackArray') { + continue; + } + + $patternStrings[] = $constantStringType->getValue(); + } + + foreach ($patternType->getConstantArrays() as $constantArrayType) { + if ( + in_array($functionName, [ + 'replace', + 'replaceCallback', + ], true) + ) { + foreach ($constantArrayType->getValueTypes() as $arrayKeyType) { + foreach ($arrayKeyType->getConstantStrings() as $constantString) { + $patternStrings[] = $constantString->getValue(); + } + } + } + + if ($functionName !== 'replaceCallbackArray') { + continue; + } + + foreach ($constantArrayType->getKeyTypes() as $arrayKeyType) { + foreach ($arrayKeyType->getConstantStrings() as $constantString) { + $patternStrings[] = $constantString->getValue(); + } + } + } + + return $patternStrings; + } + + private function validatePattern(string $pattern): ?string + { + try { + $msg = null; + $prev = set_error_handler(function (int $severity, string $message, string $file) use (&$msg): bool { + $msg = preg_replace("#^preg_match(_all)?\\(.*?\\): #", '', $message); + + return true; + }); + + if ($pattern === '') { + return 'Empty string is not a valid regular expression'; + } + + Preg::match($pattern, ''); + if ($msg !== null) { + return $msg; + } + } catch (PcreException $e) { + if ($e->getCode() === PREG_INTERNAL_ERROR && $msg !== null) { + return $msg; + } + + return preg_replace('{.*? failed executing ".*": }', '', $e->getMessage()); + } finally { + restore_error_handler(); + } + + return null; + } + +} diff --git a/app/vendor/composer/pcre/src/PHPStan/PregMatchFlags.php b/app/vendor/composer/pcre/src/PHPStan/PregMatchFlags.php new file mode 100644 index 000000000..aa30ab347 --- /dev/null +++ b/app/vendor/composer/pcre/src/PHPStan/PregMatchFlags.php @@ -0,0 +1,70 @@ +getType($flagsArg->value); + + $constantScalars = $flagsType->getConstantScalarValues(); + if ($constantScalars === []) { + return null; + } + + $internalFlagsTypes = []; + foreach ($flagsType->getConstantScalarValues() as $constantScalarValue) { + if (!is_int($constantScalarValue)) { + return null; + } + + $internalFlagsTypes[] = new ConstantIntegerType($constantScalarValue | PREG_UNMATCHED_AS_NULL); + } + return TypeCombinator::union(...$internalFlagsTypes); + } + + static public function removeNullFromMatches(Type $matchesType): Type + { + return TypeTraverser::map($matchesType, static function (Type $type, callable $traverse): Type { + if ($type instanceof UnionType || $type instanceof IntersectionType) { + return $traverse($type); + } + + if ($type instanceof ConstantArrayType) { + return new ConstantArrayType( + $type->getKeyTypes(), + array_map(static function (Type $valueType) use ($traverse): Type { + return $traverse($valueType); + }, $type->getValueTypes()), + $type->getNextAutoIndexes(), + [], + $type->isList() + ); + } + + if ($type instanceof ArrayType) { + return new ArrayType($type->getKeyType(), $traverse($type->getItemType())); + } + + return TypeCombinator::removeNull($type); + }); + } + +} diff --git a/app/vendor/composer/pcre/src/PHPStan/PregMatchParameterOutTypeExtension.php b/app/vendor/composer/pcre/src/PHPStan/PregMatchParameterOutTypeExtension.php new file mode 100644 index 000000000..e0d60208e --- /dev/null +++ b/app/vendor/composer/pcre/src/PHPStan/PregMatchParameterOutTypeExtension.php @@ -0,0 +1,65 @@ +regexShapeMatcher = $regexShapeMatcher; + } + + public function isStaticMethodSupported(MethodReflection $methodReflection, ParameterReflection $parameter): bool + { + return + $methodReflection->getDeclaringClass()->getName() === Preg::class + && in_array($methodReflection->getName(), [ + 'match', 'isMatch', 'matchStrictGroups', 'isMatchStrictGroups', + 'matchAll', 'isMatchAll', 'matchAllStrictGroups', 'isMatchAllStrictGroups' + ], true) + && $parameter->getName() === 'matches'; + } + + public function getParameterOutTypeFromStaticMethodCall(MethodReflection $methodReflection, StaticCall $methodCall, ParameterReflection $parameter, Scope $scope): ?Type + { + $args = $methodCall->getArgs(); + $patternArg = $args[0] ?? null; + $matchesArg = $args[2] ?? null; + $flagsArg = $args[3] ?? null; + + if ( + $patternArg === null || $matchesArg === null + ) { + return null; + } + + $flagsType = PregMatchFlags::getType($flagsArg, $scope); + if ($flagsType === null) { + return null; + } + + if (stripos($methodReflection->getName(), 'matchAll') !== false) { + return $this->regexShapeMatcher->matchAllExpr($patternArg->value, $flagsType, TrinaryLogic::createMaybe(), $scope); + } + + return $this->regexShapeMatcher->matchExpr($patternArg->value, $flagsType, TrinaryLogic::createMaybe(), $scope); + } + +} diff --git a/app/vendor/composer/pcre/src/PHPStan/PregMatchTypeSpecifyingExtension.php b/app/vendor/composer/pcre/src/PHPStan/PregMatchTypeSpecifyingExtension.php new file mode 100644 index 000000000..3db0ce06a --- /dev/null +++ b/app/vendor/composer/pcre/src/PHPStan/PregMatchTypeSpecifyingExtension.php @@ -0,0 +1,119 @@ +regexShapeMatcher = $regexShapeMatcher; + } + + public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void + { + $this->typeSpecifier = $typeSpecifier; + } + + public function getClass(): string + { + return Preg::class; + } + + public function isStaticMethodSupported(MethodReflection $methodReflection, StaticCall $node, TypeSpecifierContext $context): bool + { + return in_array($methodReflection->getName(), [ + 'match', 'isMatch', 'matchStrictGroups', 'isMatchStrictGroups', + 'matchAll', 'isMatchAll', 'matchAllStrictGroups', 'isMatchAllStrictGroups' + ], true) + && !$context->null(); + } + + public function specifyTypes(MethodReflection $methodReflection, StaticCall $node, Scope $scope, TypeSpecifierContext $context): SpecifiedTypes + { + $args = $node->getArgs(); + $patternArg = $args[0] ?? null; + $matchesArg = $args[2] ?? null; + $flagsArg = $args[3] ?? null; + + if ( + $patternArg === null || $matchesArg === null + ) { + return new SpecifiedTypes(); + } + + $flagsType = PregMatchFlags::getType($flagsArg, $scope); + if ($flagsType === null) { + return new SpecifiedTypes(); + } + + if (stripos($methodReflection->getName(), 'matchAll') !== false) { + $matchedType = $this->regexShapeMatcher->matchAllExpr($patternArg->value, $flagsType, TrinaryLogic::createFromBoolean($context->true()), $scope); + } else { + $matchedType = $this->regexShapeMatcher->matchExpr($patternArg->value, $flagsType, TrinaryLogic::createFromBoolean($context->true()), $scope); + } + + if ($matchedType === null) { + return new SpecifiedTypes(); + } + + if ( + in_array($methodReflection->getName(), ['matchStrictGroups', 'isMatchStrictGroups', 'matchAllStrictGroups', 'isMatchAllStrictGroups'], true) + ) { + $matchedType = PregMatchFlags::removeNullFromMatches($matchedType); + } + + $overwrite = false; + if ($context->false()) { + $overwrite = true; + $context = $context->negate(); + } + + // @phpstan-ignore function.alreadyNarrowedType + if (method_exists('PHPStan\Analyser\SpecifiedTypes', 'setRootExpr')) { + $typeSpecifier = $this->typeSpecifier->create( + $matchesArg->value, + $matchedType, + $context, + $scope + )->setRootExpr($node); + + return $overwrite ? $typeSpecifier->setAlwaysOverwriteTypes() : $typeSpecifier; + } + + // @phpstan-ignore arguments.count + return $this->typeSpecifier->create( + $matchesArg->value, + $matchedType, + $context, + // @phpstan-ignore argument.type + $overwrite, + $scope, + $node + ); + } +} diff --git a/app/vendor/composer/pcre/src/PHPStan/PregReplaceCallbackClosureTypeExtension.php b/app/vendor/composer/pcre/src/PHPStan/PregReplaceCallbackClosureTypeExtension.php new file mode 100644 index 000000000..7b9536725 --- /dev/null +++ b/app/vendor/composer/pcre/src/PHPStan/PregReplaceCallbackClosureTypeExtension.php @@ -0,0 +1,91 @@ +regexShapeMatcher = $regexShapeMatcher; + } + + public function isStaticMethodSupported(MethodReflection $methodReflection, ParameterReflection $parameter): bool + { + return in_array($methodReflection->getDeclaringClass()->getName(), [Preg::class, Regex::class], true) + && in_array($methodReflection->getName(), ['replaceCallback', 'replaceCallbackStrictGroups'], true) + && $parameter->getName() === 'replacement'; + } + + public function getTypeFromStaticMethodCall(MethodReflection $methodReflection, StaticCall $methodCall, ParameterReflection $parameter, Scope $scope): ?Type + { + $args = $methodCall->getArgs(); + $patternArg = $args[0] ?? null; + $flagsArg = $args[5] ?? null; + + if ( + $patternArg === null + ) { + return null; + } + + $flagsType = PregMatchFlags::getType($flagsArg, $scope); + + $matchesType = $this->regexShapeMatcher->matchExpr($patternArg->value, $flagsType, TrinaryLogic::createYes(), $scope); + if ($matchesType === null) { + return null; + } + + if ($methodReflection->getName() === 'replaceCallbackStrictGroups' && count($matchesType->getConstantArrays()) === 1) { + $matchesType = $matchesType->getConstantArrays()[0]; + $matchesType = new ConstantArrayType( + $matchesType->getKeyTypes(), + array_map(static function (Type $valueType): Type { + if (count($valueType->getConstantArrays()) === 1) { + $valueTypeArray = $valueType->getConstantArrays()[0]; + return new ConstantArrayType( + $valueTypeArray->getKeyTypes(), + array_map(static function (Type $valueType): Type { + return TypeCombinator::removeNull($valueType); + }, $valueTypeArray->getValueTypes()), + $valueTypeArray->getNextAutoIndexes(), + [], + $valueTypeArray->isList() + ); + } + return TypeCombinator::removeNull($valueType); + }, $matchesType->getValueTypes()), + $matchesType->getNextAutoIndexes(), + [], + $matchesType->isList() + ); + } + + return new ClosureType( + [ + new NativeParameterReflection($parameter->getName(), $parameter->isOptional(), $matchesType, $parameter->passedByReference(), $parameter->isVariadic(), $parameter->getDefaultValue()), + ], + new StringType() + ); + } +} diff --git a/app/vendor/composer/pcre/src/PHPStan/UnsafeStrictGroupsCallRule.php b/app/vendor/composer/pcre/src/PHPStan/UnsafeStrictGroupsCallRule.php new file mode 100644 index 000000000..5bced5070 --- /dev/null +++ b/app/vendor/composer/pcre/src/PHPStan/UnsafeStrictGroupsCallRule.php @@ -0,0 +1,112 @@ + + */ +final class UnsafeStrictGroupsCallRule implements Rule +{ + /** + * @var RegexArrayShapeMatcher + */ + private $regexShapeMatcher; + + public function __construct(RegexArrayShapeMatcher $regexShapeMatcher) + { + $this->regexShapeMatcher = $regexShapeMatcher; + } + + public function getNodeType(): string + { + return StaticCall::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if (!$node->class instanceof FullyQualified) { + return []; + } + $isRegex = $node->class->toString() === Regex::class; + $isPreg = $node->class->toString() === Preg::class; + if (!$isRegex && !$isPreg) { + return []; + } + if (!$node->name instanceof Node\Identifier || !in_array($node->name->name, ['matchStrictGroups', 'isMatchStrictGroups', 'matchAllStrictGroups', 'isMatchAllStrictGroups'], true)) { + return []; + } + + $args = $node->getArgs(); + if (!isset($args[0])) { + return []; + } + + $patternArg = $args[0] ?? null; + if ($isPreg) { + if (!isset($args[2])) { // no matches set, skip as the matches won't be used anyway + return []; + } + $flagsArg = $args[3] ?? null; + } else { + $flagsArg = $args[2] ?? null; + } + + if ($patternArg === null) { + return []; + } + + $flagsType = PregMatchFlags::getType($flagsArg, $scope); + if ($flagsType === null) { + return []; + } + + $matchedType = $this->regexShapeMatcher->matchExpr($patternArg->value, $flagsType, TrinaryLogic::createYes(), $scope); + if ($matchedType === null) { + return [ + RuleErrorBuilder::message(sprintf('The %s call is potentially unsafe as $matches\' type could not be inferred.', $node->name->name)) + ->identifier('composerPcre.maybeUnsafeStrictGroups') + ->build(), + ]; + } + + if (count($matchedType->getConstantArrays()) === 1) { + $matchedType = $matchedType->getConstantArrays()[0]; + $nullableGroups = []; + foreach ($matchedType->getValueTypes() as $index => $type) { + if (TypeCombinator::containsNull($type)) { + $nullableGroups[] = $matchedType->getKeyTypes()[$index]->getValue(); + } + } + + if (\count($nullableGroups) > 0) { + return [ + RuleErrorBuilder::message(sprintf( + 'The %s call is unsafe as match group%s "%s" %s optional and may be null.', + $node->name->name, + \count($nullableGroups) > 1 ? 's' : '', + implode('", "', $nullableGroups), + \count($nullableGroups) > 1 ? 'are' : 'is' + ))->identifier('composerPcre.unsafeStrictGroups')->build(), + ]; + } + } + + return []; + } +} diff --git a/app/vendor/composer/pcre/src/PcreException.php b/app/vendor/composer/pcre/src/PcreException.php index 218b2f2d8..23d93279d 100644 --- a/app/vendor/composer/pcre/src/PcreException.php +++ b/app/vendor/composer/pcre/src/PcreException.php @@ -39,13 +39,8 @@ private static function pcreLastErrorMessage($code) return preg_last_error_msg(); } - // older php versions did not set the code properly in all cases - if (PHP_VERSION_ID < 70201 && $code === 0) { - return 'UNDEFINED_ERROR'; - } - $constants = get_defined_constants(true); - if (!isset($constants['pcre'])) { + if (!isset($constants['pcre']) || !is_array($constants['pcre'])) { return 'UNDEFINED_ERROR'; } diff --git a/app/vendor/composer/pcre/src/Preg.php b/app/vendor/composer/pcre/src/Preg.php index 6fe01722a..400abbfec 100644 --- a/app/vendor/composer/pcre/src/Preg.php +++ b/app/vendor/composer/pcre/src/Preg.php @@ -20,7 +20,7 @@ class Preg /** * @param non-empty-string $pattern - * @param array $matches Set by method + * @param array $matches Set by method * @param int-mask $flags PREG_UNMATCHED_AS_NULL is always set, no other flags are supported * @return 0|1 * @@ -42,7 +42,7 @@ public static function match(string $pattern, string $subject, ?array &$matches * Variant of `match()` which outputs non-null matches (or throws) * * @param non-empty-string $pattern - * @param array $matches Set by method + * @param array $matches Set by method * @param int-mask $flags PREG_UNMATCHED_AS_NULL is always set, no other flags are supported * @return 0|1 * @throws UnexpectedNullMatchException @@ -61,7 +61,7 @@ public static function matchStrictGroups(string $pattern, string $subject, ?arra * Runs preg_match with PREG_OFFSET_CAPTURE * * @param non-empty-string $pattern - * @param array $matches Set by method + * @param array $matches Set by method * @param int-mask $flags PREG_UNMATCHED_AS_NULL and PREG_OFFSET_CAPTURE are always set, no other flags are supported * @return 0|1 * @@ -79,7 +79,7 @@ public static function matchWithOffsets(string $pattern, string $subject, ?array /** * @param non-empty-string $pattern - * @param array> $matches Set by method + * @param array $matches Set by method * @param int-mask $flags PREG_UNMATCHED_AS_NULL is always set, no other flags are supported * @return 0|positive-int * @@ -102,7 +102,7 @@ public static function matchAll(string $pattern, string $subject, ?array &$match * Variant of `match()` which outputs non-null matches (or throws) * * @param non-empty-string $pattern - * @param array> $matches Set by method + * @param array $matches Set by method * @param int-mask $flags PREG_UNMATCHED_AS_NULL is always set, no other flags are supported * @return 0|positive-int * @throws UnexpectedNullMatchException @@ -121,7 +121,7 @@ public static function matchAllStrictGroups(string $pattern, string $subject, ?a * Runs preg_match_all with PREG_OFFSET_CAPTURE * * @param non-empty-string $pattern - * @param array> $matches Set by method + * @param array $matches Set by method * @param int-mask $flags PREG_UNMATCHED_AS_NULL and PREG_MATCH_OFFSET are always set, no other flags are supported * @return 0|positive-int * @@ -147,7 +147,7 @@ public static function matchAllWithOffsets(string $pattern, string $subject, ?ar * * @param-out int<0, max> $count */ - public static function replace($pattern, $replacement, $subject, int $limit = -1, int &$count = null): string + public static function replace($pattern, $replacement, $subject, int $limit = -1, ?int &$count = null): string { if (!is_scalar($subject)) { if (is_array($subject)) { @@ -167,14 +167,14 @@ public static function replace($pattern, $replacement, $subject, int $limit = -1 /** * @param string|string[] $pattern - * @param callable(array): string $replacement + * @param ($flags is PREG_OFFSET_CAPTURE ? (callable(array}>): string) : callable(array): string) $replacement * @param string $subject * @param int $count Set by method * @param int-mask $flags PREG_OFFSET_CAPTURE is supported, PREG_UNMATCHED_AS_NULL is always set * * @param-out int<0, max> $count */ - public static function replaceCallback($pattern, callable $replacement, $subject, int $limit = -1, int &$count = null, int $flags = 0): string + public static function replaceCallback($pattern, callable $replacement, $subject, int $limit = -1, ?int &$count = null, int $flags = 0): string { if (!is_scalar($subject)) { if (is_array($subject)) { @@ -196,14 +196,14 @@ public static function replaceCallback($pattern, callable $replacement, $subject * Variant of `replaceCallback()` which outputs non-null matches (or throws) * * @param string $pattern - * @param callable(array): string $replacement + * @param ($flags is PREG_OFFSET_CAPTURE ? (callable(array}>): string) : callable(array): string) $replacement * @param string $subject * @param int $count Set by method - * @param int-mask $flags PREG_OFFSET_CAPTURE or PREG_UNMATCHED_AS_NULL, only available on PHP 7.4+ + * @param int-mask $flags PREG_OFFSET_CAPTURE is supported, PREG_UNMATCHED_AS_NULL is always set * * @param-out int<0, max> $count */ - public static function replaceCallbackStrictGroups(string $pattern, callable $replacement, $subject, int $limit = -1, int &$count = null, int $flags = 0): string + public static function replaceCallbackStrictGroups(string $pattern, callable $replacement, $subject, int $limit = -1, ?int &$count = null, int $flags = 0): string { return self::replaceCallback($pattern, function (array $matches) use ($pattern, $replacement) { return $replacement(self::enforceNonNullMatches($pattern, $matches, 'replaceCallback')); @@ -211,14 +211,14 @@ public static function replaceCallbackStrictGroups(string $pattern, callable $re } /** - * @param array): string> $pattern + * @param ($flags is PREG_OFFSET_CAPTURE ? (array}>): string>) : array): string>) $pattern * @param string $subject * @param int $count Set by method * @param int-mask $flags PREG_OFFSET_CAPTURE is supported, PREG_UNMATCHED_AS_NULL is always set * * @param-out int<0, max> $count */ - public static function replaceCallbackArray(array $pattern, $subject, int $limit = -1, int &$count = null, int $flags = 0): string + public static function replaceCallbackArray(array $pattern, $subject, int $limit = -1, ?int &$count = null, int $flags = 0): string { if (!is_scalar($subject)) { if (is_array($subject)) { @@ -291,7 +291,7 @@ public static function grep(string $pattern, array $array, int $flags = 0): arra * Variant of match() which returns a bool instead of int * * @param non-empty-string $pattern - * @param array $matches Set by method + * @param array $matches Set by method * @param int-mask $flags PREG_UNMATCHED_AS_NULL is always set, no other flags are supported * * @param-out array $matches @@ -305,7 +305,7 @@ public static function isMatch(string $pattern, string $subject, ?array &$matche * Variant of `isMatch()` which outputs non-null matches (or throws) * * @param non-empty-string $pattern - * @param array $matches Set by method + * @param array $matches Set by method * @param int-mask $flags PREG_UNMATCHED_AS_NULL is always set, no other flags are supported * @throws UnexpectedNullMatchException * @@ -320,7 +320,7 @@ public static function isMatchStrictGroups(string $pattern, string $subject, ?ar * Variant of matchAll() which returns a bool instead of int * * @param non-empty-string $pattern - * @param array> $matches Set by method + * @param array $matches Set by method * @param int-mask $flags PREG_UNMATCHED_AS_NULL is always set, no other flags are supported * * @param-out array> $matches @@ -334,7 +334,7 @@ public static function isMatchAll(string $pattern, string $subject, ?array &$mat * Variant of `isMatchAll()` which outputs non-null matches (or throws) * * @param non-empty-string $pattern - * @param array> $matches Set by method + * @param array $matches Set by method * @param int-mask $flags PREG_UNMATCHED_AS_NULL is always set, no other flags are supported * * @param-out array> $matches @@ -350,7 +350,7 @@ public static function isMatchAllStrictGroups(string $pattern, string $subject, * Runs preg_match with PREG_OFFSET_CAPTURE * * @param non-empty-string $pattern - * @param array $matches Set by method + * @param array $matches Set by method * @param int-mask $flags PREG_UNMATCHED_AS_NULL is always set, no other flags are supported * * @param-out array}> $matches @@ -366,7 +366,7 @@ public static function isMatchWithOffsets(string $pattern, string $subject, ?arr * Runs preg_match_all with PREG_OFFSET_CAPTURE * * @param non-empty-string $pattern - * @param array> $matches Set by method + * @param array $matches Set by method * @param int-mask $flags PREG_UNMATCHED_AS_NULL is always set, no other flags are supported * * @param-out array}>> $matches @@ -391,16 +391,18 @@ private static function checkSetOrder(int $flags): void } /** - * @param array $matches + * @param array $matches * @return array * @throws UnexpectedNullMatchException */ private static function enforceNonNullMatches(string $pattern, array $matches, string $variantMethod) { foreach ($matches as $group => $match) { - if (null === $match) { - throw new UnexpectedNullMatchException('Pattern "'.$pattern.'" had an unexpected unmatched group "'.$group.'", make sure the pattern always matches or use '.$variantMethod.'() instead.'); + if (is_string($match) || (is_array($match) && is_string($match[0]))) { + continue; } + + throw new UnexpectedNullMatchException('Pattern "'.$pattern.'" had an unexpected unmatched group "'.$group.'", make sure the pattern always matches or use '.$variantMethod.'() instead.'); } /** @var array */ diff --git a/app/vendor/composer/pcre/src/Regex.php b/app/vendor/composer/pcre/src/Regex.php index 112fa3250..038cf0696 100644 --- a/app/vendor/composer/pcre/src/Regex.php +++ b/app/vendor/composer/pcre/src/Regex.php @@ -43,6 +43,7 @@ public static function match(string $pattern, string $subject, int $flags = 0, i */ public static function matchStrictGroups(string $pattern, string $subject, int $flags = 0, int $offset = 0): MatchStrictGroupsResult { + // @phpstan-ignore composerPcre.maybeUnsafeStrictGroups $count = Preg::matchStrictGroups($pattern, $subject, $matches, $flags, $offset); return new MatchStrictGroupsResult($count, $matches); @@ -87,6 +88,7 @@ public static function matchAllStrictGroups(string $pattern, string $subject, in self::checkOffsetCapture($flags, 'matchAllWithOffsets'); self::checkSetOrder($flags); + // @phpstan-ignore composerPcre.maybeUnsafeStrictGroups $count = Preg::matchAllStrictGroups($pattern, $subject, $matches, $flags, $offset); return new MatchAllStrictGroupsResult($count, $matches); @@ -120,7 +122,7 @@ public static function replace($pattern, $replacement, $subject, int $limit = -1 /** * @param string|string[] $pattern - * @param callable(array): string $replacement + * @param ($flags is PREG_OFFSET_CAPTURE ? (callable(array}>): string) : callable(array): string) $replacement * @param string $subject * @param int-mask $flags PREG_OFFSET_CAPTURE is supported, PREG_UNMATCHED_AS_NULL is always set */ @@ -135,9 +137,9 @@ public static function replaceCallback($pattern, callable $replacement, $subject * Variant of `replaceCallback()` which outputs non-null matches (or throws) * * @param string $pattern - * @param callable(array): string $replacement + * @param ($flags is PREG_OFFSET_CAPTURE ? (callable(array}>): string) : callable(array): string) $replacement * @param string $subject - * @param int-mask $flags PREG_OFFSET_CAPTURE or PREG_UNMATCHED_AS_NULL, only available on PHP 7.4+ + * @param int-mask $flags PREG_OFFSET_CAPTURE is supported, PREG_UNMATCHED_AS_NULL is always set */ public static function replaceCallbackStrictGroups($pattern, callable $replacement, $subject, int $limit = -1, int $flags = 0): ReplaceResult { @@ -147,7 +149,7 @@ public static function replaceCallbackStrictGroups($pattern, callable $replaceme } /** - * @param array): string> $pattern + * @param ($flags is PREG_OFFSET_CAPTURE ? (array}>): string>) : array): string>) $pattern * @param string $subject * @param int-mask $flags PREG_OFFSET_CAPTURE is supported, PREG_UNMATCHED_AS_NULL is always set */ diff --git a/app/vendor/composer/semver/CHANGELOG.md b/app/vendor/composer/semver/CHANGELOG.md index 3b1116124..bad46cd1c 100644 --- a/app/vendor/composer/semver/CHANGELOG.md +++ b/app/vendor/composer/semver/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +### [3.4.3] 2024-09-19 + + * Fixed some type annotations + +### [3.4.2] 2024-07-12 + + * Fixed PHP 5.3 syntax error + +### [3.4.1] 2024-07-12 + + * Fixed normalizeStability's return type to enforce valid stabilities + ### [3.4.0] 2023-08-31 * Support larger major version numbers (#149) @@ -179,6 +191,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Namespace: `Composer\Test\Package\LinkConstraint` -> `Composer\Test\Semver\Constraint` * Changed: code style using php-cs-fixer. +[3.4.3]: https://github.com/composer/semver/compare/3.4.2...3.4.3 +[3.4.2]: https://github.com/composer/semver/compare/3.4.1...3.4.2 +[3.4.1]: https://github.com/composer/semver/compare/3.4.0...3.4.1 [3.4.0]: https://github.com/composer/semver/compare/3.3.2...3.4.0 [3.3.2]: https://github.com/composer/semver/compare/3.3.1...3.3.2 [3.3.1]: https://github.com/composer/semver/compare/3.3.0...3.3.1 diff --git a/app/vendor/composer/semver/composer.json b/app/vendor/composer/semver/composer.json index f3a6f4cc6..1fad9e548 100644 --- a/app/vendor/composer/semver/composer.json +++ b/app/vendor/composer/semver/composer.json @@ -34,8 +34,8 @@ "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "symfony/phpunit-bridge": "^4.2 || ^5", - "phpstan/phpstan": "^1.4" + "symfony/phpunit-bridge": "^3 || ^7", + "phpstan/phpstan": "^1.11" }, "autoload": { "psr-4": { diff --git a/app/vendor/composer/semver/phpstan-baseline.neon b/app/vendor/composer/semver/phpstan-baseline.neon deleted file mode 100644 index 933cf2031..000000000 --- a/app/vendor/composer/semver/phpstan-baseline.neon +++ /dev/null @@ -1,11 +0,0 @@ -parameters: - ignoreErrors: - - - message: "#^Parameter \\#1 \\$operator of class Composer\\\\Semver\\\\Constraint\\\\Constraint constructor expects '\\!\\='\\|'\\<'\\|'\\<\\='\\|'\\<\\>'\\|'\\='\\|'\\=\\='\\|'\\>'\\|'\\>\\=', non\\-falsy\\-string given\\.$#" - count: 1 - path: src/VersionParser.php - - - - message: "#^Strict comparison using \\=\\=\\= between null and non\\-empty\\-string will always evaluate to false\\.$#" - count: 2 - path: src/VersionParser.php diff --git a/app/vendor/composer/semver/src/CompilingMatcher.php b/app/vendor/composer/semver/src/CompilingMatcher.php index 45bce70a6..aea1d3b95 100644 --- a/app/vendor/composer/semver/src/CompilingMatcher.php +++ b/app/vendor/composer/semver/src/CompilingMatcher.php @@ -64,7 +64,7 @@ public static function clear() * @phpstan-param Constraint::OP_* $operator * @param string $version * - * @return mixed + * @return bool */ public static function match(ConstraintInterface $constraint, $operator, $version) { diff --git a/app/vendor/composer/semver/src/VersionParser.php b/app/vendor/composer/semver/src/VersionParser.php index 9318629a7..305a0faec 100644 --- a/app/vendor/composer/semver/src/VersionParser.php +++ b/app/vendor/composer/semver/src/VersionParser.php @@ -82,11 +82,16 @@ public static function parseStability($version) * @param string $stability * * @return string + * @phpstan-return 'stable'|'RC'|'beta'|'alpha'|'dev' */ public static function normalizeStability($stability) { $stability = strtolower((string) $stability); + if (!in_array($stability, array('stable', 'rc', 'beta', 'alpha', 'dev'), true)) { + throw new \InvalidArgumentException('Invalid stability string "'.$stability.'", expected one of stable, RC, beta, alpha or dev'); + } + return $stability === 'rc' ? 'RC' : $stability; } diff --git a/app/vendor/composer/spdx-licenses/.github/workflows/continuous-integration.yml b/app/vendor/composer/spdx-licenses/.github/workflows/continuous-integration.yml deleted file mode 100644 index 4143c8cd9..000000000 --- a/app/vendor/composer/spdx-licenses/.github/workflows/continuous-integration.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: "Continuous Integration" - -on: - - push - - pull_request - -env: - COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist" - SYMFONY_PHPUNIT_REMOVE_RETURN_TYPEHINT: "1" - -jobs: - tests: - name: "CI" - - runs-on: ubuntu-latest - - strategy: - matrix: - php-version: - - "5.3" - - "5.4" - - "5.5" - - "5.6" - - "7.0" - - "7.1" - - "7.2" - - "7.3" - - "7.4" - - "8.0" - - "8.1" - - steps: - - name: "Checkout" - uses: "actions/checkout@v2" - - - name: "Install PHP" - uses: "shivammathur/setup-php@v2" - with: - coverage: "none" - php-version: "${{ matrix.php-version }}" - - - name: Get composer cache directory - id: composercache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Cache dependencies - uses: actions/cache@v2 - with: - path: ${{ steps.composercache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} - restore-keys: ${{ runner.os }}-composer- - - - name: "Install latest dependencies" - run: | - # Remove PHPStan as it requires a newer PHP - composer remove phpstan/phpstan --dev --no-update - composer update ${{ env.COMPOSER_FLAGS }} - - - name: "Run tests" - run: "vendor/bin/simple-phpunit --verbose" diff --git a/app/vendor/composer/spdx-licenses/.github/workflows/lint.yml b/app/vendor/composer/spdx-licenses/.github/workflows/lint.yml deleted file mode 100644 index 81a1ac4d4..000000000 --- a/app/vendor/composer/spdx-licenses/.github/workflows/lint.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: "PHP Lint" - -on: - - push - - pull_request - -jobs: - tests: - name: "Lint" - - runs-on: ubuntu-latest - - strategy: - matrix: - php-version: - - "5.3" - - "8.0" - - steps: - - name: "Checkout" - uses: "actions/checkout@v2" - - - name: "Install PHP" - uses: "shivammathur/setup-php@v2" - with: - coverage: "none" - php-version: "${{ matrix.php-version }}" - - - name: "Lint PHP files" - run: "find src/ -type f -name '*.php' -print0 | xargs -0 -L1 -P4 -- php -l -f" diff --git a/app/vendor/composer/spdx-licenses/.github/workflows/phpstan.yml b/app/vendor/composer/spdx-licenses/.github/workflows/phpstan.yml deleted file mode 100644 index ac4c4a92c..000000000 --- a/app/vendor/composer/spdx-licenses/.github/workflows/phpstan.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: "PHPStan" - -on: - - push - - pull_request - -env: - COMPOSER_FLAGS: "--ansi --no-interaction --no-progress --prefer-dist" - SYMFONY_PHPUNIT_VERSION: "" - -jobs: - tests: - name: "PHPStan" - - runs-on: ubuntu-latest - - strategy: - matrix: - php-version: - # pinned to 7.4 because we need PHPUnit 7.5 which does not support PHP 8 - - "7.4" - - steps: - - name: "Checkout" - uses: "actions/checkout@v2" - - - name: "Install PHP" - uses: "shivammathur/setup-php@v2" - with: - coverage: "none" - php-version: "${{ matrix.php-version }}" - - - name: Get composer cache directory - id: composercache - run: echo "::set-output name=dir::$(composer config cache-files-dir)" - - - name: Cache dependencies - uses: actions/cache@v2 - with: - path: ${{ steps.composercache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} - restore-keys: ${{ runner.os }}-composer- - - - name: "Install latest dependencies" - run: "composer update ${{ env.COMPOSER_FLAGS }}" - - - name: Run PHPStan - # Locked to phpunit 7.5 here as newer ones have void return types which break inheritance - run: | - composer require --dev phpunit/phpunit:^7.5.20 --with-all-dependencies ${{ env.COMPOSER_FLAGS }} - vendor/bin/phpstan analyse diff --git a/app/vendor/composer/spdx-licenses/CHANGELOG.md b/app/vendor/composer/spdx-licenses/CHANGELOG.md deleted file mode 100644 index 15f48627b..000000000 --- a/app/vendor/composer/spdx-licenses/CHANGELOG.md +++ /dev/null @@ -1,120 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -This project adheres to [Semantic Versioning](http://semver.org/). - -## [main] - - * ... - -## [.1.5.6] 2022-05-23 - - * Changed: updated licenses list to SPDX 3.17 - * Changed: `${var}` PHP 8.2 deprecations resolved - -## [1.5.6] 2021-11-18 - - * Changed: updated licenses list to SPDX 3.15 - -## [1.5.5] 2020-12-03 - - * Changed: updated licenses list to SPDX 3.11 - -## [1.5.4] 2020-07-15 - - * Changed: updated licenses list to SPDX 3.9 - -## [1.5.3] 2020-02-14 - - * Changed: updated licenses list to SPDX 3.8 - -## [1.5.2] 2019-07-29 - - * Changed: updated licenses list to SPDX 3.6 - -## [1.5.1] 2019-03-26 - - * Changed: updated licenses list to SPDX 3.4 - -## [1.5.0] 2018-11-01 - - * Changed: updated licenses list to SPDX 3.3 - -## [1.4.0] 2018-05-04 - - * Changed: updated licenses list to SPDX 3.1 - -## [1.3.0] 2018-01-31 - - * Added: `SpdxLicenses::getLicenses` to get the whole list of methods. - * Changed: license identifiers are now case insensitive. - -## [1.2.0] 2018-01-03 - - * Added: deprecation status for all licenses and a `SpdxLicenses::isDeprecatedByIdentifier` method. - * Changed: updated licenses list to SPDX 3.0. - -## [1.1.6] 2017-04-03 - - * Changed: updated licenses list. - -## [1.1.5] 2016-09-28 - - * Changed: updated licenses list. - -## [1.1.4] 2016-05-04 - - * Changed: updated licenses list. - -## [1.1.3] 2016-03-25 - - * Changed: updated licenses list. - * Changed: dropped `test` namespace. - * Changed: tedious small things. - -## [1.1.2] 2015-10-05 - - * Changed: updated licenses list. - -## [1.1.1] 2015-09-07 - - * Changed: improved performance when looking up just one license. - * Changed: updated licenses list. - -## [1.1.0] 2015-07-17 - - * Changed: updater now sorts licenses and exceptions by key. - * Changed: filenames now class constants of SpdxLicenses (`LICENSES_FILE` and `EXCEPTIONS_FILE`). - * Changed: resources directory now available via static method `SpdxLicenses::getResourcesDir()`. - * Changed: updated licenses list. - * Changed: removed json-schema requirement. - -## [1.0.0] 2015-07-15 - - * Break: the following classes and namespaces were renamed: - - Namespace: `Composer\Util` -> `Composer\Spdx` - - Classname: `SpdxLicense` -> `SpdxLicenses` - - Classname: `SpdxLicenseTest` -> `SpdxLicensesTest` - - Classname: `Updater` -> `SpdxLicensesUpdater` - * Changed: validation via regex implementation instead of lexer. - -[main]: https://github.com/composer/spdx-licenses/compare/1.5.7...main -[1.5.7]: https://github.com/composer/spdx-licenses/compare/1.5.6...1.5.7 -[1.5.6]: https://github.com/composer/spdx-licenses/compare/1.5.5...1.5.6 -[1.5.5]: https://github.com/composer/spdx-licenses/compare/1.5.4...1.5.5 -[1.5.4]: https://github.com/composer/spdx-licenses/compare/1.5.3...1.5.4 -[1.5.3]: https://github.com/composer/spdx-licenses/compare/1.5.2...1.5.3 -[1.5.2]: https://github.com/composer/spdx-licenses/compare/1.5.1...1.5.2 -[1.5.1]: https://github.com/composer/spdx-licenses/compare/1.5.0...1.5.1 -[1.5.0]: https://github.com/composer/spdx-licenses/compare/1.4.0...1.5.0 -[1.4.0]: https://github.com/composer/spdx-licenses/compare/1.3.0...1.4.0 -[1.3.0]: https://github.com/composer/spdx-licenses/compare/1.2.0...1.3.0 -[1.2.0]: https://github.com/composer/spdx-licenses/compare/1.1.6...1.2.0 -[1.1.6]: https://github.com/composer/spdx-licenses/compare/1.1.5...1.1.6 -[1.1.5]: https://github.com/composer/spdx-licenses/compare/1.1.4...1.1.5 -[1.1.4]: https://github.com/composer/spdx-licenses/compare/1.1.3...1.1.4 -[1.1.3]: https://github.com/composer/spdx-licenses/compare/1.1.2...1.1.3 -[1.1.2]: https://github.com/composer/spdx-licenses/compare/1.1.1...1.1.2 -[1.1.1]: https://github.com/composer/spdx-licenses/compare/1.1.0...1.1.1 -[1.1.0]: https://github.com/composer/spdx-licenses/compare/1.0.0...1.1.0 -[1.0.0]: https://github.com/composer/spdx-licenses/compare/0281a7fe7820c990db3058844e7d448d7b70e3ac...1.0.0 diff --git a/app/vendor/composer/spdx-licenses/composer.json b/app/vendor/composer/spdx-licenses/composer.json index dd30895da..e1701c068 100644 --- a/app/vendor/composer/spdx-licenses/composer.json +++ b/app/vendor/composer/spdx-licenses/composer.json @@ -33,8 +33,8 @@ "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "symfony/phpunit-bridge": "^4.2 || ^5", - "phpstan/phpstan": "^0.12.55" + "symfony/phpunit-bridge": "^3 || ^7", + "phpstan/phpstan": "^1.11" }, "autoload": { "psr-4": { diff --git a/app/vendor/composer/spdx-licenses/phpstan.neon.dist b/app/vendor/composer/spdx-licenses/phpstan.neon.dist deleted file mode 100644 index 2e4efefac..000000000 --- a/app/vendor/composer/spdx-licenses/phpstan.neon.dist +++ /dev/null @@ -1,9 +0,0 @@ -parameters: - level: 8 - paths: - - src - - tests - - typeAliases: - SPDXLicense: 'array{0: string, 1: bool, 2: string, 3: bool}' - SPDXLicenseException: 'array{0: string, 1: string}' diff --git a/app/vendor/composer/spdx-licenses/res/spdx-exceptions.json b/app/vendor/composer/spdx-licenses/res/spdx-exceptions.json index 84bfe766c..3e1353577 100644 --- a/app/vendor/composer/spdx-licenses/res/spdx-exceptions.json +++ b/app/vendor/composer/spdx-licenses/res/spdx-exceptions.json @@ -5,6 +5,9 @@ "Asterisk-exception": [ "Asterisk exception" ], + "Asterisk-linking-protocols-exception": [ + "Asterisk linking protocols exception" + ], "Autoconf-exception-2.0": [ "Autoconf exception 2.0" ], @@ -20,12 +23,18 @@ "Autoconf-exception-macro": [ "Autoconf macro exception" ], + "Bison-exception-1.24": [ + "Bison exception 1.24" + ], "Bison-exception-2.2": [ "Bison exception 2.2" ], "Bootloader-exception": [ "Bootloader Distribution Exception" ], + "CGAL-linking-exception": [ + "CGAL Linking Exception" + ], "Classpath-exception-2.0": [ "Classpath exception 2.0" ], @@ -35,18 +44,27 @@ "cryptsetup-OpenSSL-exception": [ "cryptsetup OpenSSL exception" ], + "Digia-Qt-LGPL-exception-1.1": [ + "Digia Qt LGPL Exception version 1.1" + ], "DigiRule-FOSS-exception": [ "DigiRule FOSS License Exception" ], "eCos-exception-2.0": [ "eCos exception 2.0" ], + "erlang-otp-linking-exception": [ + "Erlang/OTP Linking Exception" + ], "Fawkes-Runtime-exception": [ "Fawkes Runtime Exception" ], "FLTK-exception": [ "FLTK exception" ], + "fmt-exception": [ + "fmt exception" + ], "Font-exception-2.0": [ "Font exception 2.0" ], @@ -62,15 +80,24 @@ "GCC-exception-3.1": [ "GCC Runtime Library exception 3.1" ], + "Gmsh-exception": [ + "Gmsh exception" + ], "GNAT-exception": [ "GNAT exception" ], + "GNOME-examples-exception": [ + "GNOME examples exception" + ], "GNU-compiler-exception": [ "GNU Compiler Exception" ], "gnu-javamail-exception": [ "GNU JavaMail exception" ], + "GPL-3.0-389-ds-base-exception": [ + "GPL-3.0 389 DS Base Exception" + ], "GPL-3.0-interface-exception": [ "GPL-3.0 Interface Exception" ], @@ -89,9 +116,15 @@ "GStreamer-exception-2008": [ "GStreamer Exception (2008)" ], + "harbour-exception": [ + "harbour exception" + ], "i2p-gpl-java-exception": [ "i2p GPL+Java Exception" ], + "Independent-modules-exception": [ + "Independent Module Linking exception" + ], "KiCad-libraries-exception": [ "KiCad Libraries Exception" ], @@ -119,6 +152,9 @@ "mif-exception": [ "Macros and Inline Functions Exception" ], + "mxml-exception": [ + "mxml Exception" + ], "Nokia-Qt-exception-1.1": [ "Nokia Qt LGPL exception 1.1" ], @@ -134,6 +170,12 @@ "openvpn-openssl-exception": [ "OpenVPN OpenSSL Exception" ], + "PCRE2-exception": [ + "PCRE2 exception" + ], + "polyparse-exception": [ + "Polyparse Exception" + ], "PS-or-PDF-font-exception-20170817": [ "PS/PDF font exception (2017-08-17)" ], @@ -149,6 +191,12 @@ "Qwt-exception-1.0": [ "Qwt exception 1.0" ], + "romic-exception": [ + "Romic Exception" + ], + "RRDtool-FLOSS-exception-2.0": [ + "RRDtool FLOSS exception 2.0" + ], "SANE-exception": [ "SANE Exception" ], diff --git a/app/vendor/composer/spdx-licenses/res/spdx-licenses.json b/app/vendor/composer/spdx-licenses/res/spdx-licenses.json index 36a05bb8e..11b53c965 100644 --- a/app/vendor/composer/spdx-licenses/res/spdx-licenses.json +++ b/app/vendor/composer/spdx-licenses/res/spdx-licenses.json @@ -4,6 +4,11 @@ true, false ], + "3D-Slicer-1.0": [ + "3D Slicer License v1.0", + false, + false + ], "AAL": [ "Attribution Assurance License", true, @@ -109,6 +114,11 @@ false, false ], + "AMD-newlib": [ + "AMD newlib License", + false, + false + ], "AMDPLPA": [ "AMD's plpa_map.c License", false, @@ -139,6 +149,16 @@ false, false ], + "any-OSI": [ + "Any OSI License", + false, + false + ], + "any-OSI-perl-modules": [ + "Any OSI License - Perl Modules", + false, + false + ], "Apache-1.0": [ "Apache License 1.0", false, @@ -214,6 +234,11 @@ true, false ], + "Artistic-dist": [ + "Artistic License 1.0 (dist)", + false, + false + ], "ASWF-Digital-Assets-1.0": [ "ASWF Digital Assets License version 1.0", false, @@ -239,6 +264,11 @@ false, false ], + "bcrypt-Solar-Designer": [ + "bcrypt Solar Designer License", + false, + false + ], "Beerware": [ "Beerware License", false, @@ -271,7 +301,7 @@ ], "BlueOak-1.0.0": [ "Blue Oak Model License 1.0.0", - false, + true, false ], "Boehm-GC": [ @@ -279,11 +309,21 @@ false, false ], + "Boehm-GC-without-fee": [ + "Boehm-Demers-Weiser GC License (without fee)", + false, + false + ], "Borceux": [ "Borceux license", false, false ], + "Brian-Gladman-2-Clause": [ + "Brian Gladman 2-Clause License", + false, + false + ], "Brian-Gladman-3-Clause": [ "Brian Gladman 3-Clause License", false, @@ -299,6 +339,16 @@ true, false ], + "BSD-2-Clause-Darwin": [ + "BSD 2-Clause - Ian Darwin variant", + false, + false + ], + "BSD-2-Clause-first-lines": [ + "BSD 2-Clause - first lines requirement", + false, + false + ], "BSD-2-Clause-FreeBSD": [ "BSD 2-Clause FreeBSD License", false, @@ -314,6 +364,11 @@ true, false ], + "BSD-2-Clause-pkgconf-disclaimer": [ + "BSD 2-Clause pkgconf disclaimer variant", + false, + false + ], "BSD-2-Clause-Views": [ "BSD 2-Clause with views sentence", false, @@ -324,6 +379,11 @@ true, false ], + "BSD-3-Clause-acpica": [ + "BSD 3-Clause acpica variant", + false, + false + ], "BSD-3-Clause-Attribution": [ "BSD with attribution", false, @@ -429,6 +489,11 @@ false, false ], + "BSD-Source-beginning-file": [ + "BSD Source Code Attribution - beginning of file variant", + false, + false + ], "BSD-Source-Code": [ "BSD Source Code Attribution", false, @@ -439,6 +504,11 @@ false, false ], + "BSD-Systemics-W3Works": [ + "Systemics W3Works BSD variant license", + false, + false + ], "BSL-1.0": [ "Boost Software License 1.0", true, @@ -479,6 +549,16 @@ false, false ], + "Caldera-no-preamble": [ + "Caldera License (without preamble)", + false, + false + ], + "Catharon": [ + "Catharon License", + false, + false + ], "CATOSL-1.1": [ "Computer Associates Trusted Open Source License 1.1", true, @@ -514,6 +594,11 @@ false, false ], + "CC-BY-3.0-AU": [ + "Creative Commons Attribution 3.0 Australia", + false, + false + ], "CC-BY-3.0-DE": [ "Creative Commons Attribution 3.0 Germany", false, @@ -739,6 +824,16 @@ false, false ], + "CC-PDM-1.0": [ + "Creative Commons Public Domain Mark 1.0 Universal", + false, + false + ], + "CC-SA-1.0": [ + "Creative Commons Share Alike 1.0 Generic", + false, + false + ], "CC0-1.0": [ "Creative Commons Zero v1.0 Universal", false, @@ -859,6 +954,11 @@ false, false ], + "CMU-Mach-nodoc": [ + "CMU Mach - no notices-in-documentation variant", + false, + false + ], "CNRI-Jython": [ "CNRI Jython License", false, @@ -929,6 +1029,11 @@ false, false ], + "CryptoSwift": [ + "CryptoSwift License", + false, + false + ], "CrystalStacker": [ "CrystalStacker License", false, @@ -949,6 +1054,11 @@ false, false ], + "cve-tou": [ + "Common Vulnerability Enumeration ToU License", + false, + false + ], "D-FSL-1.0": [ "Deutsche Freie Software Lizenz", false, @@ -979,6 +1089,26 @@ false, false ], + "DocBook-DTD": [ + "DocBook DTD License", + false, + false + ], + "DocBook-Schema": [ + "DocBook Schema License", + false, + false + ], + "DocBook-Stylesheet": [ + "DocBook Stylesheet License", + false, + false + ], + "DocBook-XML": [ + "DocBook XML License", + false, + false + ], "Dotseqn": [ "Dotseqn License", false, @@ -1139,6 +1269,11 @@ false, false ], + "FSFAP-no-warranty-disclaimer": [ + "FSF All Permissive License (without Warranty)", + false, + false + ], "FSFUL": [ "FSF Unlimited License", false, @@ -1154,6 +1289,16 @@ false, false ], + "FSL-1.1-ALv2": [ + "Functional Source License, Version 1.1, ALv2 Future License", + false, + false + ], + "FSL-1.1-MIT": [ + "Functional Source License, Version 1.1, MIT Future License", + false, + false + ], "FTL": [ "Freetype Project License", false, @@ -1169,6 +1314,11 @@ false, false ], + "Game-Programming-Gems": [ + "Game Programming Gems License", + false, + false + ], "GCR-docs": [ "Gnome GCR Documentation License", false, @@ -1179,6 +1329,11 @@ false, false ], + "generic-xts": [ + "Generic XTS License", + false, + false + ], "GFDL-1.1": [ "GNU Free Documentation License v1.1", false, @@ -1419,6 +1574,16 @@ false, false ], + "gtkbook": [ + "gtkbook License", + false, + false + ], + "Gutmann": [ + "Gutmann License", + false, + false + ], "HaskellReport": [ "Haskell Language Report License", false, @@ -1429,6 +1594,11 @@ false, false ], + "HIDAPI": [ + "HIDAPI License", + false, + false + ], "Hippocratic-2.1": [ "Hippocratic License 2.1", false, @@ -1469,16 +1639,61 @@ false, false ], + "HPND-export-US-acknowledgement": [ + "HPND with US Government export control warning and acknowledgment", + false, + false + ], "HPND-export-US-modify": [ "HPND with US Government export control warning and modification rqmt", false, false ], + "HPND-export2-US": [ + "HPND with US Government export control and 2 disclaimers", + false, + false + ], + "HPND-Fenneberg-Livingston": [ + "Historical Permission Notice and Disclaimer - Fenneberg-Livingston variant", + false, + false + ], + "HPND-INRIA-IMAG": [ + "Historical Permission Notice and Disclaimer - INRIA-IMAG variant", + false, + false + ], + "HPND-Intel": [ + "Historical Permission Notice and Disclaimer - Intel variant", + false, + false + ], + "HPND-Kevlin-Henney": [ + "Historical Permission Notice and Disclaimer - Kevlin Henney variant", + false, + false + ], "HPND-Markus-Kuhn": [ "Historical Permission Notice and Disclaimer - Markus Kuhn variant", false, false ], + "HPND-merchantability-variant": [ + "Historical Permission Notice and Disclaimer - merchantability variant", + false, + false + ], + "HPND-MIT-disclaimer": [ + "Historical Permission Notice and Disclaimer with MIT disclaimer", + false, + false + ], + "HPND-Netrek": [ + "Historical Permission Notice and Disclaimer - Netrek variant", + false, + false + ], "HPND-Pbmplus": [ "Historical Permission Notice and Disclaimer - Pbmplus variant", false, @@ -1504,11 +1719,21 @@ false, false ], + "HPND-sell-variant-MIT-disclaimer-rev": [ + "HPND sell variant with MIT disclaimer - reverse", + false, + false + ], "HPND-UC": [ "Historical Permission Notice and Disclaimer - University of California variant", false, false ], + "HPND-UC-export-US": [ + "Historical Permission Notice and Disclaimer - University of California, US export warning", + false, + false + ], "HTMLTIDY": [ "HTML Tidy License", false, @@ -1564,6 +1789,11 @@ false, false ], + "InnoSetup": [ + "Inno Setup License", + false, + false + ], "Intel": [ "Intel Open Source License", true, @@ -1594,6 +1824,11 @@ true, false ], + "ISC-Veillard": [ + "ISC Veillard variant", + false, + false + ], "Jam": [ "Jam License", true, @@ -1604,6 +1839,11 @@ false, false ], + "jove": [ + "Jove License", + false, + false + ], "JPL-image": [ "JPL Image Use Policy", false, @@ -1794,6 +2034,11 @@ false, false ], + "LPD-document": [ + "LPD Documentation License", + false, + false + ], "LPL-1.0": [ "Lucent Public License Version 1.0", true, @@ -1849,16 +2094,36 @@ false, false ], + "Mackerras-3-Clause": [ + "Mackerras 3-Clause License", + false, + false + ], + "Mackerras-3-Clause-acknowledgment": [ + "Mackerras 3-Clause - acknowledgment variant", + false, + false + ], "magaz": [ "magaz License", false, false ], + "mailprio": [ + "mailprio License", + false, + false + ], "MakeIndex": [ "MakeIndex License", false, false ], + "man2html": [ + "man2html License", + false, + false + ], "Martin-Birgmeier": [ "Martin Birgmeier License", false, @@ -1879,6 +2144,11 @@ false, false ], + "MIPS": [ + "MIPS License", + false, + false + ], "MirOS": [ "The MirOS Licence", true, @@ -1899,6 +2169,11 @@ false, false ], + "MIT-Click": [ + "MIT Click License", + false, + false + ], "MIT-CMU": [ "CMU License", false, @@ -1919,6 +2194,11 @@ false, false ], + "MIT-Khronos-old": [ + "MIT Khronos - old variant", + false, + false + ], "MIT-Modern-Variant": [ "MIT License Modern Variant", true, @@ -2054,11 +2334,21 @@ false, false ], + "NCBI-PD": [ + "NCBI Public Domain Notice", + false, + false + ], "NCGL-UK-2.0": [ "Non-Commercial Government Licence", false, false ], + "NCL": [ + "NCL Source Code License", + false, + false + ], "NCSA": [ "University of Illinois/NCSA Open Source License", true, @@ -2067,7 +2357,7 @@ "Net-SNMP": [ "Net-SNMP License", false, - false + true ], "NetCDF": [ "NetCDF license", @@ -2154,6 +2444,11 @@ false, false ], + "NTIA-PD": [ + "NTIA Public Domain Notice", + false, + false + ], "NTP": [ "NTP License", true, @@ -2174,6 +2469,11 @@ false, false ], + "OAR": [ + "OAR License", + false, + false + ], "OCCT-PL": [ "Open CASCADE Technology Public License", false, @@ -2364,6 +2664,16 @@ false, false ], + "OpenSSL-standalone": [ + "OpenSSL License - standalone", + false, + false + ], + "OpenVision": [ + "OpenVision License", + false, + false + ], "OPL-1.0": [ "Open Public License v1.0", false, @@ -2444,6 +2754,11 @@ false, false ], + "pkgconf": [ + "pkgconf License", + false, + false + ], "Plexus": [ "Plexus Classworlds License", false, @@ -2469,6 +2784,11 @@ true, false ], + "PPL": [ + "Peer Production License", + false, + false + ], "PSF-2.0": [ "Python Software Foundation License 2.0", false, @@ -2514,6 +2834,11 @@ false, false ], + "radvd": [ + "radvd License", + false, + false + ], "Rdisc": [ "Rdisc License", false, @@ -2554,11 +2879,21 @@ false, false ], + "Ruby-pty": [ + "Ruby pty extension license", + false, + false + ], "SAX-PD": [ "Sax Public Domain Notice", false, false ], + "SAX-PD-2.0": [ + "Sax Public Domain Notice 2.0", + false, + false + ], "Saxpath": [ "Saxpath License", false, @@ -2584,6 +2919,11 @@ false, false ], + "Sendmail-Open-Source-1.1": [ + "Sendmail Open Source License v1.1", + false, + false + ], "SGI-B-1.0": [ "SGI Free Software License B v1.0", false, @@ -2644,6 +2984,11 @@ true, false ], + "SMAIL-GPL": [ + "SMAIL General Public License", + false, + false + ], "SMLNJ": [ "Standard ML of New Jersey License", false, @@ -2664,6 +3009,16 @@ false, false ], + "SOFA": [ + "SOFA Software License", + false, + false + ], + "softSurfer": [ + "softSurfer License", + false, + false + ], "Soundex": [ "Soundex License", false, @@ -2704,6 +3059,11 @@ false, false ], + "SSLeay-standalone": [ + "SSLeay License - standalone", + false, + false + ], "SSPL-1.0": [ "Server Side Public License, v 1", false, @@ -2719,6 +3079,16 @@ false, false ], + "Sun-PPP": [ + "Sun PPP License", + false, + false + ], + "Sun-PPP-2000": [ + "Sun PPP License (2000)", + false, + false + ], "SunPro": [ "SunPro License", false, @@ -2759,6 +3129,21 @@ false, false ], + "TGPPL-1.0": [ + "Transitive Grace Period Public Licence 1.0", + false, + false + ], + "ThirdEye": [ + "ThirdEye License", + false, + false + ], + "threeparttable": [ + "threeparttable License", + false, + false + ], "TMate": [ "TMate Open Source License", false, @@ -2784,6 +3169,11 @@ false, false ], + "TrustedQSL": [ + "TrustedQSL License", + false, + false + ], "TTWL": [ "Text-Tabs+Wrap License", false, @@ -2804,6 +3194,11 @@ false, false ], + "Ubuntu-font-1.0": [ + "Ubuntu Font Licence v1.0", + false, + false + ], "UCAR": [ "UCAR License", false, @@ -2819,6 +3214,16 @@ false, false ], + "UMich-Merit": [ + "Michigan/Merit Networks License", + false, + false + ], + "Unicode-3.0": [ + "Unicode License v3", + true, + false + ], "Unicode-DFS-2015": [ "Unicode License Agreement - Data Files and Software (2015)", false, @@ -2844,6 +3249,16 @@ true, false ], + "Unlicense-libtelnet": [ + "Unlicense - libtelnet variant", + false, + false + ], + "Unlicense-libwhirlpool": [ + "Unlicense - libwhirlpool variant", + false, + false + ], "UPL-1.0": [ "Universal Permissive License v1.0", true, @@ -2881,7 +3296,7 @@ ], "W3C-20150513": [ "W3C Software Notice and Document License (2015-05-13)", - false, + true, false ], "w3m": [ @@ -2909,6 +3324,11 @@ false, false ], + "wwl": [ + "WWL License", + false, + false + ], "wxWindows": [ "wxWindows Library License", true, @@ -2924,6 +3344,11 @@ false, false ], + "X11-swapped": [ + "X11 swapped final paragraphs", + false, + false + ], "Xdebug-1.03": [ "Xdebug License v 1.03", false, @@ -2949,6 +3374,11 @@ false, false ], + "xkeyboard-config-Zinoviev": [ + "xkeyboard-config Zinoviev License", + false, + false + ], "xlock": [ "xlock License", false, @@ -2969,6 +3399,11 @@ false, false ], + "xzoom": [ + "xzoom License", + false, + false + ], "YPL-1.0": [ "Yahoo! Public License v1.0", false, diff --git a/app/vendor/composer/xdebug-handler/CHANGELOG.md b/app/vendor/composer/xdebug-handler/CHANGELOG.md index c5b5bcf4e..62ebe223a 100644 --- a/app/vendor/composer/xdebug-handler/CHANGELOG.md +++ b/app/vendor/composer/xdebug-handler/CHANGELOG.md @@ -1,5 +1,12 @@ ## [Unreleased] +## [3.0.5] - 2024-05-06 + * Fixed: fail restart if PHP_BINARY is not available + +## [3.0.4] - 2024-03-26 + * Added: Functional tests. + * Fixed: Incompatibility with PHPUnit 10. + ## [3.0.3] - 2022-02-25 * Added: support for composer/pcre versions 2 and 3. @@ -108,8 +115,10 @@ * Break: the following class was renamed: - `Composer\XdebugHandler` -> `Composer\XdebugHandler\XdebugHandler` -[Unreleased]: https://github.com/composer/xdebug-handler/compare/3.0.3...HEAD -[3.0.2]: https://github.com/composer/xdebug-handler/compare/3.0.2...3.0.3 +[Unreleased]: https://github.com/composer/xdebug-handler/compare/3.0.5...HEAD +[3.0.5]: https://github.com/composer/xdebug-handler/compare/3.0.4...3.0.5 +[3.0.4]: https://github.com/composer/xdebug-handler/compare/3.0.3...3.0.4 +[3.0.3]: https://github.com/composer/xdebug-handler/compare/3.0.2...3.0.3 [3.0.2]: https://github.com/composer/xdebug-handler/compare/3.0.1...3.0.2 [3.0.1]: https://github.com/composer/xdebug-handler/compare/3.0.0...3.0.1 [3.0.0]: https://github.com/composer/xdebug-handler/compare/2.0.3...3.0.0 diff --git a/app/vendor/composer/xdebug-handler/README.md b/app/vendor/composer/xdebug-handler/README.md index 56618fc14..f7f581ac2 100644 --- a/app/vendor/composer/xdebug-handler/README.md +++ b/app/vendor/composer/xdebug-handler/README.md @@ -51,6 +51,7 @@ The constructor takes a single parameter, `$envPrefix`, which is upper-cased and * [Process configuration](#process-configuration) * [Troubleshooting](#troubleshooting) * [Extending the library](#extending-the-library) +* [Examples](#examples) ### How it works @@ -64,6 +65,8 @@ A temporary ini file is created from the loaded (and scanned) ini files, with an * The application runs and exits. * The main process exits with the exit code from the restarted process. +See [Examples](#examples) for further information. + #### Signal handling Asynchronous signal handling is automatically enabled if the pcntl extension is loaded. `SIGINT` is set to `SIG_IGN` in the parent process and restored to `SIG_DFL` in the restarted process (if no other handler has been set). @@ -74,7 +77,7 @@ From PHP 7.4 on Windows, `CTRL+C` and `CTRL+BREAK` handling is automatically ena There are a few things to be aware of when running inside a restarted process. * Extensions set on the command-line will not be loaded. -* Ini file locations will be reported as per the restart - see [getAllIniFiles()](#getallinifiles). +* Ini file locations will be reported as per the restart - see [getAllIniFiles()](#getallinifiles-array). * Php sub-processes may be loaded with Xdebug enabled - see [Process configuration](#process-configuration). ### Helper methods @@ -200,12 +203,12 @@ Uses environment variables to remove Xdebug from the new process and persist the >_If the new process calls a PHP sub-process, Xdebug will not be loaded in that sub-process._ -This strategy can be used in the restart by calling [setPersistent()](#setpersistent). +This strategy can be used in the restart by calling [setPersistent()](#setpersistent-self). #### Sub-processes The `PhpConfig` helper class makes it easy to invoke a PHP sub-process (with or without Xdebug loaded), regardless of whether there has been a restart. -Each of its methods returns an array of PHP options (to add to the command-line) and sets up the environment for the required strategy. The [getRestartSettings()](#getrestartsettings) method is used internally. +Each of its methods returns an array of PHP options (to add to the command-line) and sets up the environment for the required strategy. The [getRestartSettings()](#getrestartsettings-array) method is used internally. * `useOriginal()` - Xdebug will be loaded in the new process. * `useStandard()` - Xdebug will **not** be loaded in the new process - see [standard settings](#standard-settings). @@ -245,7 +248,7 @@ The API is defined by classes and their accessible elements that are not annotat By default the process will restart if Xdebug is loaded and not running with `xdebug.mode=off`. Extending this method allows an application to decide, by returning a boolean (or equivalent) value. It is only called if `MYAPP_ALLOW_XDEBUG` is empty, so it will not be called in the restarted process (where this variable contains internal data), or if the restart has been overridden. -Note that the [setMainScript()](#setmainscriptscript) and [setPersistent()](#setpersistent) setters can be used here, if required. +Note that the [setMainScript()](#setmainscriptstring-script-self) and [setPersistent()](#setpersistent-self) setters can be used here, if required. #### _restart(array $command): void_ An application can extend this to modify the temporary ini file, its location given in the `tmpIni` property. New settings can be safely appended to the end of the data, which is `PHP_EOL` terminated. @@ -294,5 +297,9 @@ class MyRestarter extends XdebugHandler } ``` +### Examples +The `tests\App` directory contains command-line scripts that demonstrate the internal workings in a variety of scenarios. +See [Functional Test Scripts](./tests/App/README.md). + ## License composer/xdebug-handler is licensed under the MIT License, see the LICENSE file for details. diff --git a/app/vendor/composer/xdebug-handler/composer.json b/app/vendor/composer/xdebug-handler/composer.json index 6b649dab3..d205dc102 100644 --- a/app/vendor/composer/xdebug-handler/composer.json +++ b/app/vendor/composer/xdebug-handler/composer.json @@ -14,7 +14,7 @@ } ], "support": { - "irc": "irc://irc.freenode.org/composer", + "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/xdebug-handler/issues" }, "require": { @@ -23,9 +23,9 @@ "composer/pcre": "^1 || ^2 || ^3" }, "require-dev": { - "symfony/phpunit-bridge": "^6.0", "phpstan/phpstan": "^1.0", - "phpstan/phpstan-strict-rules": "^1.1" + "phpstan/phpstan-strict-rules": "^1.1", + "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5" }, "autoload": { "psr-4": { @@ -38,7 +38,7 @@ } }, "scripts": { - "test": "@php vendor/bin/simple-phpunit", + "test": "@php vendor/bin/phpunit", "phpstan": "@php vendor/bin/phpstan analyse" } } diff --git a/app/vendor/composer/xdebug-handler/src/Process.php b/app/vendor/composer/xdebug-handler/src/Process.php index c612200bb..4e9f076bb 100644 --- a/app/vendor/composer/xdebug-handler/src/Process.php +++ b/app/vendor/composer/xdebug-handler/src/Process.php @@ -41,6 +41,7 @@ public static function escape(string $arg, bool $meta = true, bool $module = fal $quote = strpbrk($arg, " \t") !== false || $arg === ''; $arg = Preg::replace('/(\\\\*)"/', '$1$1\\"', $arg, -1, $dquotes); + $dquotes = (bool) $dquotes; if ($meta) { $meta = $dquotes || Preg::isMatch('/%[^%]+%/', $arg); diff --git a/app/vendor/composer/xdebug-handler/src/Status.php b/app/vendor/composer/xdebug-handler/src/Status.php index b434f8592..96c5944a2 100644 --- a/app/vendor/composer/xdebug-handler/src/Status.php +++ b/app/vendor/composer/xdebug-handler/src/Status.php @@ -82,14 +82,33 @@ public function setLogger(LoggerInterface $logger): void public function report(string $op, ?string $data): void { if ($this->logger !== null || $this->debug) { - $callable = [$this, 'report'.$op]; - - if (!is_callable($callable)) { - throw new \InvalidArgumentException('Unknown op handler: '.$op); + $param = (string) $data; + + switch($op) { + case self::CHECK: + $this->reportCheck($param); + break; + case self::ERROR: + $this->reportError($param); + break; + case self::INFO: + $this->reportInfo($param); + break; + case self::NORESTART: + $this->reportNoRestart(); + break; + case self::RESTART: + $this->reportRestart(); + break; + case self::RESTARTED: + $this->reportRestarted(); + break; + case self::RESTARTING: + $this->reportRestarting($param); + break; + default: + throw new \InvalidArgumentException('Unknown op handler: '.$op); } - - $params = $data !== null ? [$data] : []; - call_user_func_array($callable, $params); } } @@ -180,7 +199,7 @@ private function reportRestarting(string $command): void { $text = sprintf('Process restarting (%s)', $this->getEnvAllow()); $this->output($text); - $text = 'Running '.$command; + $text = 'Running: '.$command; $this->output($text); } diff --git a/app/vendor/composer/xdebug-handler/src/XdebugHandler.php b/app/vendor/composer/xdebug-handler/src/XdebugHandler.php index 9052bfa43..a665939d6 100644 --- a/app/vendor/composer/xdebug-handler/src/XdebugHandler.php +++ b/app/vendor/composer/xdebug-handler/src/XdebugHandler.php @@ -143,9 +143,9 @@ public function check(): void if (!((bool) $envArgs[0]) && $this->requiresRestart(self::$xdebugActive)) { // Restart required $this->notify(Status::RESTART); + $command = $this->prepareRestart(); - if ($this->prepareRestart()) { - $command = $this->getCommand(); + if ($command !== null) { $this->restart($command); } return; @@ -183,9 +183,9 @@ public function check(): void * Returns an array of php.ini locations with at least one entry * * The equivalent of calling php_ini_loaded_file then php_ini_scanned_files. - * The loaded ini location is the first entry and may be empty. + * The loaded ini location is the first entry and may be an empty string. * - * @return string[] + * @return non-empty-list */ public static function getAllIniFiles(): array { @@ -267,7 +267,7 @@ protected function requiresRestart(bool $default): bool /** * Allows an extending class to access the tmpIni * - * @param string[] $command * + * @param non-empty-list $command */ protected function restart(array $command): void { @@ -277,24 +277,26 @@ protected function restart(array $command): void /** * Executes the restarted command then deletes the tmp ini * - * @param string[] $command + * @param non-empty-list $command * @phpstan-return never */ private function doRestart(array $command): void { - $this->tryEnableSignals(); - $this->notify(Status::RESTARTING, implode(' ', $command)); - if (PHP_VERSION_ID >= 70400) { $cmd = $command; + $displayCmd = sprintf('[%s]', implode(', ', $cmd)); } else { $cmd = Process::escapeShellCommand($command); if (defined('PHP_WINDOWS_VERSION_BUILD')) { // Outer quotes required on cmd string below PHP 8 $cmd = '"'.$cmd.'"'; } + $displayCmd = $cmd; } + $this->tryEnableSignals(); + $this->notify(Status::RESTARTING, $displayCmd); + $process = proc_open($cmd, [], $pipes); if (is_resource($process)) { $exitCode = proc_close($process); @@ -318,52 +320,74 @@ private function doRestart(array $command): void } /** - * Returns true if everything was written for the restart + * Returns the command line array if everything was written for the restart * * If any of the following fails (however unlikely) we must return false to * stop potential recursion: * - tmp ini file creation * - environment variable creation + * + * @return non-empty-list|null */ - private function prepareRestart(): bool + private function prepareRestart(): ?array { + if (!$this->cli) { + $this->notify(Status::ERROR, 'Unsupported SAPI: '.PHP_SAPI); + return null; + } + + if (($argv = $this->checkServerArgv()) === null) { + $this->notify(Status::ERROR, '$_SERVER[argv] is not as expected'); + return null; + } + + if (!$this->checkConfiguration($info)) { + $this->notify(Status::ERROR, $info); + return null; + } + + $mainScript = (string) $this->script; + if (!$this->checkMainScript($mainScript, $argv)) { + $this->notify(Status::ERROR, 'Unable to access main script: '.$mainScript); + return null; + } + + $tmpDir = sys_get_temp_dir(); + $iniError = 'Unable to create temp ini file at: '.$tmpDir; + + if (($tmpfile = @tempnam($tmpDir, '')) === false) { + $this->notify(Status::ERROR, $iniError); + return null; + } + $error = null; $iniFiles = self::getAllIniFiles(); $scannedInis = count($iniFiles) > 1; - $tmpDir = sys_get_temp_dir(); - if (!$this->cli) { - $error = 'Unsupported SAPI: '.PHP_SAPI; - } elseif (!$this->checkConfiguration($info)) { - $error = $info; - } elseif (!$this->checkMainScript()) { - $error = 'Unable to access main script: '.$this->script; - } elseif (!$this->writeTmpIni($iniFiles, $tmpDir, $error)) { - $error = $error !== null ? $error : 'Unable to create temp ini file at: '.$tmpDir; - } elseif (!$this->setEnvironment($scannedInis, $iniFiles)) { - $error = 'Unable to set environment variables'; + if (!$this->writeTmpIni($tmpfile, $iniFiles, $error)) { + $this->notify(Status::ERROR, $error ?? $iniError); + @unlink($tmpfile); + return null; } - if ($error !== null) { - $this->notify(Status::ERROR, $error); + if (!$this->setEnvironment($scannedInis, $iniFiles, $tmpfile)) { + $this->notify(Status::ERROR, 'Unable to set environment variables'); + @unlink($tmpfile); + return null; } - return $error === null; + $this->tmpIni = $tmpfile; + + return $this->getCommand($argv, $tmpfile, $mainScript); } /** * Returns true if the tmp ini file was written * - * @param string[] $iniFiles All ini files used in the current process + * @param non-empty-list $iniFiles All ini files used in the current process */ - private function writeTmpIni(array $iniFiles, string $tmpDir, ?string &$error): bool + private function writeTmpIni(string $tmpFile, array $iniFiles, ?string &$error): bool { - if (($tmpfile = @tempnam($tmpDir, '')) === false) { - return false; - } - - $this->tmpIni = $tmpfile; - // $iniFiles has at least one item and it may be empty if ($iniFiles[0] === '') { array_shift($iniFiles); @@ -380,7 +404,7 @@ private function writeTmpIni(array $iniFiles, string $tmpDir, ?string &$error): return false; } // Check and remove directives after HOST and PATH sections - if (Preg::isMatchWithOffsets($sectionRegex, $data, $matches, PREG_OFFSET_CAPTURE)) { + if (Preg::isMatchWithOffsets($sectionRegex, $data, $matches)) { $data = substr($data, 0, $matches[0][1]); } $content .= Preg::replace($xdebugRegex, ';$1', $data).PHP_EOL; @@ -400,25 +424,26 @@ private function writeTmpIni(array $iniFiles, string $tmpDir, ?string &$error): // Work-around for https://bugs.php.net/bug.php?id=75932 $content .= 'opcache.enable_cli=0'.PHP_EOL; - return (bool) @file_put_contents($this->tmpIni, $content); + return (bool) @file_put_contents($tmpFile, $content); } /** * Returns the command line arguments for the restart * - * @return string[] + * @param non-empty-list $argv + * @return non-empty-list */ - private function getCommand(): array + private function getCommand(array $argv, string $tmpIni, string $mainScript): array { $php = [PHP_BINARY]; - $args = array_slice($_SERVER['argv'], 1); + $args = array_slice($argv, 1); if (!$this->persistent) { // Use command-line options - array_push($php, '-n', '-c', $this->tmpIni); + array_push($php, '-n', '-c', $tmpIni); } - return array_merge($php, [$this->script], $args); + return array_merge($php, [$mainScript], $args); } /** @@ -426,9 +451,9 @@ private function getCommand(): array * * No need to update $_SERVER since this is set in the restarted process. * - * @param string[] $iniFiles All ini files used in the current process + * @param non-empty-list $iniFiles All ini files used in the current process */ - private function setEnvironment(bool $scannedInis, array $iniFiles): bool + private function setEnvironment(bool $scannedInis, array $iniFiles, string $tmpIni): bool { $scanDir = getenv('PHP_INI_SCAN_DIR'); $phprc = getenv('PHPRC'); @@ -440,7 +465,7 @@ private function setEnvironment(bool $scannedInis, array $iniFiles): bool if ($this->persistent) { // Use the environment to persist the settings - if (!putenv('PHP_INI_SCAN_DIR=') || !putenv('PHPRC='.$this->tmpIni)) { + if (!putenv('PHP_INI_SCAN_DIR=') || !putenv('PHPRC='.$tmpIni)) { return false; } } @@ -495,15 +520,17 @@ private function mergeLoadedConfig(array $loadedConfig, array $iniConfig): strin /** * Returns true if the script name can be used + * + * @param non-empty-list $argv */ - private function checkMainScript(): bool + private function checkMainScript(string &$mainScript, array $argv): bool { - if ($this->script !== null) { + if ($mainScript !== '') { // Allow an application to set -- for standard input - return file_exists($this->script) || '--' === $this->script; + return file_exists($mainScript) || '--' === $mainScript; } - if (file_exists($this->script = $_SERVER['argv'][0])) { + if (file_exists($mainScript = $argv[0])) { return true; } @@ -512,7 +539,7 @@ private function checkMainScript(): bool $main = end($trace); if ($main !== false && isset($main['file'])) { - return file_exists($this->script = $main['file']); + return file_exists($mainScript = $main['file']); } return false; @@ -521,7 +548,7 @@ private function checkMainScript(): bool /** * Adds restart settings to the environment * - * @param string[] $envArgs + * @param non-empty-list $envArgs */ private function setEnvRestartSettings(array $envArgs): void { @@ -563,6 +590,11 @@ private function checkConfiguration(?string &$info): bool return false; } + if (!file_exists(PHP_BINARY)) { + $info = 'PHP_BINARY is not available'; + return false; + } + if (extension_loaded('uopz') && !((bool) ini_get('uopz.disable'))) { // uopz works at opcode level and disables exit calls if (function_exists('uopz_allow_exit')) { @@ -619,6 +651,28 @@ private function tryEnableSignals(): void } } + /** + * Returns $_SERVER['argv'] if it is as expected + * + * @return non-empty-list|null + */ + private function checkServerArgv(): ?array + { + $result = []; + + if (isset($_SERVER['argv']) && is_array($_SERVER['argv'])) { + foreach ($_SERVER['argv'] as $value) { + if (!is_string($value)) { + return null; + } + + $result[] = $value; + } + } + + return count($result) > 0 ? $result : null; + } + /** * Sets static properties $xdebugActive, $xdebugVersion and $xdebugMode */ diff --git a/app/vendor/dealerdirect/phpcodesniffer-composer-installer/CHANGELOG.md b/app/vendor/dealerdirect/phpcodesniffer-composer-installer/CHANGELOG.md new file mode 100644 index 000000000..3a55c0d24 --- /dev/null +++ b/app/vendor/dealerdirect/phpcodesniffer-composer-installer/CHANGELOG.md @@ -0,0 +1,575 @@ +# Change Log for the Composer Installer for PHP CodeSniffer + +All notable changes to this project will be documented in this file. + +This projects adheres to [Keep a CHANGELOG](https://keepachangelog.com/) and uses [Semantic Versioning](https://semver.org/). + + +## [Unreleased] + +_Nothing yet._ + + +## [v1.1.2] - 2025-07-17 + +### Changed +- General housekeeping. + +### Fixed +- [#247]: Potential fatal error when the Composer EventDispatcher is called programmatically from an integration. Thanks [@jrfnl] ! [#248] + +[#247]: https://github.com/PHPCSStandards/composer-installer/issues/247 +[#248]: https://github.com/PHPCSStandards/composer-installer/pull/248 + + +## [v1.1.1] - 2025-06-27 + +### Changed +- Various housekeeping, including improvements to the documentation. + +### Fixed +- [#239]: The PHP_CodeSniffer package could not be always found when running the plugin in a Drupal or Magento setup. Thanks [@jrfnl] ! [#245] + +[#239]: https://github.com/PHPCSStandards/composer-installer/issues/239 +[#245]: https://github.com/PHPCSStandards/composer-installer/pull/245 + + +## [v1.1.0] - 2025-06-24 + +### Changed +- Various housekeeping, including improvements to the documentation and tests. Thanks [@SplotyCode], [@fredden] for contributing! + +### Removed +- Drop support for Composer v1.x. Thanks [@fredden] ! [#230] + +[#230]: https://github.com/PHPCSStandards/composer-installer/pull/230 + + +## [v1.0.0] - 2023-01-05 + +### Breaking changes +- Rename namespace prefix from Dealerdirect to PHPCSStandards by [@jrfnl] in [#191] +- Drop support for PHP 5.3 by [@jrfnl] in [#147] + +### Changed +- Correct grammar in error message by [@fredden] in [#189] +- .gitattributes: sync with current repo state by [@jrfnl] in [#198] +- PHPCSVersions: update URL references by [@jrfnl] in [#161] +- README: remove references to Scrutinizer by [@jrfnl] in [#157] +- Rename references to master branch by [@Potherca] in [#201] +- Update repo references by [@jrfnl] in [#158] +- GH Actions: add builds against Composer 2.2 for PHP 7.2 - 8.x by [@jrfnl] in [#172] +- GH Actions: bust the cache semi-regularly by [@jrfnl] in [#192] +- GH Actions: fix builds on Windows with PHP 8.2 by [@jrfnl] in [#180] +- GH Actions: fix up fail-fast for setup-php by [@jrfnl] in [#195] +- GH Actions: run integration tests against Composer snapshot by [@jrfnl] in [#163] +- GH Actions: run linting against against ubuntu-latest by [@jrfnl] in [#184] +- GH Actions/Securitycheck: update the security checker download by [@jrfnl] in [#178] +- GH Actions/Securitycheck: update the security checker download by [@jrfnl] in [#186] +- GH Actions/Securitycheck: update the security checker download by [@jrfnl] in [#190] +- GH Actions: selectively use fail-fast with setup-php by [@jrfnl] in [#194] +- GH Actions: stop running tests against PHP 5.5/Composer 1.x on Windows (and remove work-arounds) by [@jrfnl] in [#183] +- GH Actions: various tweaks / PHP 8.2 not allowed to fail by [@jrfnl] in [#193] +- GH Actions: version update for various predefined actions by [@jrfnl] in [#170] +- Update YamLint by [@Potherca] in [#173] +- Add initial integration test setup and first few tests by [@jrfnl] in [#153] +- BaseLineTest: stabilize the message checks by [@jrfnl] in [#162] +- PlayNiceWithScriptsTest: wrap output expectation in condition by [@jrfnl] in [#179] +- RegisterExternalStandardsTest: add new tests by [@jrfnl] in [#165] +- RegisterExternalStandardsTest: stabilize test for Composer v1 on Windows with PHP 5.5 by [@jrfnl] in [#171] +- TestCase::executeCliCommand(): retry Composer commands on a particular exception by [@jrfnl] in [#164] +- Tests: add new InstalledPathsOrderTest by [@jrfnl] in [#176] +- Tests: add new InstallUpdateEventsTest and NonInstallUpdateEventsTest by [@jrfnl] in [#174] +- Tests: add new InvalidPackagesTest by [@jrfnl] in [#168] +- Tests: add new PlayNiceWithScriptsTest by [@jrfnl] in [#169] +- Tests: add new PreexistingPHPCSConfigTest by [@jrfnl] in [#166] +- Tests: add new PreexistingPHPCSInstalledPathsConfigTest + bug fix by [@jrfnl] in [#167] +- Tests: add new RemovePluginTest by [@jrfnl] in [#177] +- Tests: add new RootPackageHandlingTest + bugfix by [@jrfnl] in [#175] + +### Fixed +- Plugin: improve feedback by [@jrfnl] in [#182] + +[#147]: https://github.com/PHPCSStandards/composer-installer/pull/147 +[#153]: https://github.com/PHPCSStandards/composer-installer/pull/153 +[#157]: https://github.com/PHPCSStandards/composer-installer/pull/157 +[#158]: https://github.com/PHPCSStandards/composer-installer/pull/158 +[#161]: https://github.com/PHPCSStandards/composer-installer/pull/161 +[#162]: https://github.com/PHPCSStandards/composer-installer/pull/162 +[#163]: https://github.com/PHPCSStandards/composer-installer/pull/163 +[#164]: https://github.com/PHPCSStandards/composer-installer/pull/164 +[#165]: https://github.com/PHPCSStandards/composer-installer/pull/165 +[#166]: https://github.com/PHPCSStandards/composer-installer/pull/166 +[#167]: https://github.com/PHPCSStandards/composer-installer/pull/167 +[#168]: https://github.com/PHPCSStandards/composer-installer/pull/168 +[#169]: https://github.com/PHPCSStandards/composer-installer/pull/169 +[#170]: https://github.com/PHPCSStandards/composer-installer/pull/170 +[#171]: https://github.com/PHPCSStandards/composer-installer/pull/171 +[#172]: https://github.com/PHPCSStandards/composer-installer/pull/172 +[#173]: https://github.com/PHPCSStandards/composer-installer/pull/173 +[#174]: https://github.com/PHPCSStandards/composer-installer/pull/174 +[#175]: https://github.com/PHPCSStandards/composer-installer/pull/175 +[#176]: https://github.com/PHPCSStandards/composer-installer/pull/176 +[#177]: https://github.com/PHPCSStandards/composer-installer/pull/177 +[#178]: https://github.com/PHPCSStandards/composer-installer/pull/178 +[#179]: https://github.com/PHPCSStandards/composer-installer/pull/179 +[#180]: https://github.com/PHPCSStandards/composer-installer/pull/180 +[#182]: https://github.com/PHPCSStandards/composer-installer/pull/182 +[#183]: https://github.com/PHPCSStandards/composer-installer/pull/183 +[#184]: https://github.com/PHPCSStandards/composer-installer/pull/184 +[#186]: https://github.com/PHPCSStandards/composer-installer/pull/186 +[#189]: https://github.com/PHPCSStandards/composer-installer/pull/189 +[#190]: https://github.com/PHPCSStandards/composer-installer/pull/190 +[#191]: https://github.com/PHPCSStandards/composer-installer/pull/191 +[#192]: https://github.com/PHPCSStandards/composer-installer/pull/192 +[#193]: https://github.com/PHPCSStandards/composer-installer/pull/193 +[#194]: https://github.com/PHPCSStandards/composer-installer/pull/194 +[#195]: https://github.com/PHPCSStandards/composer-installer/pull/195 +[#198]: https://github.com/PHPCSStandards/composer-installer/pull/198 +[#201]: https://github.com/PHPCSStandards/composer-installer/pull/201 + + +## [v0.7.2] - 2022-02-04 + +### Changed +- Add details regarding QA automation in CONTRIBUTING.md file. by [@Potherca] in [#133] +- Add mention of Composer and PHP compatibility to project README. by [@Potherca] in [#132] +- Composer: tweak PHPCS version constraint by [@jrfnl] in [#152] +- CONTRIBUTING: remove duplicate code of conduct by [@jrfnl] in [#148] +- Document release process by [@Potherca] in [#118] +- Plugin::loadInstalledPaths(): config-show always shows all by [@jrfnl] in [#154] +- README: minor tweaks by [@jrfnl] in [#149] +- README: update with information about Composer >= 2.2 by [@jrfnl] in [#141] +- Replace deprecated Sensiolabs security checker by [@paras-malhotra] in [#130] +- Stabilize a condition by [@jrfnl] in [#127] +- Update copyright year by [@jrfnl] in [#138] +- Various minor tweaks by [@jrfnl] in [#151] +- Change YamlLint config to prevent "truthy" warning. by [@Potherca] in [#144] +- GH Actions: PHP 8.1 has been released by [@jrfnl] in [#139] +- Travis: line length tweaks by [@jrfnl] in [#128] +- CI: Switch to GH Actions by [@jrfnl] in [#137] +- CI: various updates by [@jrfnl] in [#140] + +[#118]: https://github.com/PHPCSStandards/composer-installer/pull/118 +[#127]: https://github.com/PHPCSStandards/composer-installer/pull/127 +[#128]: https://github.com/PHPCSStandards/composer-installer/pull/128 +[#130]: https://github.com/PHPCSStandards/composer-installer/pull/130 +[#132]: https://github.com/PHPCSStandards/composer-installer/pull/132 +[#133]: https://github.com/PHPCSStandards/composer-installer/pull/133 +[#137]: https://github.com/PHPCSStandards/composer-installer/pull/137 +[#138]: https://github.com/PHPCSStandards/composer-installer/pull/138 +[#139]: https://github.com/PHPCSStandards/composer-installer/pull/139 +[#140]: https://github.com/PHPCSStandards/composer-installer/pull/140 +[#141]: https://github.com/PHPCSStandards/composer-installer/pull/141 +[#144]: https://github.com/PHPCSStandards/composer-installer/pull/144 +[#148]: https://github.com/PHPCSStandards/composer-installer/pull/148 +[#149]: https://github.com/PHPCSStandards/composer-installer/pull/149 +[#151]: https://github.com/PHPCSStandards/composer-installer/pull/151 +[#152]: https://github.com/PHPCSStandards/composer-installer/pull/152 +[#154]: https://github.com/PHPCSStandards/composer-installer/pull/154 + + +## [v0.7.1] - 2020-12-07 + +### Closed issues +- Order of installed_paths inconsistent between runs [#125] +- Maintaining this project and Admin rights [#113] + +### Changed +- Sort list of installed paths before saving for consistency by [@kevinfodness] in [#126] +- Update code of conduct by [@Potherca] in [#117] +- Add remark configuration by [@Potherca] in [#122] +- Travis: add build against PHP 8.0 by [@jrfnl] in [#124] + +### Fixed +- Fixed v4 constraint by [@GrahamCampbell] in [#115] + +[#113]: https://github.com/PHPCSStandards/composer-installer/issues/113 +[#115]: https://github.com/PHPCSStandards/composer-installer/pull/115 +[#117]: https://github.com/PHPCSStandards/composer-installer/pull/117 +[#122]: https://github.com/PHPCSStandards/composer-installer/pull/122 +[#124]: https://github.com/PHPCSStandards/composer-installer/pull/124 +[#125]: https://github.com/PHPCSStandards/composer-installer/issues/125 +[#126]: https://github.com/PHPCSStandards/composer-installer/pull/126 + + +## [v0.7.0] - 2020-06-25 + +### Closed issues +- Composer 2.x compatibility [#108] +- Add link to Packagist on main page [#110] +- Switch from Travis CI .org to .com [#112] + +### Added +- Allow installation on PHP 8 by [@jrfnl] in [#106] +- Support Composer 2.0 by [@jrfnl] in [#111] + +### Changed +- Test with PHPCS 4.x and allow installation when using PHPCS 4.x by [@jrfnl] in [#107] +- Fix case of class name by [@Seldaek] in [#109] + +[#106]: https://github.com/PHPCSStandards/composer-installer/pull/106 +[#107]: https://github.com/PHPCSStandards/composer-installer/pull/107 +[#108]: https://github.com/PHPCSStandards/composer-installer/issues/108 +[#109]: https://github.com/PHPCSStandards/composer-installer/pull/109 +[#110]: https://github.com/PHPCSStandards/composer-installer/issues/110 +[#111]: https://github.com/PHPCSStandards/composer-installer/pull/111 +[#112]: https://github.com/PHPCSStandards/composer-installer/issues/112 + + +## [v0.6.2] - 2020-01-29 + +### Fixed +- Composer scripts/commands broken in 0.6.0 update by [@BrianHenryIE] in [#105] + +[#105]: https://github.com/PHPCSStandards/composer-installer/pull/105 + +## [v0.6.1] - 2020-01-27 + +### Closed issues +- Do not exit with code 1 on uninstall (--no-dev) [#103] + +### Changed +- Readme: minor tweak now 0.6.0 has been released [#102] ([@jrfnl]) + +### Fixed +- [#103]: Fix for issue #103 [#104] ([@Potherca]) + +[#102]: https://github.com/PHPCSStandards/composer-installer/pull/102 +[#103]: https://github.com/PHPCSStandards/composer-installer/issues/103 +[#104]: https://github.com/PHPCSStandards/composer-installer/pull/104 + + +## [v0.6.0] - 2020-01-19 + +### Closed issues +- Composer PHP version appears not to be respected [#79] +- Allow a string value for extra.phpcodesniffer-search-depth [#82] +- Add [@jrfnl] as (co)maintainer to this project [#87] + +### Added +- Add support for a string phpcodesniffer-search-depth config value set via composer config by [@TravisCarden] in [#85] +- Send an exit code when the script terminates by [@jrfnl] in [#93] +- Verify the installed_paths after save by [@jrfnl] in [#97] + +### Changed +- CS: fix compliance with PSR12 by [@jrfnl] in [#88] +- Improve GH issue template by [@jrfnl] in [#94] +- Readme: add section about including this plugin from an external PHPCS standard by [@jrfnl] in [#95] +- Bug report template: further enhancement by [@jrfnl] in [#99] +- Update copyright year. by [@Potherca] in [#101] +- Adding linting jobs in github action by [@mjrider] in [#96] +- GH Actions: minor tweaks: by [@jrfnl] in [#100] +- Travis: disable Xdebug by [@jrfnl] in [#89] +- Travis: test against PHP 7.4, not snapshot by [@jrfnl] in [#90] +- Travis: use a mix of PHPCS versions in the matrix by [@jrfnl] in [#91] +- Update Travis file and fix build by [@Potherca] in [#86] + +### Fixed +- [#79]: Respect PHP version used by Composer and provide better feedback on failure by [@jrfnl] in [#80] +- Bug fix: loadInstalledPaths() very very broken since PHPCS 3.1.0 by [@jrfnl] in [#98] + +[#79]: https://github.com/PHPCSStandards/composer-installer/issues/79 +[#80]: https://github.com/PHPCSStandards/composer-installer/issues/80 +[#82]: https://github.com/PHPCSStandards/composer-installer/issues/82 +[#85]: https://github.com/PHPCSStandards/composer-installer/pull/85 +[#86]: https://github.com/PHPCSStandards/composer-installer/pull/86 +[#87]: https://github.com/PHPCSStandards/composer-installer/issues/87 +[#88]: https://github.com/PHPCSStandards/composer-installer/pull/88 +[#89]: https://github.com/PHPCSStandards/composer-installer/pull/89 +[#90]: https://github.com/PHPCSStandards/composer-installer/pull/90 +[#91]: https://github.com/PHPCSStandards/composer-installer/pull/91 +[#93]: https://github.com/PHPCSStandards/composer-installer/pull/93 +[#94]: https://github.com/PHPCSStandards/composer-installer/pull/94 +[#95]: https://github.com/PHPCSStandards/composer-installer/pull/95 +[#96]: https://github.com/PHPCSStandards/composer-installer/pull/96 +[#97]: https://github.com/PHPCSStandards/composer-installer/pull/97 +[#98]: https://github.com/PHPCSStandards/composer-installer/issues/98 +[#99]: https://github.com/PHPCSStandards/composer-installer/pull/99 +[#100]: https://github.com/PHPCSStandards/composer-installer/pull/100 +[#101]: https://github.com/PHPCSStandards/composer-installer/pull/101 + + +## [v0.5.0] - 2018-10-26 + +### Closed issues +- Scan depth as parameter [#45] +- phpcs: Exit Code: 127 (Command not found) on every Composer command [#48] +- The composer plugin implementation seems to be breaking the composer lifecycle [#49] +- Installation error [#53] +- Broke composer commands when used with wp-cli/package-command [#59] +- Getting a new stable release [#60] +- Support PHP CodeSniffer standards in packages installed outside of the vendor directory [#63] + +### Added +- Adds the ability to set the max depth from the composer.json file by [@Potherca] in [#46] + +### Changed +- Build/PHPCS: update PHPCompatibility repo name by [@jrfnl] in [#54] +- README: remove VersionEye badge by [@jrfnl] in [#55] +- README: replace maintenance badge by [@jrfnl] in [#56] +- Execute phpcs and security-checker from vendor/bin by [@gapple] in [#52] +- PHPCS: various minor tweaks by [@jrfnl] in [#57] +- Travis: various tweaks by [@jrfnl] in [#58] +- Use PHPCompatibility 9.0.0 by [@jrfnl] in [#61] +- Build/Travis: test builds against PHP 7.3 by [@jrfnl] in [#62] +- Updates copyright year by [@frenck] in [#67] +- Enforces PSR12 by [@frenck] in [#66] +- Updates contact information by [@frenck] in [#68] +- Updates README, spelling/grammar, removed Working section by [@frenck] in [#69] +- Replaces ProcessBuilder by ProcessExecutor by [@frenck] in [#70] +- Refactors relative path logic by [@frenck] in [#71] +- Removes suggested packages by [@frenck] in [#72] +- Ensures absolute paths during detection phase by [@frenck] in [#73] +- Trivial code cleanup by [@frenck] in [#74] +- Fixes duplicate declaration of cwd by [@frenck] in [#75] +- Removes HHVM from TravisCI by [@frenck] in [#76] +- Adds PHP_CodeSniffer version constraints by [@frenck] in [#77] + +### Fixed +- [#49]: Move loadInstalledPaths from init to onDependenciesChangedEvent by [@gapple] in [#51] + +[#45]: https://github.com/PHPCSStandards/composer-installer/issues/45 +[#46]: https://github.com/PHPCSStandards/composer-installer/pull/46 +[#48]: https://github.com/PHPCSStandards/composer-installer/issues/48 +[#49]: https://github.com/PHPCSStandards/composer-installer/issues/49 +[#51]: https://github.com/PHPCSStandards/composer-installer/pull/51 +[#52]: https://github.com/PHPCSStandards/composer-installer/pull/52 +[#53]: https://github.com/PHPCSStandards/composer-installer/issues/53 +[#54]: https://github.com/PHPCSStandards/composer-installer/pull/54 +[#55]: https://github.com/PHPCSStandards/composer-installer/pull/55 +[#56]: https://github.com/PHPCSStandards/composer-installer/pull/56 +[#57]: https://github.com/PHPCSStandards/composer-installer/pull/57 +[#58]: https://github.com/PHPCSStandards/composer-installer/pull/58 +[#59]: https://github.com/PHPCSStandards/composer-installer/issues/59 +[#60]: https://github.com/PHPCSStandards/composer-installer/issues/60 +[#61]: https://github.com/PHPCSStandards/composer-installer/pull/61 +[#62]: https://github.com/PHPCSStandards/composer-installer/pull/62 +[#63]: https://github.com/PHPCSStandards/composer-installer/issues/63 +[#66]: https://github.com/PHPCSStandards/composer-installer/pull/66 +[#67]: https://github.com/PHPCSStandards/composer-installer/pull/67 +[#68]: https://github.com/PHPCSStandards/composer-installer/pull/68 +[#69]: https://github.com/PHPCSStandards/composer-installer/pull/69 +[#70]: https://github.com/PHPCSStandards/composer-installer/pull/70 +[#71]: https://github.com/PHPCSStandards/composer-installer/pull/71 +[#72]: https://github.com/PHPCSStandards/composer-installer/pull/72 +[#73]: https://github.com/PHPCSStandards/composer-installer/pull/73 +[#74]: https://github.com/PHPCSStandards/composer-installer/pull/74 +[#75]: https://github.com/PHPCSStandards/composer-installer/pull/75 +[#76]: https://github.com/PHPCSStandards/composer-installer/pull/76 +[#77]: https://github.com/PHPCSStandards/composer-installer/pull/77 + + +## [v0.4.4] - 2017-12-06 + +### Closed issues +- PHP 7.2 compatibility issue [#43] + +### Changed +- Update Travis CI svg badge and link URLs [#42] ([@ntwb]) +- Add PHP 7.2 to Travis CI [#41] ([@ntwb]) +- Docs: Fix link to releases [#40] ([@GaryJones]) + +[#40]: https://github.com/PHPCSStandards/composer-installer/pull/40 +[#41]: https://github.com/PHPCSStandards/composer-installer/pull/41 +[#42]: https://github.com/PHPCSStandards/composer-installer/pull/42 +[#43]: https://github.com/PHPCSStandards/composer-installer/issues/43 + + +## [v0.4.3] - 2017-09-18 + +### Changed +- CS: Add PHP 5.3 compatibility [#39] ([@GaryJones]) +- Local PHPCS [#38] ([@GaryJones]) + +[#38]: https://github.com/PHPCSStandards/composer-installer/pull/38 +[#39]: https://github.com/PHPCSStandards/composer-installer/pull/39 + + +## [v0.4.2] - 2017-08-16 + +### Changed +- Docs: Rename example script [#35] ([@GaryJones]) +- Update README.md [#36] ([@jrfnl]) +- Documentation update. [#37] ([@frenck]) + +[#35]: https://github.com/PHPCSStandards/composer-installer/pull/35 +[#36]: https://github.com/PHPCSStandards/composer-installer/pull/36 +[#37]: https://github.com/PHPCSStandards/composer-installer/pull/37 + + +## [v0.4.1] - 2017-08-01 + +### Closed issues +- Incorrect relative paths for WPCS [#33] + +### Fixed +- [#33]: Changes the way the installed_paths are set. [#34] ([@frenck]) + +[#33]: https://github.com/PHPCSStandards/composer-installer/issues/33 +[#34]: https://github.com/PHPCSStandards/composer-installer/pull/34 + + +## [v0.4.0] - 2017-05-11 + +### Closed issues +- Add support for code standards in root of repository for PHP_CodeSniffer 3.x [#26] +- Config codings styles in composer.json from project [#23] +- Check the root package for sniffs to install [#20] +- Document the ability to execute the main plugin functionality directly [#18] +- Add a CHANGELOG.md [#17] +- Install sniffs with relative paths in CodeSniffer.conf [#14] + +### Added +- Support for coding standard in the root repository for PHP_CodeSniffer v3.x [#30] ([@frenck]) +- Added support for having coding standards in the root package [#25] ([@frenck]) + +### Changed +- Local projects uses relative paths to their coding standards [#28] ([@frenck]) +- Docs: Updated README. [#31] ([@frenck]) +- Docs: Adds reference to calling the script directly in the README. [#29] ([@Potherca]) +- Adds Travis-CI configuration file. [#27] ([@Potherca]) + + +[#14]: https://github.com/PHPCSStandards/composer-installer/issues/14 +[#17]: https://github.com/PHPCSStandards/composer-installer/issues/17 +[#18]: https://github.com/PHPCSStandards/composer-installer/issues/18 +[#20]: https://github.com/PHPCSStandards/composer-installer/issues/20 +[#23]: https://github.com/PHPCSStandards/composer-installer/issues/23 +[#25]: https://github.com/PHPCSStandards/composer-installer/pull/25 +[#26]: https://github.com/PHPCSStandards/composer-installer/issues/26 +[#27]: https://github.com/PHPCSStandards/composer-installer/pull/27 +[#28]: https://github.com/PHPCSStandards/composer-installer/pull/28 +[#29]: https://github.com/PHPCSStandards/composer-installer/pull/29 +[#31]: https://github.com/PHPCSStandards/composer-installer/pull/31 + + +## [v0.3.2] - 2017-03-29 + +### Closed issues +- Coding Standard tries itself to install with installPath when it's the root package [#19] + +### Changed +- Improvements to the documentation [#22] ([@Potherca]) +- Added instanceof check to prevent root package from being installed [#21] ([@bastianschwarz]) + +### Fixed +- [#13]: Incorrect coding standards search depth [#15] ([@frenck]) + +[#19]: https://github.com/PHPCSStandards/composer-installer/issues/19 +[#21]: https://github.com/PHPCSStandards/composer-installer/pull/21 +[#22]: https://github.com/PHPCSStandards/composer-installer/pull/22 + + +## [v0.3.1] - 2017-02-17 + +### Closed issues +- Plugin not working correctly when sniffs install depth is equal to "1" [#13] +- Create new stable release version to support wider use [#11] + +### Fixed +- [#13]: Incorrect coding standards search depth [#15] ([@frenck]) + +[#11]: https://github.com/PHPCSStandards/composer-installer/issues/11 +[#13]: https://github.com/PHPCSStandards/composer-installer/issues/13 +[#15]: https://github.com/PHPCSStandards/composer-installer/pull/15 + + +## [v0.3.0] - 2017-02-15 + +### Implemented enhancements +- Install Plugin provides no feedback [#7] +- Installing coding standards when executing Composer with --no-scripts [#4] +- Github contribution templates [#10] ([@christopher-hopper]) +- Show config actions and a result as Console output [#8] ([@christopher-hopper]) +- Adds static function to call the Plugin::onDependenciesChangedEvent() method [#5] ([@Potherca]) + +### Added +- Support existing standards packages with subfolders [#6] ([@christopher-hopper]) + +### Changed +- Improved documentation [#12] ([@frenck]) +- Removal of lgtm.co [#3] ([@frenck]) + +[#3]: https://github.com/PHPCSStandards/composer-installer/pull/3 +[#4]: https://github.com/PHPCSStandards/composer-installer/issues/4 +[#5]: https://github.com/PHPCSStandards/composer-installer/pull/5 +[#6]: https://github.com/PHPCSStandards/composer-installer/pull/6 +[#7]: https://github.com/PHPCSStandards/composer-installer/issues/7 +[#8]: https://github.com/PHPCSStandards/composer-installer/pull/8 +[#10]: https://github.com/PHPCSStandards/composer-installer/pull/10 +[#12]: https://github.com/PHPCSStandards/composer-installer/pull/12 + + +## [v0.2.1] - 2016-11-01 + +Fixes an issue with having this plugin installed globally within composer, but using your global composer installation on a local repository without PHP_CodeSniffer installed. + +### Fixed +- Bugfix: Plugin fails when PHP_CodeSniffer is not installed [#2] ([@frenck]) + +[#2]: https://github.com/PHPCSStandards/composer-installer/pull/2 + + +## [v0.2.0] - 2016-11-01 + +For this version on, this installer no longer messes with the installation paths of composer libraries, but instead, it configures PHP_CodeSniffer to look into other directories for coding standards. + +### Changed +- PHPCS Configuration management [#1] ([@frenck]) + +[#1]: https://github.com/PHPCSStandards/composer-installer/pull/1 + + +## [v0.1.1] - 2016-10-24 + +### Changed +- Standard name mapping improvements + + +## v0.1.0 - 2016-10-23 + +First useable release. + +[v1.1.2]: https://github.com/PHPCSStandards/composer-installer/compare/v1.1.1...v1.1.2 +[v1.1.1]: https://github.com/PHPCSStandards/composer-installer/compare/v1.1.0...v1.1.1 +[v1.1.0]: https://github.com/PHPCSStandards/composer-installer/compare/v1.0.0...v1.1.0 +[v1.0.0]: https://github.com/PHPCSStandards/composer-installer/compare/v0.7.2...v1.0.0 +[v0.7.2]: https://github.com/PHPCSStandards/composer-installer/compare/v0.7.1...v0.7.2 +[v0.7.1]: https://github.com/PHPCSStandards/composer-installer/compare/v0.7.0...v0.7.1 +[v0.7.0]: https://github.com/PHPCSStandards/composer-installer/compare/v0.6.2...v0.7.0 +[v0.6.2]: https://github.com/PHPCSStandards/composer-installer/compare/v0.6.1...v0.6.2 +[v0.6.1]: https://github.com/PHPCSStandards/composer-installer/compare/v0.6.0...v0.6.1 +[v0.6.0]: https://github.com/PHPCSStandards/composer-installer/compare/v0.5.0...v0.6.0 +[v0.5.0]: https://github.com/PHPCSStandards/composer-installer/compare/v0.4.4...v0.5.0 +[v0.4.4]: https://github.com/PHPCSStandards/composer-installer/compare/v0.4.3...v0.4.4 +[v0.4.3]: https://github.com/PHPCSStandards/composer-installer/compare/v0.4.2...v0.4.3 +[v0.4.2]: https://github.com/PHPCSStandards/composer-installer/compare/v0.4.1...v0.4.2 +[v0.4.1]: https://github.com/PHPCSStandards/composer-installer/compare/v0.4.0...v0.4.1 +[v0.4.0]: https://github.com/PHPCSStandards/composer-installer/compare/v0.3.2...v0.4.0 +[v0.3.2]: https://github.com/PHPCSStandards/composer-installer/compare/v0.3.1...v0.3.2 +[v0.3.1]: https://github.com/PHPCSStandards/composer-installer/compare/v0.3.0...v0.3.1 +[v0.3.0]: https://github.com/PHPCSStandards/composer-installer/compare/v0.2.1...v0.3.0 +[v0.2.1]: https://github.com/PHPCSStandards/composer-installer/compare/v0.2.0...v0.2.1 +[v0.2.0]: https://github.com/PHPCSStandards/composer-installer/compare/v0.1.1...v0.2.0 +[v0.1.1]: https://github.com/PHPCSStandards/composer-installer/compare/v0.1.0...v0.1.1 + +[PHP_CodeSniffer]: https://github.com/PHPCSStandards/PHP_CodeSniffer + +[@bastianschwarz]: https://github.com/bastianschwarz +[@BrianHenryIE]: https://github.com/BrianHenryIE +[@christopher-hopper]: https://github.com/christopher-hopper +[@fredden]: https://github.com/fredden +[@frenck]: https://github.com/frenck +[@gapple]: https://github.com/gapple +[@GaryJones]: https://github.com/GaryJones +[@GrahamCampbell]: https://github.com/GrahamCampbell +[@jrfnl]: https://github.com/jrfnl +[@kevinfodness]: https://github.com/kevinfodness +[@mjrider]: https://github.com/mjrider +[@ntwb]: https://github.com/ntwb +[@paras-malhotra]: https://github.com/paras-malhotra +[@Potherca]: https://github.com/Potherca +[@Seldaek]: https://github.com/Seldaek +[@SplotyCode]: https://github.com/SplotyCode +[@TravisCarden]: https://github.com/TravisCarden diff --git a/app/vendor/dealerdirect/phpcodesniffer-composer-installer/README.md b/app/vendor/dealerdirect/phpcodesniffer-composer-installer/README.md index e8c263abc..273fefab3 100644 --- a/app/vendor/dealerdirect/phpcodesniffer-composer-installer/README.md +++ b/app/vendor/dealerdirect/phpcodesniffer-composer-installer/README.md @@ -1,6 +1,5 @@ # PHP_CodeSniffer Standards Composer Installer Plugin -![Project Stage][project-stage-shield] ![Last Commit][last-updated-shield] ![Awesome][awesome-shield] [![License][license-shield]](LICENSE.md) @@ -11,20 +10,19 @@ [![Contributor Covenant][code-of-conduct-shield]][code-of-conduct] -This composer installer plugin allows for easy installation of [PHP_CodeSniffer][codesniffer] coding standards (rulesets). +This composer installer plugin makes installation of [PHP_CodeSniffer][codesniffer] coding standards (rulesets) straight-forward. -No more symbolic linking of directories, checking out repositories on specific locations or changing -the `phpcs` configuration. +No more symbolic linking of directories, checking out repositories on specific locations or manually changing the `phpcs` configuration. ## Usage Installation can be done with [Composer][composer], by requiring this package as a development dependency: ```bash -composer require --dev dealerdirect/phpcodesniffer-composer-installer +composer require --dev dealerdirect/phpcodesniffer-composer-installer:"^1.0" ``` -When using Composer 2.2 or higher, Composer will [ask for your permission](https://blog.packagist.com/composer-2-2/#more-secure-plugin-execution) to allow this plugin to execute code. For this plugin to be functional, permission needs to be granted. +Since Composer 2.2, Composer will [ask for your permission](https://blog.packagist.com/composer-2-2/#more-secure-plugin-execution) to allow this plugin to execute code. For this plugin to be functional, permission needs to be granted. When permission has been granted, the following snippet will automatically be added to your `composer.json` file by Composer: ```json @@ -37,7 +35,7 @@ When permission has been granted, the following snippet will automatically be ad } ``` -When using Composer < 2.2, you can add the permission flag ahead of the upgrade to Composer 2.2, by running: +You can safely add the permission flag (to avoid Composer needing to ask), by running: ```bash composer config allow-plugins.dealerdirect/phpcodesniffer-composer-installer true ``` @@ -49,11 +47,8 @@ That's it. This plugin is compatible with: - PHP **5.4+**, **7.x**, and **8.x** (Support for PHP v8 is available since [`v0.7.0`][v0.7]) -- [Composer][composer] **1.x** and **2.x** (Support for Composer v2 is available since [`v0.7.0`][v0.7]) -- [PHP_CodeSniffer][codesniffer] **2.x** and **3.x** (Support for PHP_CodeSniffer v3 is available since [`v0.4.0`][v0.4]) - - -> **ℹ️ Please Note:** [Composer treats _minor_ releases below 1.0.0 as _major_ releases][composer-manual-caret]. So version `0.7.x` (or higher) of this plugin must be _explicitly_ set as version constraint when using Composer 2.x or PHP 8.0. In other words: using `^0.6` will **not** work with Composer 2.x or PHP 8.0. +- [Composer][composer] **2.2+** (Support for Composer v2 is available since [`v0.7.0`][v0.7]; support for Composer < 2.2 was dropped in [`v1.1.0`][v1.1]) +- [PHP_CodeSniffer][codesniffer] **2.x**, **3.x** and **4.x**(Support for PHP_CodeSniffer v3 is available since [`v0.4.0`][v0.4], support for PHP_CodeSniffer v4 since [`v0.7.0`][v0.7]) ### How it works @@ -92,7 +87,7 @@ After running `composer install` PHP_CodeSniffer just works: ```bash $ ./vendor/bin/phpcs -i -The installed coding standards are MySource, PEAR, PSR1, PSR2, PSR12, Squiz, Zend, ObjectCalisthenics, +The installed coding standards are PEAR, PSR1, PSR2, PSR12, Squiz, Zend, ObjectCalisthenics, PHPCompatibility, WordPress, WordPress-Core, WordPress-Docs and WordPress-Extra ``` @@ -198,23 +193,16 @@ via `require`, **not** `require-dev`. > To prevent your end-users getting into "_dependency hell_", make sure to make the version requirement > for this plugin flexible. > -> As, for now, this plugin is still regarded as "unstable" (version < 1.0), remember that Composer -> treats unstable minors as majors and will not be able to resolve one config requiring this plugin -> at version `^0.5`, while another requires it at version `^0.6`. +> Remember that [Composer treats unstable minors as majors][composer-manual-caret] and will not be able to resolve +> one config requiring this plugin at version `^0.7`, while another requires it at version `^1.0`. > Either allow multiple minors or use `*` as the version requirement. > > Some examples of flexible requirements which can be used: > ```bash > composer require dealerdirect/phpcodesniffer-composer-installer:"*" -> composer require dealerdirect/phpcodesniffer-composer-installer:"0.*" -> composer require dealerdirect/phpcodesniffer-composer-installer:"^0.4.1 || ^0.5 || ^0.6 || ^0.7" +> composer require dealerdirect/phpcodesniffer-composer-installer:"^0.4.1 || ^0.5 || ^0.6 || ^0.7 || ^1.0" > ``` -## Changelog - -This repository does not contain a `CHANGELOG.md` file, however, we do publish a changelog on each release -using the [GitHub releases][changelog] functionality. - ## Contributing This is an active open-source project. We are always open to people who want to @@ -228,14 +216,20 @@ Thank you for being involved! :heart_eyes: The original idea and setup of this repository is by [Franck Nijhof][frenck], employee @ Dealerdirect. -For a full list of all author and/or contributors, check [the contributors page][contributors]. +For a full list of all authors and/or contributors, check [the contributors page][contributors]. + +## Funding + +This project is included in the projects supported via the [PHP_CodeSniffer Open Collective][phpcs-open-collective]. + +If you use this plugin, financial contributions to the Open Collective are encouraged and appreciated. ## License The MIT License (MIT) Copyright (c) 2016-2022 Dealerdirect B.V. and contributors -Copyright (c) 2022 PHPCSStandards and contributors +Copyright (c) 2022- PHPCSStandards and contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -256,10 +250,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. [awesome-shield]: https://img.shields.io/badge/awesome%3F-yes-brightgreen.svg -[changelog]: https://github.com/PHPCSStandards/composer-installer/releases [code-of-conduct-shield]: https://img.shields.io/badge/Contributor%20Covenant-v2.0-ff69b4.svg [code-of-conduct]: CODE_OF_CONDUCT.md -[codesniffer]: https://github.com/squizlabs/PHP_CodeSniffer +[codesniffer]: https://github.com/PHPCSStandards/PHP_CodeSniffer [composer-manual-scripts]: https://getcomposer.org/doc/articles/scripts.md [composer-manual-caret]: https://getcomposer.org/doc/articles/versions.md#caret-version-range- [composer]: https://getcomposer.org/ @@ -274,12 +267,13 @@ THE SOFTWARE. [packagist-version]: https://packagist.org/packages/dealerdirect/phpcodesniffer-composer-installer [packagist]: https://packagist.org/packages/dealerdirect/phpcodesniffer-composer-installer [`phpcodesniffer-standard` packages]: https://packagist.org/explore/?type=phpcodesniffer-standard -[project-stage-shield]: https://img.shields.io/badge/Project%20Stage-Development-yellowgreen.svg +[phpcs-open-collective]: https://opencollective.com/php_codesniffer [scrutinizer-shield]: https://img.shields.io/scrutinizer/g/dealerdirect/phpcodesniffer-composer-installer.svg [scrutinizer]: https://scrutinizer-ci.com/g/dealerdirect/phpcodesniffer-composer-installer/ [ghactionstest-shield]: https://github.com/PHPCSStandards/composer-installer/actions/workflows/integrationtest.yml/badge.svg [ghactions]: https://github.com/PHPCSStandards/composer-installer/actions/workflows/integrationtest.yml -[tutorial]: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Coding-Standard-Tutorial +[tutorial]: https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki/Coding-Standard-Tutorial [using-composer-plugins]: https://getcomposer.org/doc/articles/plugins.md#using-plugins [v0.4]: https://github.com/PHPCSStandards/composer-installer/releases/tag/v0.4.0 [v0.7]: https://github.com/PHPCSStandards/composer-installer/releases/tag/v0.7.0 +[v1.1]: https://github.com/PHPCSStandards/composer-installer/releases/tag/v1.1.0 diff --git a/app/vendor/dealerdirect/phpcodesniffer-composer-installer/composer.json b/app/vendor/dealerdirect/phpcodesniffer-composer-installer/composer.json index bf3355ac4..73b27e7b7 100644 --- a/app/vendor/dealerdirect/phpcodesniffer-composer-installer/composer.json +++ b/app/vendor/dealerdirect/phpcodesniffer-composer-installer/composer.json @@ -8,14 +8,13 @@ "standard", "standards", "style guide", "stylecheck", "qa", "quality", "code quality", "tests" ], - "homepage": "http://www.dealerdirect.com", "license": "MIT", "authors": [ { "name": "Franck Nijhof", - "email": "franck.nijhof@dealerdirect.com", - "homepage": "http://www.frenck.nl", - "role": "Developer / IT Manager" + "email": "opensource@frenck.dev", + "homepage": "https://frenck.dev", + "role": "Open source developer" }, { "name" : "Contributors", @@ -24,19 +23,20 @@ ], "support": { "issues": "https://github.com/PHPCSStandards/composer-installer/issues", - "source": "https://github.com/PHPCSStandards/composer-installer" + "source": "https://github.com/PHPCSStandards/composer-installer", + "security": "https://github.com/PHPCSStandards/composer-installer/security/policy" }, "require": { "php": ">=5.4", - "composer-plugin-api": "^1.0 || ^2.0", + "composer-plugin-api": "^2.2", "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" }, "require-dev": { "ext-json": "*", "ext-zip": "*", - "composer/composer": "*", + "composer/composer": "^2.2", "phpcompatibility/php-compatibility": "^9.0", - "php-parallel-lint/php-parallel-lint": "^1.3.1", + "php-parallel-lint/php-parallel-lint": "^1.4.0", "yoast/phpunit-polyfills": "^1.0" }, "minimum-stability": "dev", @@ -51,6 +51,9 @@ "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Tests\\": "tests/" } }, + "config": { + "lock": false + }, "extra": { "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" }, @@ -59,7 +62,7 @@ "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin::run" ], "lint": [ - "@php ./vendor/php-parallel-lint/php-parallel-lint/parallel-lint . -e php --exclude vendor --exclude .git" + "@php ./vendor/php-parallel-lint/php-parallel-lint/parallel-lint . -e php --show-deprecated --exclude vendor --exclude .git" ], "test": [ "@php ./vendor/phpunit/phpunit/phpunit --no-coverage" diff --git a/app/vendor/dealerdirect/phpcodesniffer-composer-installer/src/Plugin.php b/app/vendor/dealerdirect/phpcodesniffer-composer-installer/src/Plugin.php index a2863d6c8..5d115df21 100644 --- a/app/vendor/dealerdirect/phpcodesniffer-composer-installer/src/Plugin.php +++ b/app/vendor/dealerdirect/phpcodesniffer-composer-installer/src/Plugin.php @@ -550,6 +550,10 @@ private function getPHPCodeSnifferPackage($versionConstraint = null) /** * Returns the path to the PHP_CodeSniffer package installation location * + * {@internal Do NOT try to modernize via the Composer 2.2 API (`InstalledVersions::getInstallPath()`). + * Doing so doesn't play nice with other plugins. + * {@link https://github.com/PHPCSStandards/composer-installer/issues/239}} + * * @return string */ private function getPHPCodeSnifferInstallPath() @@ -560,6 +564,10 @@ private function getPHPCodeSnifferInstallPath() /** * Simple check if PHP_CodeSniffer is installed. * + * {@internal Do NOT try to modernize via the Composer 2.2 API (`InstalledVersions::isInstalled()`). + * Doing so doesn't play nice with integrations calling the Composer EventDispatcher programmatically. + * {@link https://github.com/PHPCSStandards/composer-installer/issues/247}} + * * @param null|string|\Composer\Semver\Constraint\ConstraintInterface $versionConstraint to match against * * @return bool Whether PHP_CodeSniffer is installed diff --git a/app/vendor/doctrine/cache/LICENSE b/app/vendor/doctrine/cache/LICENSE deleted file mode 100644 index 8c38cc1bc..000000000 --- a/app/vendor/doctrine/cache/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2006-2015 Doctrine Project - -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/app/vendor/doctrine/cache/README.md b/app/vendor/doctrine/cache/README.md deleted file mode 100644 index a13196d15..000000000 --- a/app/vendor/doctrine/cache/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Doctrine Cache - -[![Build Status](https://github.com/doctrine/cache/workflows/Continuous%20Integration/badge.svg)](https://github.com/doctrine/cache/actions) -[![Code Coverage](https://codecov.io/gh/doctrine/cache/branch/1.10.x/graph/badge.svg)](https://codecov.io/gh/doctrine/cache/branch/1.10.x) - -[![Latest Stable Version](https://img.shields.io/packagist/v/doctrine/cache.svg?style=flat-square)](https://packagist.org/packages/doctrine/cache) -[![Total Downloads](https://img.shields.io/packagist/dt/doctrine/cache.svg?style=flat-square)](https://packagist.org/packages/doctrine/cache) - -Cache component extracted from the Doctrine Common project. [Documentation](https://www.doctrine-project.org/projects/doctrine-cache/en/current/index.html) - -This library is deprecated and will no longer receive bug fixes from the -Doctrine Project. Please use a different cache library, preferably PSR-6 or -PSR-16 instead. diff --git a/app/vendor/doctrine/cache/UPGRADE-1.11.md b/app/vendor/doctrine/cache/UPGRADE-1.11.md deleted file mode 100644 index 6c5ddb559..000000000 --- a/app/vendor/doctrine/cache/UPGRADE-1.11.md +++ /dev/null @@ -1,27 +0,0 @@ -# Upgrade to 1.11 - -doctrine/cache will no longer be maintained and all cache implementations have -been marked as deprecated. These implementations will be removed in 2.0, which -will only contain interfaces to provide a lightweight package for backward -compatibility. - -There are two new classes to use in the `Doctrine\Common\Cache\Psr6` namespace: -* The `CacheAdapter` class allows using any Doctrine Cache as PSR-6 cache. This - is useful to provide a forward compatibility layer in libraries that accept - Doctrine cache implementations and switch to PSR-6. -* The `DoctrineProvider` class allows using any PSR-6 cache as Doctrine cache. - This implementation is designed for libraries that leak the cache and want to - switch to allowing PSR-6 implementations. This class is design to be used - during the transition phase of sunsetting doctrine/cache support. - -A full example to setup a filesystem based PSR-6 cache with symfony/cache -using the `DoctrineProvider` to convert back to Doctrine's `Cache` interface: - -```php -use Doctrine\Common\Cache\Psr6\DoctrineProvider; -use Symfony\Component\Cache\Adapter\FilesystemAdapter; - -$cachePool = new FilesystemAdapter(); -$cache = DoctrineProvider::wrap($cachePool); -// $cache instanceof \Doctrine\Common\Cache\Cache -``` diff --git a/app/vendor/doctrine/cache/UPGRADE-1.4.md b/app/vendor/doctrine/cache/UPGRADE-1.4.md deleted file mode 100644 index e1f8a503e..000000000 --- a/app/vendor/doctrine/cache/UPGRADE-1.4.md +++ /dev/null @@ -1,16 +0,0 @@ -# Upgrade to 1.4 - -## Minor BC Break: `Doctrine\Common\Cache\FileCache#$extension` is now `private`. - -If you need to override the value of `Doctrine\Common\Cache\FileCache#$extension`, then use the -second parameter of `Doctrine\Common\Cache\FileCache#__construct()` instead of overriding -the property in your own implementation. - -## Minor BC Break: file based caches paths changed - -`Doctrine\Common\Cache\FileCache`, `Doctrine\Common\Cache\PhpFileCache` and -`Doctrine\Common\Cache\FilesystemCache` are using a different cache paths structure. - -If you rely on warmed up caches for deployments, consider that caches generated -with `doctrine/cache` `<1.4` are not compatible with the new directory structure, -and will be ignored. diff --git a/app/vendor/doctrine/cache/composer.json b/app/vendor/doctrine/cache/composer.json deleted file mode 100644 index 3c8ca971e..000000000 --- a/app/vendor/doctrine/cache/composer.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "name": "doctrine/cache", - "type": "library", - "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.", - "keywords": [ - "php", - "cache", - "caching", - "abstraction", - "redis", - "memcached", - "couchdb", - "xcache", - "apcu" - ], - "homepage": "https://www.doctrine-project.org/projects/cache.html", - "license": "MIT", - "authors": [ - {"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"}, - {"name": "Roman Borschel", "email": "roman@code-factory.org"}, - {"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"}, - {"name": "Jonathan Wage", "email": "jonwage@gmail.com"}, - {"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"} - ], - "require": { - "php": "~7.1 || ^8.0" - }, - "require-dev": { - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "doctrine/coding-standard": "^9", - "psr/cache": "^1.0 || ^2.0 || ^3.0", - "cache/integration-tests": "dev-master", - "symfony/cache": "^4.4 || ^5.4 || ^6", - "symfony/var-exporter": "^4.4 || ^5.4 || ^6" - }, - "conflict": { - "doctrine/common": ">2.2,<2.4" - }, - "autoload": { - "psr-4": { "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" } - }, - "autoload-dev": { - "psr-4": { "Doctrine\\Tests\\": "tests/Doctrine/Tests" } - }, - "config": { - "allow-plugins": { - "dealerdirect/phpcodesniffer-composer-installer": true - } - } -} diff --git a/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Cache.php b/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Cache.php deleted file mode 100644 index 4cfab6c0f..000000000 --- a/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Cache.php +++ /dev/null @@ -1,90 +0,0 @@ -hits - * Number of keys that have been requested and found present. - * - * - misses - * Number of items that have been requested and not found. - * - * - uptime - * Time that the server is running. - * - * - memory_usage - * Memory used by this server to store items. - * - * - memory_available - * Memory allowed to use for storage. - * - * @return mixed[]|null An associative array with server's statistics if available, NULL otherwise. - */ - public function getStats(); -} diff --git a/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/CacheProvider.php b/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/CacheProvider.php deleted file mode 100644 index 180482a7b..000000000 --- a/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/CacheProvider.php +++ /dev/null @@ -1,325 +0,0 @@ -namespace = (string) $namespace; - $this->namespaceVersion = null; - } - - /** - * Retrieves the namespace that prefixes all cache ids. - * - * @return string - */ - public function getNamespace() - { - return $this->namespace; - } - - /** - * {@inheritdoc} - */ - public function fetch($id) - { - return $this->doFetch($this->getNamespacedId($id)); - } - - /** - * {@inheritdoc} - */ - public function fetchMultiple(array $keys) - { - if (empty($keys)) { - return []; - } - - // note: the array_combine() is in place to keep an association between our $keys and the $namespacedKeys - $namespacedKeys = array_combine($keys, array_map([$this, 'getNamespacedId'], $keys)); - $items = $this->doFetchMultiple($namespacedKeys); - $foundItems = []; - - // no internal array function supports this sort of mapping: needs to be iterative - // this filters and combines keys in one pass - foreach ($namespacedKeys as $requestedKey => $namespacedKey) { - if (! isset($items[$namespacedKey]) && ! array_key_exists($namespacedKey, $items)) { - continue; - } - - $foundItems[$requestedKey] = $items[$namespacedKey]; - } - - return $foundItems; - } - - /** - * {@inheritdoc} - */ - public function saveMultiple(array $keysAndValues, $lifetime = 0) - { - $namespacedKeysAndValues = []; - foreach ($keysAndValues as $key => $value) { - $namespacedKeysAndValues[$this->getNamespacedId($key)] = $value; - } - - return $this->doSaveMultiple($namespacedKeysAndValues, $lifetime); - } - - /** - * {@inheritdoc} - */ - public function contains($id) - { - return $this->doContains($this->getNamespacedId($id)); - } - - /** - * {@inheritdoc} - */ - public function save($id, $data, $lifeTime = 0) - { - return $this->doSave($this->getNamespacedId($id), $data, $lifeTime); - } - - /** - * {@inheritdoc} - */ - public function deleteMultiple(array $keys) - { - return $this->doDeleteMultiple(array_map([$this, 'getNamespacedId'], $keys)); - } - - /** - * {@inheritdoc} - */ - public function delete($id) - { - return $this->doDelete($this->getNamespacedId($id)); - } - - /** - * {@inheritdoc} - */ - public function getStats() - { - return $this->doGetStats(); - } - - /** - * {@inheritDoc} - */ - public function flushAll() - { - return $this->doFlush(); - } - - /** - * {@inheritDoc} - */ - public function deleteAll() - { - $namespaceCacheKey = $this->getNamespaceCacheKey(); - $namespaceVersion = $this->getNamespaceVersion() + 1; - - if ($this->doSave($namespaceCacheKey, $namespaceVersion)) { - $this->namespaceVersion = $namespaceVersion; - - return true; - } - - return false; - } - - /** - * Prefixes the passed id with the configured namespace value. - * - * @param string $id The id to namespace. - * - * @return string The namespaced id. - */ - private function getNamespacedId(string $id): string - { - $namespaceVersion = $this->getNamespaceVersion(); - - return sprintf('%s[%s][%s]', $this->namespace, $id, $namespaceVersion); - } - - /** - * Returns the namespace cache key. - */ - private function getNamespaceCacheKey(): string - { - return sprintf(self::DOCTRINE_NAMESPACE_CACHEKEY, $this->namespace); - } - - /** - * Returns the namespace version. - */ - private function getNamespaceVersion(): int - { - if ($this->namespaceVersion !== null) { - return $this->namespaceVersion; - } - - $namespaceCacheKey = $this->getNamespaceCacheKey(); - $this->namespaceVersion = (int) $this->doFetch($namespaceCacheKey) ?: 1; - - return $this->namespaceVersion; - } - - /** - * Default implementation of doFetchMultiple. Each driver that supports multi-get should owerwrite it. - * - * @param string[] $keys Array of keys to retrieve from cache - * - * @return mixed[] Array of values retrieved for the given keys. - */ - protected function doFetchMultiple(array $keys) - { - $returnValues = []; - - foreach ($keys as $key) { - $item = $this->doFetch($key); - if ($item === false && ! $this->doContains($key)) { - continue; - } - - $returnValues[$key] = $item; - } - - return $returnValues; - } - - /** - * Fetches an entry from the cache. - * - * @param string $id The id of the cache entry to fetch. - * - * @return mixed|false The cached data or FALSE, if no cache entry exists for the given id. - */ - abstract protected function doFetch($id); - - /** - * Tests if an entry exists in the cache. - * - * @param string $id The cache id of the entry to check for. - * - * @return bool TRUE if a cache entry exists for the given cache id, FALSE otherwise. - */ - abstract protected function doContains($id); - - /** - * Default implementation of doSaveMultiple. Each driver that supports multi-put should override it. - * - * @param mixed[] $keysAndValues Array of keys and values to save in cache - * @param int $lifetime The lifetime. If != 0, sets a specific lifetime for these - * cache entries (0 => infinite lifeTime). - * - * @return bool TRUE if the operation was successful, FALSE if it wasn't. - */ - protected function doSaveMultiple(array $keysAndValues, $lifetime = 0) - { - $success = true; - - foreach ($keysAndValues as $key => $value) { - if ($this->doSave($key, $value, $lifetime)) { - continue; - } - - $success = false; - } - - return $success; - } - - /** - * Puts data into the cache. - * - * @param string $id The cache id. - * @param string $data The cache entry/data. - * @param int $lifeTime The lifetime. If != 0, sets a specific lifetime for this - * cache entry (0 => infinite lifeTime). - * - * @return bool TRUE if the entry was successfully stored in the cache, FALSE otherwise. - */ - abstract protected function doSave($id, $data, $lifeTime = 0); - - /** - * Default implementation of doDeleteMultiple. Each driver that supports multi-delete should override it. - * - * @param string[] $keys Array of keys to delete from cache - * - * @return bool TRUE if the operation was successful, FALSE if it wasn't - */ - protected function doDeleteMultiple(array $keys) - { - $success = true; - - foreach ($keys as $key) { - if ($this->doDelete($key)) { - continue; - } - - $success = false; - } - - return $success; - } - - /** - * Deletes a cache entry. - * - * @param string $id The cache id. - * - * @return bool TRUE if the cache entry was successfully deleted, FALSE otherwise. - */ - abstract protected function doDelete($id); - - /** - * Flushes all cache entries. - * - * @return bool TRUE if the cache entries were successfully flushed, FALSE otherwise. - */ - abstract protected function doFlush(); - - /** - * Retrieves cached information from the data store. - * - * @return mixed[]|null An associative array with server's statistics if available, NULL otherwise. - */ - abstract protected function doGetStats(); -} diff --git a/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ClearableCache.php b/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ClearableCache.php deleted file mode 100644 index b94618e46..000000000 --- a/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/ClearableCache.php +++ /dev/null @@ -1,21 +0,0 @@ - infinite lifeTime). - * - * @return bool TRUE if the operation was successful, FALSE if it wasn't. - */ - public function saveMultiple(array $keysAndValues, $lifetime = 0); -} diff --git a/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Psr6/CacheAdapter.php b/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Psr6/CacheAdapter.php deleted file mode 100644 index d3693b7c6..000000000 --- a/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Psr6/CacheAdapter.php +++ /dev/null @@ -1,340 +0,0 @@ - */ - private $deferredItems = []; - - public static function wrap(Cache $cache): CacheItemPoolInterface - { - if ($cache instanceof DoctrineProvider && ! $cache->getNamespace()) { - return $cache->getPool(); - } - - if ($cache instanceof SymfonyDoctrineProvider && ! $cache->getNamespace()) { - $getPool = function () { - // phpcs:ignore Squiz.Scope.StaticThisUsage.Found - return $this->pool; - }; - - return $getPool->bindTo($cache, SymfonyDoctrineProvider::class)(); - } - - return new self($cache); - } - - private function __construct(Cache $cache) - { - $this->cache = $cache; - } - - /** @internal */ - public function getCache(): Cache - { - return $this->cache; - } - - /** - * {@inheritDoc} - */ - public function getItem($key): CacheItemInterface - { - assert(self::validKey($key)); - - if (isset($this->deferredItems[$key])) { - $this->commit(); - } - - $value = $this->cache->fetch($key); - - if (PHP_VERSION_ID >= 80000) { - if ($value !== false) { - return new TypedCacheItem($key, $value, true); - } - - return new TypedCacheItem($key, null, false); - } - - if ($value !== false) { - return new CacheItem($key, $value, true); - } - - return new CacheItem($key, null, false); - } - - /** - * {@inheritDoc} - */ - public function getItems(array $keys = []): array - { - if ($this->deferredItems) { - $this->commit(); - } - - assert(self::validKeys($keys)); - - $values = $this->doFetchMultiple($keys); - $items = []; - - if (PHP_VERSION_ID >= 80000) { - foreach ($keys as $key) { - if (array_key_exists($key, $values)) { - $items[$key] = new TypedCacheItem($key, $values[$key], true); - } else { - $items[$key] = new TypedCacheItem($key, null, false); - } - } - - return $items; - } - - foreach ($keys as $key) { - if (array_key_exists($key, $values)) { - $items[$key] = new CacheItem($key, $values[$key], true); - } else { - $items[$key] = new CacheItem($key, null, false); - } - } - - return $items; - } - - /** - * {@inheritDoc} - */ - public function hasItem($key): bool - { - assert(self::validKey($key)); - - if (isset($this->deferredItems[$key])) { - $this->commit(); - } - - return $this->cache->contains($key); - } - - public function clear(): bool - { - $this->deferredItems = []; - - if (! $this->cache instanceof ClearableCache) { - return false; - } - - return $this->cache->deleteAll(); - } - - /** - * {@inheritDoc} - */ - public function deleteItem($key): bool - { - assert(self::validKey($key)); - unset($this->deferredItems[$key]); - - return $this->cache->delete($key); - } - - /** - * {@inheritDoc} - */ - public function deleteItems(array $keys): bool - { - foreach ($keys as $key) { - assert(self::validKey($key)); - unset($this->deferredItems[$key]); - } - - return $this->doDeleteMultiple($keys); - } - - public function save(CacheItemInterface $item): bool - { - return $this->saveDeferred($item) && $this->commit(); - } - - public function saveDeferred(CacheItemInterface $item): bool - { - if (! $item instanceof CacheItem && ! $item instanceof TypedCacheItem) { - return false; - } - - $this->deferredItems[$item->getKey()] = $item; - - return true; - } - - public function commit(): bool - { - if (! $this->deferredItems) { - return true; - } - - $now = microtime(true); - $itemsCount = 0; - $byLifetime = []; - $expiredKeys = []; - - foreach ($this->deferredItems as $key => $item) { - $lifetime = ($item->getExpiry() ?? $now) - $now; - - if ($lifetime < 0) { - $expiredKeys[] = $key; - - continue; - } - - ++$itemsCount; - $byLifetime[(int) $lifetime][$key] = $item->get(); - } - - $this->deferredItems = []; - - switch (count($expiredKeys)) { - case 0: - break; - case 1: - $this->cache->delete(current($expiredKeys)); - break; - default: - $this->doDeleteMultiple($expiredKeys); - break; - } - - if ($itemsCount === 1) { - return $this->cache->save($key, $item->get(), (int) $lifetime); - } - - $success = true; - foreach ($byLifetime as $lifetime => $values) { - $success = $this->doSaveMultiple($values, $lifetime) && $success; - } - - return $success; - } - - public function __destruct() - { - $this->commit(); - } - - /** - * @param mixed $key - */ - private static function validKey($key): bool - { - if (! is_string($key)) { - throw new InvalidArgument(sprintf('Cache key must be string, "%s" given.', is_object($key) ? get_class($key) : gettype($key))); - } - - if ($key === '') { - throw new InvalidArgument('Cache key length must be greater than zero.'); - } - - if (strpbrk($key, self::RESERVED_CHARACTERS) !== false) { - throw new InvalidArgument(sprintf('Cache key "%s" contains reserved characters "%s".', $key, self::RESERVED_CHARACTERS)); - } - - return true; - } - - /** - * @param mixed[] $keys - */ - private static function validKeys(array $keys): bool - { - foreach ($keys as $key) { - self::validKey($key); - } - - return true; - } - - /** - * @param mixed[] $keys - */ - private function doDeleteMultiple(array $keys): bool - { - if ($this->cache instanceof MultiDeleteCache) { - return $this->cache->deleteMultiple($keys); - } - - $success = true; - foreach ($keys as $key) { - $success = $this->cache->delete($key) && $success; - } - - return $success; - } - - /** - * @param mixed[] $keys - * - * @return mixed[] - */ - private function doFetchMultiple(array $keys): array - { - if ($this->cache instanceof MultiGetCache) { - return $this->cache->fetchMultiple($keys); - } - - $values = []; - foreach ($keys as $key) { - $value = $this->cache->fetch($key); - if (! $value) { - continue; - } - - $values[$key] = $value; - } - - return $values; - } - - /** - * @param mixed[] $keysAndValues - */ - private function doSaveMultiple(array $keysAndValues, int $lifetime = 0): bool - { - if ($this->cache instanceof MultiPutCache) { - return $this->cache->saveMultiple($keysAndValues, $lifetime); - } - - $success = true; - foreach ($keysAndValues as $key => $value) { - $success = $this->cache->save($key, $value, $lifetime) && $success; - } - - return $success; - } -} diff --git a/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Psr6/CacheItem.php b/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Psr6/CacheItem.php deleted file mode 100644 index 0b6f0a28d..000000000 --- a/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Psr6/CacheItem.php +++ /dev/null @@ -1,118 +0,0 @@ -key = $key; - $this->value = $data; - $this->isHit = $isHit; - } - - public function getKey(): string - { - return $this->key; - } - - /** - * {@inheritDoc} - * - * @return mixed - */ - public function get() - { - return $this->value; - } - - public function isHit(): bool - { - return $this->isHit; - } - - /** - * {@inheritDoc} - */ - public function set($value): self - { - $this->value = $value; - - return $this; - } - - /** - * {@inheritDoc} - */ - public function expiresAt($expiration): self - { - if ($expiration === null) { - $this->expiry = null; - } elseif ($expiration instanceof DateTimeInterface) { - $this->expiry = (float) $expiration->format('U.u'); - } else { - throw new TypeError(sprintf( - 'Expected $expiration to be an instance of DateTimeInterface or null, got %s', - is_object($expiration) ? get_class($expiration) : gettype($expiration) - )); - } - - return $this; - } - - /** - * {@inheritDoc} - */ - public function expiresAfter($time): self - { - if ($time === null) { - $this->expiry = null; - } elseif ($time instanceof DateInterval) { - $this->expiry = microtime(true) + DateTime::createFromFormat('U', 0)->add($time)->format('U.u'); - } elseif (is_int($time)) { - $this->expiry = $time + microtime(true); - } else { - throw new TypeError(sprintf( - 'Expected $time to be either an integer, an instance of DateInterval or null, got %s', - is_object($time) ? get_class($time) : gettype($time) - )); - } - - return $this; - } - - /** - * @internal - */ - public function getExpiry(): ?float - { - return $this->expiry; - } -} diff --git a/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Psr6/DoctrineProvider.php b/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Psr6/DoctrineProvider.php deleted file mode 100644 index 3b0f416c1..000000000 --- a/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Psr6/DoctrineProvider.php +++ /dev/null @@ -1,135 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Doctrine\Common\Cache\Psr6; - -use Doctrine\Common\Cache\Cache; -use Doctrine\Common\Cache\CacheProvider; -use Psr\Cache\CacheItemPoolInterface; -use Symfony\Component\Cache\Adapter\DoctrineAdapter as SymfonyDoctrineAdapter; -use Symfony\Contracts\Service\ResetInterface; - -use function rawurlencode; - -/** - * This class was copied from the Symfony Framework, see the original copyright - * notice above. The code is distributed subject to the license terms in - * https://github.com/symfony/symfony/blob/ff0cf61278982539c49e467db9ab13cbd342f76d/LICENSE - */ -final class DoctrineProvider extends CacheProvider -{ - /** @var CacheItemPoolInterface */ - private $pool; - - public static function wrap(CacheItemPoolInterface $pool): Cache - { - if ($pool instanceof CacheAdapter) { - return $pool->getCache(); - } - - if ($pool instanceof SymfonyDoctrineAdapter) { - $getCache = function () { - // phpcs:ignore Squiz.Scope.StaticThisUsage.Found - return $this->provider; - }; - - return $getCache->bindTo($pool, SymfonyDoctrineAdapter::class)(); - } - - return new self($pool); - } - - private function __construct(CacheItemPoolInterface $pool) - { - $this->pool = $pool; - } - - /** @internal */ - public function getPool(): CacheItemPoolInterface - { - return $this->pool; - } - - public function reset(): void - { - if ($this->pool instanceof ResetInterface) { - $this->pool->reset(); - } - - $this->setNamespace($this->getNamespace()); - } - - /** - * {@inheritdoc} - */ - protected function doFetch($id) - { - $item = $this->pool->getItem(rawurlencode($id)); - - return $item->isHit() ? $item->get() : false; - } - - /** - * {@inheritdoc} - * - * @return bool - */ - protected function doContains($id) - { - return $this->pool->hasItem(rawurlencode($id)); - } - - /** - * {@inheritdoc} - * - * @return bool - */ - protected function doSave($id, $data, $lifeTime = 0) - { - $item = $this->pool->getItem(rawurlencode($id)); - - if (0 < $lifeTime) { - $item->expiresAfter($lifeTime); - } - - return $this->pool->save($item->set($data)); - } - - /** - * {@inheritdoc} - * - * @return bool - */ - protected function doDelete($id) - { - return $this->pool->deleteItem(rawurlencode($id)); - } - - /** - * {@inheritdoc} - * - * @return bool - */ - protected function doFlush() - { - return $this->pool->clear(); - } - - /** - * {@inheritdoc} - * - * @return array|null - */ - protected function doGetStats() - { - return null; - } -} diff --git a/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Psr6/InvalidArgument.php b/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Psr6/InvalidArgument.php deleted file mode 100644 index 196f1bca9..000000000 --- a/app/vendor/doctrine/cache/lib/Doctrine/Common/Cache/Psr6/InvalidArgument.php +++ /dev/null @@ -1,13 +0,0 @@ -key; - } - - public function get(): mixed - { - return $this->value; - } - - public function isHit(): bool - { - return $this->isHit; - } - - public function set(mixed $value): static - { - $this->value = $value; - - return $this; - } - - /** - * {@inheritDoc} - */ - public function expiresAt($expiration): static - { - if ($expiration === null) { - $this->expiry = null; - } elseif ($expiration instanceof DateTimeInterface) { - $this->expiry = (float) $expiration->format('U.u'); - } else { - throw new TypeError(sprintf( - 'Expected $expiration to be an instance of DateTimeInterface or null, got %s', - get_debug_type($expiration) - )); - } - - return $this; - } - - /** - * {@inheritDoc} - */ - public function expiresAfter($time): static - { - if ($time === null) { - $this->expiry = null; - } elseif ($time instanceof DateInterval) { - $this->expiry = microtime(true) + DateTime::createFromFormat('U', 0)->add($time)->format('U.u'); - } elseif (is_int($time)) { - $this->expiry = $time + microtime(true); - } else { - throw new TypeError(sprintf( - 'Expected $time to be either an integer, an instance of DateInterval or null, got %s', - get_debug_type($time) - )); - } - - return $this; - } - - /** - * @internal - */ - public function getExpiry(): ?float - { - return $this->expiry; - } -} diff --git a/app/vendor/doctrine/dbal/README.md b/app/vendor/doctrine/dbal/README.md index bf1b204ea..4b724d61f 100644 --- a/app/vendor/doctrine/dbal/README.md +++ b/app/vendor/doctrine/dbal/README.md @@ -1,11 +1,10 @@ # Doctrine DBAL -| [5.0-dev][5.0] | [4.1-dev][4.1] | [4.0][4.0] | [3.9-dev][3.9] | [3.8][3.8] | -|:---------------------------------------------------:|:---------------------------------------------------:|:---------------------------------------------------:|:---------------------------------------------------:|:---------------------------------------------------:| -| [![GitHub Actions][GA 5.0 image]][GA 5.0] | [![GitHub Actions][GA 4.1 image]][GA 4.1] | [![GitHub Actions][GA 4.0 image]][GA 4.0] | [![GitHub Actions][GA 3.9 image]][GA 3.9] | [![GitHub Actions][GA 3.8 image]][GA 3.8] | -| [![AppVeyor][AppVeyor 5.0 image]][AppVeyor 5.0] | [![AppVeyor][AppVeyor 4.1 image]][AppVeyor 4.1] | [![AppVeyor][AppVeyor 4.0 image]][AppVeyor 4.0] | [![AppVeyor][AppVeyor 3.9 image]][AppVeyor 3.9] | [![AppVeyor][AppVeyor 3.8 image]][AppVeyor 3.8] | -| [![Code Coverage][Coverage 5.0 image]][CodeCov 5.0] | [![Code Coverage][Coverage 4.1 image]][CodeCov 4.1] | [![Code Coverage][Coverage 4.0 image]][CodeCov 4.0] | [![Code Coverage][Coverage 3.9 image]][CodeCov 3.9] | [![Code Coverage][Coverage 3.8 image]][CodeCov 3.8] | -| N/A | N/A | [![Type Coverage][TypeCov image]][TypeCov] | N/A | | +| [5.0-dev][5.0] | [4.4-dev][4.4] | [4.3][4.3] | [3.10][3.10] | +|:---------------------------------------------------:|:---------------------------------------------------:|:---------------------------------------------------:|:-----------------------------------------------------:| +| [![GitHub Actions][GA 5.0 image]][GA 5.0] | [![GitHub Actions][GA 4.4 image]][GA 4.4] | [![GitHub Actions][GA 4.3 image]][GA 4.3] | [![GitHub Actions][GA 3.10 image]][GA 3.10] | +| [![AppVeyor][AppVeyor 5.0 image]][AppVeyor 5.0] | [![AppVeyor][AppVeyor 4.4 image]][AppVeyor 4.4] | [![AppVeyor][AppVeyor 4.3 image]][AppVeyor 4.3] | [![AppVeyor][AppVeyor 3.10 image]][AppVeyor 3.10] | +| [![Code Coverage][Coverage 5.0 image]][CodeCov 5.0] | [![Code Coverage][Coverage 4.4 image]][CodeCov 4.4] | [![Code Coverage][Coverage 4.3 image]][CodeCov 4.3] | [![Code Coverage][Coverage 3.10 image]][CodeCov 3.10] | Powerful ***D***ata***B***ase ***A***bstraction ***L***ayer with many features for database schema introspection and schema management. @@ -21,38 +20,28 @@ Powerful ***D***ata***B***ase ***A***bstraction ***L***ayer with many features f [AppVeyor 5.0]: https://ci.appveyor.com/project/doctrine/dbal/branch/5.0.x [AppVeyor 5.0 image]: https://ci.appveyor.com/api/projects/status/i88kitq8qpbm0vie/branch/5.0.x?svg=true [GA 5.0]: https://github.com/doctrine/dbal/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A5.0.x - [GA 5.0 image]: https://github.com/doctrine/dbal/workflows/Continuous%20Integration/badge.svg?branch=5.0.x - - [Coverage 4.1 image]: https://codecov.io/gh/doctrine/dbal/branch/4.1.x/graph/badge.svg - [4.1]: https://github.com/doctrine/dbal/tree/4.1.x - [CodeCov 4.1]: https://codecov.io/gh/doctrine/dbal/branch/4.1.x - [AppVeyor 4.1]: https://ci.appveyor.com/project/doctrine/dbal/branch/4.1.x - [AppVeyor 4.1 image]: https://ci.appveyor.com/api/projects/status/i88kitq8qpbm0vie/branch/4.1.x?svg=true - [GA 4.1]: https://github.com/doctrine/dbal/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A4.1.x - [GA 4.1 image]: https://github.com/doctrine/dbal/workflows/Continuous%20Integration/badge.svg?branch=4.1.x - - [Coverage 4.0 image]: https://codecov.io/gh/doctrine/dbal/branch/4.0.x/graph/badge.svg - [4.0]: https://github.com/doctrine/dbal/tree/4.0.x - [CodeCov 4.0]: https://codecov.io/gh/doctrine/dbal/branch/4.0.x - [AppVeyor 4.0]: https://ci.appveyor.com/project/doctrine/dbal/branch/4.0.x - [AppVeyor 4.0 image]: https://ci.appveyor.com/api/projects/status/i88kitq8qpbm0vie/branch/4.0.x?svg=true - [GA 4.0]: https://github.com/doctrine/dbal/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A4.0.x - [GA 4.0 image]: https://github.com/doctrine/dbal/workflows/Continuous%20Integration/badge.svg?branch=4.0.x - [TypeCov]: https://shepherd.dev/github/doctrine/dbal - [TypeCov image]: https://shepherd.dev/github/doctrine/dbal/coverage.svg - - [Coverage 3.9 image]: https://codecov.io/gh/doctrine/dbal/branch/3.9.x/graph/badge.svg - [3.9]: https://github.com/doctrine/dbal/tree/3.9.x - [CodeCov 3.9]: https://codecov.io/gh/doctrine/dbal/branch/3.9.x - [AppVeyor 3.9]: https://ci.appveyor.com/project/doctrine/dbal/branch/3.9.x - [AppVeyor 3.9 image]: https://ci.appveyor.com/api/projects/status/i88kitq8qpbm0vie/branch/3.9.x?svg=true - [GA 3.9]: https://github.com/doctrine/dbal/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A3.9.x - [GA 3.9 image]: https://github.com/doctrine/dbal/workflows/Continuous%20Integration/badge.svg?branch=3.9.x - - [Coverage 3.8 image]: https://codecov.io/gh/doctrine/dbal/branch/3.8.x/graph/badge.svg - [3.8]: https://github.com/doctrine/dbal/tree/3.8.x - [CodeCov 3.8]: https://codecov.io/gh/doctrine/dbal/branch/3.8.x - [AppVeyor 3.8]: https://ci.appveyor.com/project/doctrine/dbal/branch/3.8.x - [AppVeyor 3.8 image]: https://ci.appveyor.com/api/projects/status/i88kitq8qpbm0vie/branch/3.8.x?svg=true - [GA 3.8]: https://github.com/doctrine/dbal/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A3.8.x - [GA 3.8 image]: https://github.com/doctrine/dbal/workflows/Continuous%20Integration/badge.svg?branch=3.8.x + [GA 5.0 image]: https://github.com/doctrine/dbal/actions/workflows/continuous-integration.yml/badge.svg?branch=5.0.x + + [Coverage 4.4 image]: https://codecov.io/gh/doctrine/dbal/branch/4.4.x/graph/badge.svg + [4.4]: https://github.com/doctrine/dbal/tree/4.4.x + [CodeCov 4.4]: https://codecov.io/gh/doctrine/dbal/branch/4.4.x + [AppVeyor 4.4]: https://ci.appveyor.com/project/doctrine/dbal/branch/4.4.x + [AppVeyor 4.4 image]: https://ci.appveyor.com/api/projects/status/i88kitq8qpbm0vie/branch/4.4.x?svg=true + [GA 4.4]: https://github.com/doctrine/dbal/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A4.4.x + [GA 4.4 image]: https://github.com/doctrine/dbal/actions/workflows/continuous-integration.yml/badge.svg?branch=4.4.x + + [Coverage 4.3 image]: https://codecov.io/gh/doctrine/dbal/branch/4.3.x/graph/badge.svg + [4.3]: https://github.com/doctrine/dbal/tree/4.3.x + [CodeCov 4.3]: https://codecov.io/gh/doctrine/dbal/branch/4.3.x + [AppVeyor 4.3]: https://ci.appveyor.com/project/doctrine/dbal/branch/4.3.x + [AppVeyor 4.3 image]: https://ci.appveyor.com/api/projects/status/i88kitq8qpbm0vie/branch/4.3.x?svg=true + [GA 4.3]: https://github.com/doctrine/dbal/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A4.3.x + [GA 4.3 image]: https://github.com/doctrine/dbal/actions/workflows/continuous-integration.yml/badge.svg?branch=4.3.x + + [Coverage 3.10 image]: https://codecov.io/gh/doctrine/dbal/branch/3.10.x/graph/badge.svg + [3.10]: https://github.com/doctrine/dbal/tree/3.10.x + [CodeCov 3.10]: https://codecov.io/gh/doctrine/dbal/branch/3.10.x + [AppVeyor 3.10]: https://ci.appveyor.com/project/doctrine/dbal/branch/3.10.x + [AppVeyor 3.10 image]: https://ci.appveyor.com/api/projects/status/i88kitq8qpbm0vie/branch/3.10.x?svg=true + [GA 3.10]: https://github.com/doctrine/dbal/actions?query=workflow%3A%22Continuous+Integration%22+branch%3A3.10.x + [GA 3.10 image]: https://github.com/doctrine/dbal/actions/workflows/continuous-integration.yml/badge.svg?branch=3.10.x diff --git a/app/vendor/doctrine/dbal/composer.json b/app/vendor/doctrine/dbal/composer.json index 53d08298a..4ff95d983 100644 --- a/app/vendor/doctrine/dbal/composer.json +++ b/app/vendor/doctrine/dbal/composer.json @@ -33,25 +33,26 @@ "require": { "php": "^7.4 || ^8.0", "composer-runtime-api": "^2", - "doctrine/cache": "^1.11|^2.0", "doctrine/deprecations": "^0.5.3|^1", "doctrine/event-manager": "^1|^2", "psr/cache": "^1|^2|^3", "psr/log": "^1|^2|^3" }, "require-dev": { - "doctrine/coding-standard": "12.0.0", + "doctrine/cache": "^1.11|^2.0", + "doctrine/coding-standard": "13.0.0", "fig/log-test": "^1", "jetbrains/phpstorm-stubs": "2023.1", - "phpstan/phpstan": "1.10.57", - "phpstan/phpstan-strict-rules": "^1.5", - "phpunit/phpunit": "9.6.16", - "psalm/plugin-phpunit": "0.18.4", - "slevomat/coding-standard": "8.13.1", - "squizlabs/php_codesniffer": "3.8.1", + "phpstan/phpstan": "2.1.17", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "9.6.23", + "slevomat/coding-standard": "8.16.2", + "squizlabs/php_codesniffer": "3.13.1", "symfony/cache": "^5.4|^6.0|^7.0", - "symfony/console": "^4.4|^5.4|^6.0|^7.0", - "vimeo/psalm": "4.30.0" + "symfony/console": "^4.4|^5.4|^6.0|^7.0" + }, + "conflict": { + "doctrine/cache": "< 1.11" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." diff --git a/app/vendor/doctrine/dbal/phpstan-baseline.neon b/app/vendor/doctrine/dbal/phpstan-baseline.neon new file mode 100644 index 000000000..7bb0252a5 --- /dev/null +++ b/app/vendor/doctrine/dbal/phpstan-baseline.neon @@ -0,0 +1,829 @@ +parameters: + ignoreErrors: + - + message: '#^@readonly property cannot have a default value\.$#' + identifier: property.readOnlyByPhpDocDefaultValue + count: 1 + path: src/Driver/AbstractException.php + + - + message: '#^Method Doctrine\\DBAL\\Driver\\OCI8\\Result\:\:fetchAllAssociative\(\) should return list\\> but returns array\\.$#' + identifier: return.type + count: 1 + path: src/Driver/OCI8/Result.php + + - + message: '#^Method Doctrine\\DBAL\\Driver\\OCI8\\Result\:\:fetchAllNumeric\(\) should return list\\> but returns array\\.$#' + identifier: return.type + count: 1 + path: src/Driver/OCI8/Result.php + + - + message: '#^@readonly property Doctrine\\DBAL\\Driver\\PDO\\PDOException\:\:\$sqlState is assigned outside of the constructor\.$#' + identifier: property.readOnlyByPhpDocAssignNotInConstructor + count: 1 + path: src/Driver/PDO/PDOException.php + + - + message: '#^@readonly property cannot have a default value\.$#' + identifier: property.readOnlyByPhpDocDefaultValue + count: 1 + path: src/Driver/PDO/PDOException.php + + - + message: '#^Method Doctrine\\DBAL\\Driver\\PDO\\Result\:\:fetchAll\(\) should return list\ but returns array\.$#' + identifier: return.type + count: 1 + path: src/Driver/PDO/Result.php + + - + message: '#^Method Doctrine\\DBAL\\Driver\\PgSQL\\Result\:\:fetchAllAssociative\(\) should return list\\> but returns array\\>\.$#' + identifier: return.type + count: 1 + path: src/Driver/PgSQL/Result.php + + - + message: '#^Method Doctrine\\DBAL\\Driver\\PgSQL\\Result\:\:fetchAllNumeric\(\) should return list\\> but returns array\\>\.$#' + identifier: return.type + count: 1 + path: src/Driver/PgSQL/Result.php + + - + message: '#^Method Doctrine\\DBAL\\Driver\\PgSQL\\Result\:\:fetchFirstColumn\(\) should return list\ but returns array\\.$#' + identifier: return.type + count: 1 + path: src/Driver/PgSQL/Result.php + + - + message: '#^Method Doctrine\\DBAL\\Driver\\SQLite3\\Result\:\:fetchNumeric\(\) should return list\\|false but returns array\|false\.$#' + identifier: return.type + count: 1 + path: src/Driver/SQLite3/Result.php + + - + message: '#^Method Doctrine\\DBAL\\Platforms\\AbstractMySQLPlatform\:\:getAlterTableSQL\(\) should return list\ but returns array\\.$#' + identifier: return.type + count: 1 + path: src/Platforms/AbstractMySQLPlatform.php + + - + message: '#^Parameter \#1 \$assets of method Doctrine\\DBAL\\Platforms\\AbstractMySQLPlatform\:\:indexAssetsByLowerCaseName\(\) expects list\, array\ given\.$#' + identifier: argument.type + count: 1 + path: src/Platforms/AbstractMySQLPlatform.php + + - + message: '#^Method Doctrine\\DBAL\\Platforms\\AbstractPlatform\:\:buildCreateTableSQL\(\) should return list\ but returns array\\.$#' + identifier: return.type + count: 2 + path: src/Platforms/AbstractPlatform.php + + - + message: '#^Method Doctrine\\DBAL\\Platforms\\DB2Platform\:\:getAlterTableSQL\(\) should return list\ but returns array\\.$#' + identifier: return.type + count: 1 + path: src/Platforms/DB2Platform.php + + - + message: '#^Method Doctrine\\DBAL\\Platforms\\OraclePlatform\:\:getAlterTableSQL\(\) should return list\ but returns array\\.$#' + identifier: return.type + count: 1 + path: src/Platforms/OraclePlatform.php + + - + message: '#^Method Doctrine\\DBAL\\Platforms\\PostgreSQLPlatform\:\:getAlterTableSQL\(\) should return list\ but returns array\\.$#' + identifier: return.type + count: 1 + path: src/Platforms/PostgreSQLPlatform.php + + - + message: '#^Method Doctrine\\DBAL\\Platforms\\SQLServerPlatform\:\:getAlterTableSQL\(\) should return list\ but returns array\\.$#' + identifier: return.type + count: 2 + path: src/Platforms/SQLServerPlatform.php + + - + message: '#^Method Doctrine\\DBAL\\Platforms\\SqlitePlatform\:\:getAlterTableSQL\(\) should return list\ but returns array\\.$#' + identifier: return.type + count: 1 + path: src/Platforms/SqlitePlatform.php + + - + message: '#^Method Doctrine\\DBAL\\Platforms\\SqlitePlatform\:\:getAlterTableSQL\(\) should return list\ but returns array\\.$#' + identifier: return.type + count: 1 + path: src/Platforms/SqlitePlatform.php + + - + message: '#^Parameter &\$knownAliases by\-ref type of method Doctrine\\DBAL\\Query\\QueryBuilder\:\:getSQLForJoins\(\) expects array\, non\-empty\-array\ given\.$#' + identifier: parameterByRef.type + count: 1 + path: src/Query/QueryBuilder.php + + - + message: '#^Property Doctrine\\DBAL\\Query\\QueryBuilder\:\:\$params \(array\\|string, mixed\>\) does not accept non\-empty\-array\\.$#' + identifier: assign.propertyType + count: 1 + path: src/Query/QueryBuilder.php + + - + message: '#^Parameter \#1 \$sequences of method Doctrine\\DBAL\\SQL\\Builder\\DropSchemaObjectsSQLBuilder\:\:buildSequenceStatements\(\) expects list\, array\ given\.$#' + identifier: argument.type + count: 1 + path: src/SQL/Builder/DropSchemaObjectsSQLBuilder.php + + - + message: '#^Parameter \#1 \$tables of method Doctrine\\DBAL\\SQL\\Builder\\DropSchemaObjectsSQLBuilder\:\:buildTableStatements\(\) expects list\, array\ given\.$#' + identifier: argument.type + count: 1 + path: src/SQL/Builder/DropSchemaObjectsSQLBuilder.php + + - + message: '#^Method Doctrine\\DBAL\\Schema\\AbstractSchemaManager\:\:doListTableNames\(\) should return list\ but returns array\\.$#' + identifier: return.type + count: 1 + path: src/Schema/AbstractSchemaManager.php + + - + message: '#^Template type T is declared as covariant, but occurs in invariant position in property Doctrine\\DBAL\\Schema\\AbstractSchemaManager\:\:\$_platform\.$#' + identifier: generics.variance + count: 1 + path: src/Schema/AbstractSchemaManager.php + + - + message: '#^Parameter \#1 \$tables of method Doctrine\\DBAL\\Platforms\\AbstractPlatform\:\:getDropTablesSQL\(\) expects list\, array\ given\.$#' + identifier: argument.type + count: 1 + path: src/Schema/SchemaDiff.php + + - + message: '#^Method Doctrine\\DBAL\\Schema\\SqliteSchemaManager\:\:addDetailsToTableForeignKeyColumns\(\) should return list\\> but returns array\, array\\>\.$#' + identifier: return.type + count: 1 + path: src/Schema/SqliteSchemaManager.php + + - + message: '#^Method Doctrine\\DBAL\\Schema\\TableDiff\:\:getAddedForeignKeys\(\) should return list\ but returns array\\.$#' + identifier: return.type + count: 1 + path: src/Schema/TableDiff.php + + - + message: '#^Method Doctrine\\DBAL\\Schema\\TableDiff\:\:getDroppedForeignKeys\(\) should return list\ but returns array\\.$#' + identifier: return.type + count: 1 + path: src/Schema/TableDiff.php + + - + message: '#^Method Doctrine\\DBAL\\Schema\\TableDiff\:\:getModifiedForeignKeys\(\) should return list\ but returns array\\.$#' + identifier: return.type + count: 1 + path: src/Schema/TableDiff.php + + - + message: '#^Parameter \#2 \$haystack of static method PHPUnit\\Framework\\Assert\:\:assertStringNotContainsString\(\) expects string, array\\|string given\.$#' + identifier: argument.type + count: 1 + path: tests/Cache/QueryCacheProfileTest.php + + - + message: '#^Parameter \#1 \$cache of method Doctrine\\DBAL\\Tests\\Connection\\CachedQueryTest\:\:assertCachedQueryIsExecutedOnceAndYieldsTheSameResult\(\) expects Doctrine\\Common\\Cache\\Cache\|Psr\\Cache\\CacheItemPoolInterface, Doctrine\\Common\\Cache\\ArrayCache given\.$#' + identifier: argument.type + count: 1 + path: tests/Connection/CachedQueryTest.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\Assert\:\:equalTo\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 2 + path: tests/Connection/LoggingTest.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\TestCase\:\:once\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 2 + path: tests/Connection/LoggingTest.php + + - + message: '#^Dead catch \- RuntimeException is never thrown in the try block\.$#' + identifier: catch.neverThrown + count: 1 + path: tests/ConnectionTest.php + + - + message: '#^Parameter \#1 \$params of class Doctrine\\DBAL\\Connection constructor expects array\{application_name\?\: string, charset\?\: string, dbname\?\: string, defaultTableOptions\?\: array\, default_dbname\?\: string, driver\?\: ''ibm_db2''\|''mysqli''\|''oci8''\|''pdo_mysql''\|''pdo_oci''\|''pdo_pgsql''\|''pdo_sqlite''\|''pdo_sqlsrv''\|''pgsql''\|''sqlite3''\|''sqlsrv'', driverClass\?\: class\-string\, driverOptions\?\: array\, \.\.\.\}, array\{driver\: ''pdo_mysql'', host\: ''localhost'', user\: ''root'', password\: ''password'', port\: 1234, platform\: stdClass\} given\.$#' + identifier: argument.type + count: 1 + path: tests/ConnectionTest.php + + - + message: '#^Return type \(void\) of method Doctrine\\DBAL\\Connection@anonymous/tests/ConnectionTest\.php\:1079\:\:rollBack\(\) should be compatible with return type \(bool\) of method Doctrine\\DBAL\\Connection\:\:rollBack\(\)$#' + identifier: method.childReturnType + count: 1 + path: tests/ConnectionTest.php + + - + message: '#^Return type \(void\) of method Doctrine\\DBAL\\Connection@anonymous/tests/ConnectionTest\.php\:1103\:\:commit\(\) should be compatible with return type \(bool\) of method Doctrine\\DBAL\\Connection\:\:commit\(\)$#' + identifier: method.childReturnType + count: 1 + path: tests/ConnectionTest.php + + - + message: '#^Return type \(void\) of method Doctrine\\DBAL\\Connection@anonymous/tests/ConnectionTest\.php\:1103\:\:rollBack\(\) should be compatible with return type \(bool\) of method Doctrine\\DBAL\\Connection\:\:rollBack\(\)$#' + identifier: method.childReturnType + count: 1 + path: tests/ConnectionTest.php + + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: tests/ConnectionTest.php + + - + message: '#^Call to an undefined method Doctrine\\DBAL\\Driver\:\:createDatabasePlatformForVersion\(\)\.$#' + identifier: method.notFound + count: 1 + path: tests/Driver/AbstractDriverTestCase.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\Assert\:\:assertSame\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 1 + path: tests/Driver/IBMDB2/DataSourceNameTest.php + + - + message: '#^Parameter \#1 \$params of method Doctrine\\DBAL\\Driver\\Mysqli\\Driver\:\:connect\(\) expects array\{application_name\?\: string, charset\?\: string, dbname\?\: string, defaultTableOptions\?\: array\, default_dbname\?\: string, driver\?\: ''ibm_db2''\|''mysqli''\|''oci8''\|''pdo_mysql''\|''pdo_oci''\|''pdo_pgsql''\|''pdo_sqlite''\|''pdo_sqlsrv''\|''pgsql''\|''sqlite3''\|''sqlsrv'', driverClass\?\: class\-string\, driverOptions\?\: array\, \.\.\.\}, array\{persistent\: ''true''\} given\.$#' + identifier: argument.type + count: 1 + path: tests/Driver/Mysqli/ConnectionTest.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\Assert\:\:markTestSkipped\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 1 + path: tests/Driver/PDO/PgSQL/DriverTest.php + + - + message: '#^Offset string might not exist on array\{application_name\?\: string, charset\?\: string, dbname\?\: string, defaultTableOptions\?\: array\, default_dbname\?\: string, driver\?\: ''ibm_db2''\|''mysqli''\|''oci8''\|''pdo_mysql''\|''pdo_oci''\|''pdo_pgsql''\|''pdo_sqlite''\|''pdo_sqlsrv''\|''pgsql''\|''sqlite3''\|''sqlsrv'', driverClass\?\: class\-string\, driverOptions\?\: array\, \.\.\.\}\.$#' + identifier: offsetAccess.notFound + count: 2 + path: tests/DriverManagerTest.php + + - + message: '#^Parameter \#1 \$params of static method Doctrine\\DBAL\\DriverManager\:\:getConnection\(\) expects array\{application_name\?\: string, charset\?\: string, dbname\?\: string, defaultTableOptions\?\: array\, default_dbname\?\: string, driver\?\: ''ibm_db2''\|''mysqli''\|''oci8''\|''pdo_mysql''\|''pdo_oci''\|''pdo_pgsql''\|''pdo_sqlite''\|''pdo_sqlsrv''\|''pgsql''\|''sqlite3''\|''sqlsrv'', driverClass\?\: class\-string\, driverOptions\?\: array\, \.\.\.\}, array\{driver\: ''invalid_driver''\} given\.$#' + identifier: argument.type + count: 1 + path: tests/DriverManagerTest.php + + - + message: '#^Parameter \#1 \$params of static method Doctrine\\DBAL\\DriverManager\:\:getConnection\(\) expects array\{application_name\?\: string, charset\?\: string, dbname\?\: string, defaultTableOptions\?\: array\, default_dbname\?\: string, driver\?\: ''ibm_db2''\|''mysqli''\|''oci8''\|''pdo_mysql''\|''pdo_oci''\|''pdo_pgsql''\|''pdo_sqlite''\|''pdo_sqlsrv''\|''pgsql''\|''sqlite3''\|''sqlsrv'', driverClass\?\: class\-string\, driverOptions\?\: array\, \.\.\.\}, array\{driver\: ''pdo_sqlite'', memory\: true, wrapperClass\: ''stdClass''\} given\.$#' + identifier: argument.type + count: 1 + path: tests/DriverManagerTest.php + + - + message: '#^Parameter \#1 \$params of static method Doctrine\\DBAL\\DriverManager\:\:getConnection\(\) expects array\{application_name\?\: string, charset\?\: string, dbname\?\: string, defaultTableOptions\?\: array\, default_dbname\?\: string, driver\?\: ''ibm_db2''\|''mysqli''\|''oci8''\|''pdo_mysql''\|''pdo_oci''\|''pdo_pgsql''\|''pdo_sqlite''\|''pdo_sqlsrv''\|''pgsql''\|''sqlite3''\|''sqlsrv'', driverClass\?\: class\-string\, driverOptions\?\: array\, \.\.\.\}, array\{driverClass\: ''stdClass''\} given\.$#' + identifier: argument.type + count: 1 + path: tests/DriverManagerTest.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\Assert\:\:markTestSkipped\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 1 + path: tests/Functional/Connection/ConnectionLostTest.php + + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: tests/Functional/ConnectionTest.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\Assert\:\:assertNull\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 1 + path: tests/Functional/Driver/DBAL6024Test.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\Assert\:\:assertEquals\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 2 + path: tests/Functional/Driver/DBAL6044Test.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\Assert\:\:assertFalse\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 1 + path: tests/Functional/Driver/DBAL6044Test.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\Assert\:\:assertTrue\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 1 + path: tests/Functional/Driver/DBAL6044Test.php + + - + message: '#^Cannot access property \$affected_rows on mysqli_stmt\|false\.$#' + identifier: property.nonObject + count: 1 + path: tests/Functional/Driver/Mysqli/ResultTest.php + + - + message: '#^Cannot call method execute\(\) on mysqli_stmt\|false\.$#' + identifier: method.nonObject + count: 2 + path: tests/Functional/Driver/Mysqli/ResultTest.php + + - + message: '#^Parameter \#1 \$statement of class Doctrine\\DBAL\\Driver\\Mysqli\\Result constructor expects mysqli_stmt, mysqli_stmt\|false given\.$#' + identifier: argument.type + count: 2 + path: tests/Functional/Driver/Mysqli/ResultTest.php + + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: tests/Functional/Driver/Mysqli/ResultTest.php + + - + message: '#^Call to sprintf contains 0 placeholders, 1 value given\.$#' + identifier: argument.sprintf + count: 2 + path: tests/Functional/Driver/OCI8/ResultTest.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\Assert\:\:assertEquals\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 1 + path: tests/Functional/Driver/OCI8/ResultTest.php + + - + message: '#^Cannot access offset ''name'' on array\{name\: string, passwd\: string, uid\: int, gid\: int, gecos\: string, dir\: string, shell\: string\}\|false\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: tests/Functional/ExceptionTest.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\Assert\:\:assertEquals\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 2 + path: tests/Functional/LegacyAPITest.php + + - + message: '#^Parameter \#1 \$mode of method Doctrine\\DBAL\\Result\:\:fetch\(\) expects 2\|3\|7, 1 given\.$#' + identifier: argument.type + count: 1 + path: tests/Functional/LegacyAPITest.php + + - + message: '#^Parameter \#1 \$mode of method Doctrine\\DBAL\\Result\:\:fetchAll\(\) expects 2\|3\|7, 1 given\.$#' + identifier: argument.type + count: 1 + path: tests/Functional/LegacyAPITest.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\Assert\:\:markTestSkipped\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 1 + path: tests/Functional/ModifyLimitQueryTest.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\Assert\:\:assertTrue\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 2 + path: tests/Functional/Platform/PlatformRestrictionsTest.php + + - + message: '#^Offset ''replica'' might not exist on array\{application_name\?\: string, charset\?\: string, dbname\?\: string, defaultTableOptions\?\: array\, default_dbname\?\: string, driver\?\: ''ibm_db2''\|''mysqli''\|''oci8''\|''pdo_mysql''\|''pdo_oci''\|''pdo_pgsql''\|''pdo_sqlite''\|''pdo_sqlsrv''\|''pgsql''\|''sqlite3''\|''sqlsrv'', driverClass\?\: class\-string\, driverOptions\?\: array\, \.\.\.\}\.$#' + identifier: offsetAccess.notFound + count: 1 + path: tests/Functional/PrimaryReadReplicaConnectionTest.php + + - + message: '#^Instanceof between Doctrine\\DBAL\\Platforms\\MariaDBPlatform and Doctrine\\DBAL\\Platforms\\MariaDb1010Platform will always evaluate to false\.$#' + identifier: instanceof.alwaysFalse + count: 1 + path: tests/Functional/Query/QueryBuilderTest.php + + - + message: '#^PHPDoc tag @param for parameter \$expectedDefault with type mixed is not subtype of native type string\|null\.$#' + identifier: parameter.phpDocType + count: 2 + path: tests/Functional/Schema/DefaultValueTest.php + + - + message: '#^Only numeric types are allowed in \+, int\|null given on the left side\.$#' + identifier: plus.leftNonNumeric + count: 1 + path: tests/Functional/Schema/MySQL/ComparatorTest.php + + - + message: '#^Call to function array_filter\(\) requires parameter \#2 to be passed to avoid loose comparison semantics\.$#' + identifier: arrayFilter.strict + count: 1 + path: tests/Functional/Schema/MySQL/JsonCollationTest.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\Assert\:\:assertTrue\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 3 + path: tests/Functional/Schema/MySQL/JsonCollationTest.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\Assert\:\:assertEquals\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 1 + path: tests/Functional/Schema/PostgreSQL/SchemaTest.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\Assert\:\:assertNotFalse\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 1 + path: tests/Functional/Schema/PostgreSQL/SchemaTest.php + + - + message: '#^Call to static method PHPUnit\\Framework\\Assert\:\:assertTrue\(\) with true and mixed will always evaluate to true\.$#' + identifier: staticMethod.alreadyNarrowedType + count: 2 + path: tests/Functional/Schema/PostgreSQLSchemaManagerTest.php + + - + message: '#^Cannot call method getForeignTableName\(\) on Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\|null\.$#' + identifier: method.nonObject + count: 1 + path: tests/Functional/Schema/PostgreSQLSchemaManagerTest.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\Assert\:\:assertArrayHasKey\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 2 + path: tests/Functional/Schema/PostgreSQLSchemaManagerTest.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\Assert\:\:assertCount\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 2 + path: tests/Functional/Schema/PostgreSQLSchemaManagerTest.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\Assert\:\:assertInstanceOf\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 2 + path: tests/Functional/Schema/PostgreSQLSchemaManagerTest.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\Assert\:\:assertTrue\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 4 + path: tests/Functional/Schema/PostgreSQLSchemaManagerTest.php + + - + message: '#^Cannot call method getColumns\(\) on Doctrine\\DBAL\\Schema\\Index\|false\.$#' + identifier: method.nonObject + count: 1 + path: tests/Functional/Schema/SQLServerSchemaManagerTest.php + + - + message: '#^Call to method Doctrine\\DBAL\\Schema\\AbstractAsset\:\:getName\(\) with incorrect case\: getname$#' + identifier: method.nameCase + count: 6 + path: tests/Functional/Schema/SchemaManagerFunctionalTestCase.php + + - + message: '#^Call to method Doctrine\\DBAL\\Schema\\Column\:\:getDefault\(\) with incorrect case\: getdefault$#' + identifier: method.nameCase + count: 6 + path: tests/Functional/Schema/SchemaManagerFunctionalTestCase.php + + - + message: '#^Call to method Doctrine\\DBAL\\Schema\\Column\:\:getFixed\(\) with incorrect case\: getfixed$#' + identifier: method.nameCase + count: 3 + path: tests/Functional/Schema/SchemaManagerFunctionalTestCase.php + + - + message: '#^Call to method Doctrine\\DBAL\\Schema\\Column\:\:getLength\(\) with incorrect case\: getlength$#' + identifier: method.nameCase + count: 2 + path: tests/Functional/Schema/SchemaManagerFunctionalTestCase.php + + - + message: '#^Call to method Doctrine\\DBAL\\Schema\\Column\:\:getNotnull\(\) with incorrect case\: getnotnull$#' + identifier: method.nameCase + count: 6 + path: tests/Functional/Schema/SchemaManagerFunctionalTestCase.php + + - + message: '#^Call to method Doctrine\\DBAL\\Schema\\Column\:\:getPrecision\(\) with incorrect case\: getprecision$#' + identifier: method.nameCase + count: 1 + path: tests/Functional/Schema/SchemaManagerFunctionalTestCase.php + + - + message: '#^Call to method Doctrine\\DBAL\\Schema\\Column\:\:getScale\(\) with incorrect case\: getscale$#' + identifier: method.nameCase + count: 1 + path: tests/Functional/Schema/SchemaManagerFunctionalTestCase.php + + - + message: '#^Call to method Doctrine\\DBAL\\Schema\\Column\:\:getType\(\) with incorrect case\: gettype$#' + identifier: method.nameCase + count: 6 + path: tests/Functional/Schema/SchemaManagerFunctionalTestCase.php + + - + message: '#^Call to method Doctrine\\DBAL\\Schema\\Column\:\:getUnsigned\(\) with incorrect case\: getunsigned$#' + identifier: method.nameCase + count: 2 + path: tests/Functional/Schema/SchemaManagerFunctionalTestCase.php + + - + message: '#^Cannot call method getColumns\(\) on Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\|false\.$#' + identifier: method.nonObject + count: 2 + path: tests/Functional/Schema/SchemaManagerFunctionalTestCase.php + + - + message: '#^Cannot call method getForeignColumns\(\) on Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\|false\.$#' + identifier: method.nonObject + count: 1 + path: tests/Functional/Schema/SchemaManagerFunctionalTestCase.php + + - + message: '#^Cannot call method getForeignTableName\(\) on Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\|false\.$#' + identifier: method.nonObject + count: 1 + path: tests/Functional/Schema/SchemaManagerFunctionalTestCase.php + + - + message: '#^Cannot call method getName\(\) on Doctrine\\DBAL\\Schema\\Index\|false\.$#' + identifier: method.nonObject + count: 1 + path: tests/Functional/Schema/SchemaManagerFunctionalTestCase.php + + - + message: '#^Cannot call method isUnique\(\) on Doctrine\\DBAL\\Schema\\Index\|false\.$#' + identifier: method.nonObject + count: 1 + path: tests/Functional/Schema/SchemaManagerFunctionalTestCase.php + + - + message: '#^Cannot call method getForeignColumns\(\) on Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\|null\.$#' + identifier: method.nonObject + count: 5 + path: tests/Functional/Schema/SqliteSchemaManagerTest.php + + - + message: '#^Cannot call method getForeignTableName\(\) on Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\|null\.$#' + identifier: method.nonObject + count: 1 + path: tests/Functional/Schema/SqliteSchemaManagerTest.php + + - + message: '#^Cannot call method getLocalColumns\(\) on Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\|null\.$#' + identifier: method.nonObject + count: 5 + path: tests/Functional/Schema/SqliteSchemaManagerTest.php + + - + message: '#^Cannot call method getName\(\) on Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\|null\.$#' + identifier: method.nonObject + count: 4 + path: tests/Functional/Schema/SqliteSchemaManagerTest.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\Assert\:\:assertEquals\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 2 + path: tests/Functional/StatementTest.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\Assert\:\:markTestSkipped\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 1 + path: tests/Functional/TransactionTest.php + + - + message: '#^Method Doctrine\\DBAL\\Tests\\Functional\\Types\\JsonTest\:\:insert\(\) has parameter \$value with no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: tests/Functional/Types/JsonTest.php + + - + message: '#^Method Doctrine\\DBAL\\Tests\\Functional\\Types\\JsonTest\:\:select\(\) return type has no value type specified in iterable type array\.$#' + identifier: missingType.iterableValue + count: 1 + path: tests/Functional/Types/JsonTest.php + + - + message: '#^Method PHPUnit\\Framework\\MockObject\\Builder\\InvocationMocker\:\:with\(\) invoked with unpacked array with possibly string key, but it''s not allowed because of @no\-named\-arguments\.$#' + identifier: argument.named + count: 1 + path: tests/Logging/LoggerChainTest.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\Assert\:\:assertStringEndsNotWith\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 1 + path: tests/Platforms/AbstractPlatformTestCase.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\Assert\:\:markTestSkipped\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 1 + path: tests/Platforms/AbstractPlatformTestCase.php + + - + message: '#^Parameter \#1 \$value1 of method Doctrine\\DBAL\\Platforms\\AbstractPlatform\:\:getBitAndComparisonExpression\(\) expects string, int given\.$#' + identifier: argument.type + count: 1 + path: tests/Platforms/AbstractPlatformTestCase.php + + - + message: '#^Parameter \#1 \$value1 of method Doctrine\\DBAL\\Platforms\\AbstractPlatform\:\:getBitOrComparisonExpression\(\) expects string, int given\.$#' + identifier: argument.type + count: 1 + path: tests/Platforms/AbstractPlatformTestCase.php + + - + message: '#^Parameter \#1 \$value1 of method Doctrine\\DBAL\\Tests\\Platforms\\AbstractPlatformTestCase\\:\:getBitAndComparisonExpressionSql\(\) expects string, int given\.$#' + identifier: argument.type + count: 1 + path: tests/Platforms/AbstractPlatformTestCase.php + + - + message: '#^Parameter \#1 \$value1 of method Doctrine\\DBAL\\Tests\\Platforms\\AbstractPlatformTestCase\\:\:getBitOrComparisonExpressionSql\(\) expects string, int given\.$#' + identifier: argument.type + count: 1 + path: tests/Platforms/AbstractPlatformTestCase.php + + - + message: '#^Parameter \#2 \$limit of method Doctrine\\DBAL\\Platforms\\AbstractPlatform\:\:modifyLimitQuery\(\) expects int\|null, string given\.$#' + identifier: argument.type + count: 1 + path: tests/Platforms/AbstractPlatformTestCase.php + + - + message: '#^Parameter \#2 \$lockMode of method Doctrine\\DBAL\\Platforms\\AbstractPlatform\:\:appendLockHint\(\) expects 0\|1\|2\|4, 128 given\.$#' + identifier: argument.type + count: 1 + path: tests/Platforms/AbstractPlatformTestCase.php + + - + message: '#^Parameter \#2 \$value2 of method Doctrine\\DBAL\\Platforms\\AbstractPlatform\:\:getBitAndComparisonExpression\(\) expects string, int given\.$#' + identifier: argument.type + count: 1 + path: tests/Platforms/AbstractPlatformTestCase.php + + - + message: '#^Parameter \#2 \$value2 of method Doctrine\\DBAL\\Platforms\\AbstractPlatform\:\:getBitOrComparisonExpression\(\) expects string, int given\.$#' + identifier: argument.type + count: 1 + path: tests/Platforms/AbstractPlatformTestCase.php + + - + message: '#^Parameter \#2 \$value2 of method Doctrine\\DBAL\\Tests\\Platforms\\AbstractPlatformTestCase\\:\:getBitAndComparisonExpressionSql\(\) expects string, int given\.$#' + identifier: argument.type + count: 1 + path: tests/Platforms/AbstractPlatformTestCase.php + + - + message: '#^Parameter \#2 \$value2 of method Doctrine\\DBAL\\Tests\\Platforms\\AbstractPlatformTestCase\\:\:getBitOrComparisonExpressionSql\(\) expects string, int given\.$#' + identifier: argument.type + count: 1 + path: tests/Platforms/AbstractPlatformTestCase.php + + - + message: '#^Parameter \#3 \$offset of method Doctrine\\DBAL\\Platforms\\AbstractPlatform\:\:modifyLimitQuery\(\) expects int, string given\.$#' + identifier: argument.type + count: 1 + path: tests/Platforms/AbstractPlatformTestCase.php + + - + message: '#^Cannot access offset ''boolean'' on iterable\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: tests/Platforms/DB2PlatformTest.php + + - + message: '#^Method Doctrine\\DBAL\\Tests\\Platforms\\DB2PlatformTest\:\:getIsCommentedDoctrineType\(\) should return array\ but returns array\\|\(ArrayAccess&iterable\)\.$#' + identifier: return.type + count: 1 + path: tests/Platforms/DB2PlatformTest.php + + - + message: '#^Parameter \#3 \$message of static method PHPUnit\\Framework\\Assert\:\:assertEquals\(\) expects string, true given\.$#' + identifier: argument.type + count: 1 + path: tests/Platforms/DB2PlatformTest.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\Assert\:\:assertTrue\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 1 + path: tests/Platforms/MySQL/MariaDbJsonComparatorTest.php + + - + message: '#^Dynamic call to static method Doctrine\\DBAL\\Platforms\\OraclePlatform\:\:assertValidIdentifier\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 2 + path: tests/Platforms/OraclePlatformTest.php + + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: tests/Platforms/PostgreSQLPlatformTest.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\Assert\:\:markTestSkipped\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 1 + path: tests/Platforms/SqlitePlatformTest.php + + - + message: '#^PHPDoc tag @return contains unresolvable type\.$#' + identifier: return.unresolvableType + count: 1 + path: tests/Portability/StatementTest.php + + - + message: '#^Return type of call to method PHPUnit\\Framework\\MockObject\\MockBuilder\\:\:getMock\(\) contains unresolvable type\.$#' + identifier: method.unresolvableReturnType + count: 1 + path: tests/Portability/StatementTest.php + + - + message: '#^Parameter \#2 \$y of method Doctrine\\DBAL\\Query\\Expression\\ExpressionBuilder\:\:in\(\) expects array\\|string, array\ given\.$#' + identifier: argument.type + count: 1 + path: tests/Query/Expression/ExpressionBuilderTest.php + + - + message: '#^Parameter \#2 \$y of method Doctrine\\DBAL\\Query\\Expression\\ExpressionBuilder\:\:notIn\(\) expects array\\|string, array\ given\.$#' + identifier: argument.type + count: 1 + path: tests/Query/Expression/ExpressionBuilderTest.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\TestCase\:\:any\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 1 + path: tests/Query/QueryBuilderTest.php + + - + message: '#^Parameter \#1 \$precision of method Doctrine\\DBAL\\Schema\\Column\:\:setPrecision\(\) expects int, null given\.$#' + identifier: argument.type + count: 1 + path: tests/Schema/AbstractComparatorTestCase.php + + - + message: '#^Static call to instance method Doctrine\\DBAL\\Schema\\Comparator\:\:compareSchemas\(\)\.$#' + identifier: method.staticCall + count: 1 + path: tests/Schema/AbstractComparatorTestCase.php + + - + message: '#^Cannot call method getName\(\) on Doctrine\\DBAL\\Schema\\Index\|false\.$#' + identifier: method.nonObject + count: 1 + path: tests/Schema/SchemaTest.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\TestCase\:\:exactly\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 3 + path: tests/Schema/SchemaTest.php + + - + message: '#^Parameter \#1 \$class of class ReflectionProperty constructor expects object\|string, Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\|false given\.$#' + identifier: argument.type + count: 1 + path: tests/Schema/SchemaTest.php + + - + message: '#^Parameter \#1 \$object of method ReflectionProperty\:\:getValue\(\) expects object\|null, Doctrine\\DBAL\\Schema\\ForeignKeyConstraint\|false given\.$#' + identifier: argument.type + count: 1 + path: tests/Schema/SchemaTest.php + + - + message: '#^Cannot call method getColumns\(\) on Doctrine\\DBAL\\Schema\\Index\|false\.$#' + identifier: method.nonObject + count: 1 + path: tests/Schema/TableTest.php + + - + message: '#^Cannot call method getName\(\) on Doctrine\\DBAL\\Schema\\Index\|false\.$#' + identifier: method.nonObject + count: 2 + path: tests/Schema/TableTest.php + + - + message: '#^Dynamic call to static method PHPUnit\\Framework\\TestCase\:\:any\(\)\.$#' + identifier: staticMethod.dynamicCall + count: 1 + path: tests/Schema/Visitor/CreateSchemaSqlCollectorTest.php diff --git a/app/vendor/doctrine/dbal/src/ArrayParameterType.php b/app/vendor/doctrine/dbal/src/ArrayParameterType.php index 65e1a29c2..d78cd5f16 100644 --- a/app/vendor/doctrine/dbal/src/ArrayParameterType.php +++ b/app/vendor/doctrine/dbal/src/ArrayParameterType.php @@ -27,9 +27,9 @@ final class ArrayParameterType /** * @internal * - * @psalm-param self::* $type + * @phpstan-param self::* $type * - * @psalm-return ParameterType::INTEGER|ParameterType::STRING|ParameterType::ASCII|ParameterType::BINARY + * @phpstan-return ParameterType::INTEGER|ParameterType::STRING|ParameterType::ASCII|ParameterType::BINARY */ public static function toElementParameterType(int $type): int { diff --git a/app/vendor/doctrine/dbal/src/ArrayParameters/Exception/MissingNamedParameter.php b/app/vendor/doctrine/dbal/src/ArrayParameters/Exception/MissingNamedParameter.php index cd9b9756a..8fd40a357 100644 --- a/app/vendor/doctrine/dbal/src/ArrayParameters/Exception/MissingNamedParameter.php +++ b/app/vendor/doctrine/dbal/src/ArrayParameters/Exception/MissingNamedParameter.php @@ -7,7 +7,6 @@ use function sprintf; -/** @psalm-immutable */ class MissingNamedParameter extends LogicException implements Exception { public static function new(string $name): self diff --git a/app/vendor/doctrine/dbal/src/ArrayParameters/Exception/MissingPositionalParameter.php b/app/vendor/doctrine/dbal/src/ArrayParameters/Exception/MissingPositionalParameter.php index f89a98b79..2cd311491 100644 --- a/app/vendor/doctrine/dbal/src/ArrayParameters/Exception/MissingPositionalParameter.php +++ b/app/vendor/doctrine/dbal/src/ArrayParameters/Exception/MissingPositionalParameter.php @@ -7,11 +7,7 @@ use function sprintf; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ class MissingPositionalParameter extends LogicException implements Exception { public static function new(int $index): self diff --git a/app/vendor/doctrine/dbal/src/Cache/CacheException.php b/app/vendor/doctrine/dbal/src/Cache/CacheException.php index 18e95d6be..fd10fd5d8 100644 --- a/app/vendor/doctrine/dbal/src/Cache/CacheException.php +++ b/app/vendor/doctrine/dbal/src/Cache/CacheException.php @@ -4,7 +4,6 @@ use Doctrine\DBAL\Exception; -/** @psalm-immutable */ class CacheException extends Exception { /** @return CacheException */ diff --git a/app/vendor/doctrine/dbal/src/Cache/QueryCacheProfile.php b/app/vendor/doctrine/dbal/src/Cache/QueryCacheProfile.php index 1601a9828..71d5b04c4 100644 --- a/app/vendor/doctrine/dbal/src/Cache/QueryCacheProfile.php +++ b/app/vendor/doctrine/dbal/src/Cache/QueryCacheProfile.php @@ -8,8 +8,10 @@ use Doctrine\DBAL\Types\Type; use Doctrine\Deprecations\Deprecation; use Psr\Cache\CacheItemPoolInterface; +use RuntimeException; use TypeError; +use function class_exists; use function get_class; use function hash; use function serialize; @@ -82,7 +84,19 @@ public function getResultCacheDriver() __METHOD__, ); - return $this->resultCache !== null ? DoctrineProvider::wrap($this->resultCache) : null; + if ($this->resultCache === null) { + return null; + } + + if (! class_exists(DoctrineProvider::class)) { + throw new RuntimeException(sprintf( + 'Calling %s() is not supported if the doctrine/cache package is not installed. ' + . 'Try running "composer require doctrine/cache" or migrate cache access to PSR-6.', + __METHOD__, + )); + } + + return DoctrineProvider::wrap($this->resultCache); } /** @return int */ diff --git a/app/vendor/doctrine/dbal/src/Configuration.php b/app/vendor/doctrine/dbal/src/Configuration.php index 5cdae8135..106eccae8 100644 --- a/app/vendor/doctrine/dbal/src/Configuration.php +++ b/app/vendor/doctrine/dbal/src/Configuration.php @@ -10,8 +10,12 @@ use Doctrine\DBAL\Schema\SchemaManagerFactory; use Doctrine\Deprecations\Deprecation; use Psr\Cache\CacheItemPoolInterface; +use RuntimeException; +use function class_exists; use function func_num_args; +use function interface_exists; +use function sprintf; /** * Configuration container for the Doctrine DBAL. @@ -129,6 +133,14 @@ public function getResultCacheImpl(): ?Cache __METHOD__, ); + if ($this->resultCache !== null && ! interface_exists(Cache::class)) { + throw new RuntimeException(sprintf( + 'Calling %s() is not supported if the doctrine/cache package is not installed. ' + . 'Try running "composer require doctrine/cache" or migrate cache access to PSR-6.', + __METHOD__, + )); + } + return $this->resultCacheImpl; } @@ -137,8 +149,11 @@ public function getResultCacheImpl(): ?Cache */ public function setResultCache(CacheItemPoolInterface $cache): void { - $this->resultCacheImpl = DoctrineProvider::wrap($cache); - $this->resultCache = $cache; + if (class_exists(DoctrineProvider::class)) { + $this->resultCacheImpl = DoctrineProvider::wrap($cache); + } + + $this->resultCache = $cache; } /** diff --git a/app/vendor/doctrine/dbal/src/Connection.php b/app/vendor/doctrine/dbal/src/Connection.php index 76b427b5b..2902429f4 100644 --- a/app/vendor/doctrine/dbal/src/Connection.php +++ b/app/vendor/doctrine/dbal/src/Connection.php @@ -9,14 +9,19 @@ use Doctrine\DBAL\Cache\QueryCacheProfile; use Doctrine\DBAL\Driver\API\ExceptionConverter; use Doctrine\DBAL\Driver\Connection as DriverConnection; +use Doctrine\DBAL\Driver\Exception as TheDriverException; use Doctrine\DBAL\Driver\ServerInfoAwareConnection; use Doctrine\DBAL\Driver\Statement as DriverStatement; use Doctrine\DBAL\Event\TransactionBeginEventArgs; use Doctrine\DBAL\Event\TransactionCommitEventArgs; use Doctrine\DBAL\Event\TransactionRollBackEventArgs; use Doctrine\DBAL\Exception\ConnectionLost; +use Doctrine\DBAL\Exception\DeadlockException; use Doctrine\DBAL\Exception\DriverException; +use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException; use Doctrine\DBAL\Exception\InvalidArgumentException; +use Doctrine\DBAL\Exception\TransactionRolledBack; +use Doctrine\DBAL\Exception\UniqueConstraintViolationException; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Query\Expression\ExpressionBuilder; use Doctrine\DBAL\Query\QueryBuilder; @@ -48,8 +53,8 @@ * A database abstraction-level connection that implements features like events, transaction isolation levels, * configuration, emulated transaction nesting, lazy connecting and more. * - * @psalm-import-type Params from DriverManager - * @psalm-consistent-constructor + * @phpstan-import-type Params from DriverManager + * @phpstan-consistent-constructor */ class Connection { @@ -131,7 +136,7 @@ class Connection * The parameters used during creation of the Connection instance. * * @var array - * @psalm-var Params + * @phpstan-var Params */ private array $params; @@ -175,7 +180,7 @@ class Connection * @param Driver $driver The driver to use. * @param Configuration|null $config The configuration, optional. * @param EventManager|null $eventManager The event manager, optional. - * @psalm-param Params $params + * @phpstan-param Params $params * * @throws Exception */ @@ -239,7 +244,7 @@ public function __construct( * @internal * * @return array - * @psalm-return Params + * @phpstan-return Params */ public function getParams() { @@ -360,7 +365,7 @@ public function getExpressionBuilder() * * @throws Exception * - * @psalm-assert !null $this->_conn + * @phpstan-assert !null $this->_conn */ public function connect() { @@ -1278,16 +1283,41 @@ public function lastInsertId($name = null) public function transactional(Closure $func) { $this->beginTransaction(); + + $successful = false; + try { $res = $func($this); + + $successful = true; + } finally { + if (! $successful) { + $this->rollBack(); + } + } + + $shouldRollback = true; + try { $this->commit(); - return $res; - } catch (Throwable $e) { - $this->rollBack(); + $shouldRollback = false; + } catch (TheDriverException $t) { + $convertedException = $this->handleDriverException($t, null); + $shouldRollback = ! ( + $convertedException instanceof TransactionRolledBack + || $convertedException instanceof UniqueConstraintViolationException + || $convertedException instanceof ForeignKeyConstraintViolationException + || $convertedException instanceof DeadlockException + ); - throw $e; + throw $t; + } finally { + if ($shouldRollback) { + $this->rollBack(); + } } + + return $res; } /** @@ -1317,10 +1347,6 @@ public function setNestTransactionsWithSavepoints($nestTransactionsWithSavepoint throw ConnectionException::mayNotAlterNestedTransactionWithSavepointsInTransaction(); } - if (! $this->getDatabasePlatform()->supportsSavepoints()) { - throw ConnectionException::savepointsNotSupported(); - } - $this->nestTransactionsWithSavepoints = (bool) $nestTransactionsWithSavepoints; } @@ -1423,12 +1449,21 @@ public function commit() $connection = $this->getWrappedConnection(); - if ($this->transactionNestingLevel === 1) { - $result = $this->doCommit($connection); - } elseif ($this->nestTransactionsWithSavepoints) { - $this->releaseSavepoint($this->_getNestedTransactionSavePointName()); + try { + if ($this->transactionNestingLevel === 1) { + $result = $this->doCommit($connection); + } elseif ($this->nestTransactionsWithSavepoints) { + $this->releaseSavepoint($this->_getNestedTransactionSavePointName()); + } + } finally { + $this->updateTransactionStateAfterCommit(); } + return $result; + } + + private function updateTransactionStateAfterCommit(): void + { --$this->transactionNestingLevel; $eventManager = $this->getEventManager(); @@ -1445,12 +1480,10 @@ public function commit() } if ($this->autoCommit !== false || $this->transactionNestingLevel !== 0) { - return $result; + return; } $this->beginTransaction(); - - return $result; } /** diff --git a/app/vendor/doctrine/dbal/src/ConnectionException.php b/app/vendor/doctrine/dbal/src/ConnectionException.php index f1e18987b..49d9efe41 100644 --- a/app/vendor/doctrine/dbal/src/ConnectionException.php +++ b/app/vendor/doctrine/dbal/src/ConnectionException.php @@ -2,7 +2,6 @@ namespace Doctrine\DBAL; -/** @psalm-immutable */ class ConnectionException extends Exception { /** @return ConnectionException */ diff --git a/app/vendor/doctrine/dbal/src/Connections/PrimaryReadReplicaConnection.php b/app/vendor/doctrine/dbal/src/Connections/PrimaryReadReplicaConnection.php index 2617fb802..0a6d13744 100644 --- a/app/vendor/doctrine/dbal/src/Connections/PrimaryReadReplicaConnection.php +++ b/app/vendor/doctrine/dbal/src/Connections/PrimaryReadReplicaConnection.php @@ -59,7 +59,7 @@ * * Instantiation through the DriverManager looks like: * - * @psalm-import-type Params from DriverManager + * @phpstan-import-type Params from DriverManager * @example * * $conn = DriverManager::getConnection(array( @@ -98,7 +98,7 @@ class PrimaryReadReplicaConnection extends Connection * @internal The connection can be only instantiated by the driver manager. * * @param array $params - * @psalm-param Params $params + * @phpstan-param Params $params * * @throws Exception * @throws InvalidArgumentException diff --git a/app/vendor/doctrine/dbal/src/Driver.php b/app/vendor/doctrine/dbal/src/Driver.php index 46e422ba9..a376f069b 100644 --- a/app/vendor/doctrine/dbal/src/Driver.php +++ b/app/vendor/doctrine/dbal/src/Driver.php @@ -13,7 +13,7 @@ * Driver interface. * Interface that all DBAL drivers must implement. * - * @psalm-import-type Params from DriverManager + * @phpstan-import-type Params from DriverManager */ interface Driver { @@ -21,7 +21,7 @@ interface Driver * Attempts to create a connection with the database. * * @param array $params All connection parameters. - * @psalm-param Params $params All connection parameters. + * @phpstan-param Params $params All connection parameters. * * @return DriverConnection The database connection. * diff --git a/app/vendor/doctrine/dbal/src/Driver/API/MySQL/ExceptionConverter.php b/app/vendor/doctrine/dbal/src/Driver/API/MySQL/ExceptionConverter.php index 87d50aff9..fdfc75a77 100644 --- a/app/vendor/doctrine/dbal/src/Driver/API/MySQL/ExceptionConverter.php +++ b/app/vendor/doctrine/dbal/src/Driver/API/MySQL/ExceptionConverter.php @@ -101,6 +101,7 @@ public function convert(Exception $exception, ?Query $query): DriverException return new ConnectionException($exception, $query); case 2006: + case 4031: return new ConnectionLost($exception, $query); case 1048: diff --git a/app/vendor/doctrine/dbal/src/Driver/API/OCI/ExceptionConverter.php b/app/vendor/doctrine/dbal/src/Driver/API/OCI/ExceptionConverter.php index 4703a57d5..62a08a799 100644 --- a/app/vendor/doctrine/dbal/src/Driver/API/OCI/ExceptionConverter.php +++ b/app/vendor/doctrine/dbal/src/Driver/API/OCI/ExceptionConverter.php @@ -6,6 +6,8 @@ use Doctrine\DBAL\Driver\API\ExceptionConverter as ExceptionConverterInterface; use Doctrine\DBAL\Driver\Exception; +use Doctrine\DBAL\Driver\OCI8\Exception\Error; +use Doctrine\DBAL\Driver\PDO\PDOException; use Doctrine\DBAL\Exception\ConnectionException; use Doctrine\DBAL\Exception\DatabaseDoesNotExist; use Doctrine\DBAL\Exception\DatabaseObjectNotFoundException; @@ -17,16 +19,30 @@ use Doctrine\DBAL\Exception\SyntaxErrorException; use Doctrine\DBAL\Exception\TableExistsException; use Doctrine\DBAL\Exception\TableNotFoundException; +use Doctrine\DBAL\Exception\TransactionRolledBack; use Doctrine\DBAL\Exception\UniqueConstraintViolationException; use Doctrine\DBAL\Query; +use function explode; +use function str_replace; + /** @internal */ final class ExceptionConverter implements ExceptionConverterInterface { /** @link http://www.dba-oracle.com/t_error_code_list.htm */ public function convert(Exception $exception, ?Query $query): DriverException { - switch ($exception->getCode()) { + /** @phpstan-var int|'HY000' $code */ // @phpstan-ignore varTag.type + $code = $exception->getCode(); + // @phpstan-ignore property.notFound, property.notFound + if ($code === 'HY000' && isset($exception->errorInfo[1], $exception->errorInfo[2])) { + $errorInfo = $exception->errorInfo; + $exception = new PDOException($errorInfo[2], $errorInfo[1]); + $exception->errorInfo = $errorInfo; + $code = $exception->getCode(); + } + + switch ($code) { case 1: case 2299: case 38911: @@ -58,6 +74,22 @@ public function convert(Exception $exception, ?Query $query): DriverException case 1918: return new DatabaseDoesNotExist($exception, $query); + case 2091: + //ORA-02091: transaction rolled back + //ORA-00001: unique constraint (DOCTRINE.GH3423_UNIQUE) violated + [, $causeError] = explode("\n", $exception->getMessage(), 2); + + [$causeCode] = explode(': ', $causeError, 2); + $code = (int) str_replace('ORA-', '', $causeCode); + + if ($exception instanceof PDOException) { + $why = $this->convert(new PDOException($causeError, $code, $exception), $query); + } else { + $why = $this->convert(new Error($causeError, null, $code, $exception), $query); + } + + return new TransactionRolledBack($why, $query); + case 2289: case 2443: case 4080: diff --git a/app/vendor/doctrine/dbal/src/Driver/AbstractDB2Driver.php b/app/vendor/doctrine/dbal/src/Driver/AbstractDB2Driver.php index 79efb8650..81d84328c 100644 --- a/app/vendor/doctrine/dbal/src/Driver/AbstractDB2Driver.php +++ b/app/vendor/doctrine/dbal/src/Driver/AbstractDB2Driver.php @@ -87,7 +87,7 @@ private function getVersionNumber(string $versionString): string '/^(?:[^\s]+\s)?(?P\d+)\.(?P\d+)\.(?P\d+)/i', $versionString, $versionParts, - ) === 0 + ) !== 1 ) { throw DBALException::invalidPlatformVersionSpecified( $versionString, diff --git a/app/vendor/doctrine/dbal/src/Driver/AbstractException.php b/app/vendor/doctrine/dbal/src/Driver/AbstractException.php index 389f82e70..9b7bff40f 100644 --- a/app/vendor/doctrine/dbal/src/Driver/AbstractException.php +++ b/app/vendor/doctrine/dbal/src/Driver/AbstractException.php @@ -11,8 +11,6 @@ * Base implementation of the {@see Exception} interface. * * @internal - * - * @psalm-immutable */ abstract class AbstractException extends BaseException implements Exception { diff --git a/app/vendor/doctrine/dbal/src/Driver/AbstractMySQLDriver.php b/app/vendor/doctrine/dbal/src/Driver/AbstractMySQLDriver.php index 83159a540..f8c3b3996 100644 --- a/app/vendor/doctrine/dbal/src/Driver/AbstractMySQLDriver.php +++ b/app/vendor/doctrine/dbal/src/Driver/AbstractMySQLDriver.php @@ -8,12 +8,14 @@ use Doctrine\DBAL\Exception; use Doctrine\DBAL\Platforms\AbstractMySQLPlatform; use Doctrine\DBAL\Platforms\AbstractPlatform; +use Doctrine\DBAL\Platforms\MariaDb1010Platform; use Doctrine\DBAL\Platforms\MariaDb1027Platform; use Doctrine\DBAL\Platforms\MariaDb1043Platform; use Doctrine\DBAL\Platforms\MariaDb1052Platform; use Doctrine\DBAL\Platforms\MariaDb1060Platform; use Doctrine\DBAL\Platforms\MySQL57Platform; use Doctrine\DBAL\Platforms\MySQL80Platform; +use Doctrine\DBAL\Platforms\MySQL84Platform; use Doctrine\DBAL\Platforms\MySQLPlatform; use Doctrine\DBAL\Schema\MySQLSchemaManager; use Doctrine\DBAL\VersionAwarePlatformDriver; @@ -40,6 +42,10 @@ public function createDatabasePlatformForVersion($version) if ($mariadb) { $mariaDbVersion = $this->getMariaDbMysqlVersionNumber($version); + if (version_compare($mariaDbVersion, '10.10.0', '>=')) { + return new MariaDb1010Platform(); + } + if (version_compare($mariaDbVersion, '10.6.0', '>=')) { return new MariaDb1060Platform(); } @@ -64,6 +70,20 @@ public function createDatabasePlatformForVersion($version) } } else { $oracleMysqlVersion = $this->getOracleMysqlVersionNumber($version); + + if (version_compare($oracleMysqlVersion, '8.4.0', '>=')) { + if (! version_compare($version, '8.4.0', '>=')) { + Deprecation::trigger( + 'doctrine/orm', + 'https://github.com/doctrine/dbal/pull/5779', + 'Version detection logic for MySQL will change in DBAL 4. ' + . 'Please specify the version as the server reports it, e.g. "8.4.0" instead of "8.4".', + ); + } + + return new MySQL84Platform(); + } + if (version_compare($oracleMysqlVersion, '8', '>=')) { if (! version_compare($version, '8.0.0', '>=')) { Deprecation::trigger( @@ -116,7 +136,7 @@ private function getOracleMysqlVersionNumber(string $versionString): string '/^(?P\d+)(?:\.(?P\d+)(?:\.(?P\d+))?)?/', $versionString, $versionParts, - ) === 0 + ) !== 1 ) { throw Exception::invalidPlatformVersionSpecified( $versionString, @@ -130,6 +150,8 @@ private function getOracleMysqlVersionNumber(string $versionString): string if ($majorVersion === '5' && $minorVersion === '7') { $patchVersion ??= '9'; + } else { + $patchVersion ??= '0'; } return $majorVersion . '.' . $minorVersion . '.' . $patchVersion; @@ -160,7 +182,7 @@ private function getMariaDbMysqlVersionNumber(string $versionString): string '/^(?:5\.5\.5-)?(mariadb-)?(?P\d+)\.(?P\d+)\.(?P\d+)/i', $versionString, $versionParts, - ) === 0 + ) !== 1 ) { throw Exception::invalidPlatformVersionSpecified( $versionString, diff --git a/app/vendor/doctrine/dbal/src/Driver/AbstractPostgreSQLDriver.php b/app/vendor/doctrine/dbal/src/Driver/AbstractPostgreSQLDriver.php index 099630d33..eba309daa 100644 --- a/app/vendor/doctrine/dbal/src/Driver/AbstractPostgreSQLDriver.php +++ b/app/vendor/doctrine/dbal/src/Driver/AbstractPostgreSQLDriver.php @@ -8,6 +8,7 @@ use Doctrine\DBAL\Exception; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\PostgreSQL100Platform; +use Doctrine\DBAL\Platforms\PostgreSQL120Platform; use Doctrine\DBAL\Platforms\PostgreSQL94Platform; use Doctrine\DBAL\Platforms\PostgreSQLPlatform; use Doctrine\DBAL\Schema\PostgreSQLSchemaManager; @@ -28,7 +29,7 @@ abstract class AbstractPostgreSQLDriver implements VersionAwarePlatformDriver */ public function createDatabasePlatformForVersion($version) { - if (preg_match('/^(?P\d+)(?:\.(?P\d+)(?:\.(?P\d+))?)?/', $version, $versionParts) === 0) { + if (preg_match('/^(?P\d+)(?:\.(?P\d+)(?:\.(?P\d+))?)?/', $version, $versionParts) !== 1) { throw Exception::invalidPlatformVersionSpecified( $version, '..', @@ -40,6 +41,10 @@ public function createDatabasePlatformForVersion($version) $patchVersion = $versionParts['patch'] ?? 0; $version = $majorVersion . '.' . $minorVersion . '.' . $patchVersion; + if (version_compare($version, '12.0', '>=')) { + return new PostgreSQL120Platform(); + } + if (version_compare($version, '10.0', '>=')) { return new PostgreSQL100Platform(); } diff --git a/app/vendor/doctrine/dbal/src/Driver/AbstractSQLServerDriver/Exception/PortWithoutHost.php b/app/vendor/doctrine/dbal/src/Driver/AbstractSQLServerDriver/Exception/PortWithoutHost.php index ea8dcc461..3b2665617 100644 --- a/app/vendor/doctrine/dbal/src/Driver/AbstractSQLServerDriver/Exception/PortWithoutHost.php +++ b/app/vendor/doctrine/dbal/src/Driver/AbstractSQLServerDriver/Exception/PortWithoutHost.php @@ -6,11 +6,7 @@ use Doctrine\DBAL\Driver\AbstractException; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class PortWithoutHost extends AbstractException { public static function new(): self diff --git a/app/vendor/doctrine/dbal/src/Driver/Exception.php b/app/vendor/doctrine/dbal/src/Driver/Exception.php index f963563b8..cf824a5f5 100644 --- a/app/vendor/doctrine/dbal/src/Driver/Exception.php +++ b/app/vendor/doctrine/dbal/src/Driver/Exception.php @@ -6,7 +6,6 @@ use Throwable; -/** @psalm-immutable */ interface Exception extends Throwable { /** diff --git a/app/vendor/doctrine/dbal/src/Driver/Exception/UnknownParameterType.php b/app/vendor/doctrine/dbal/src/Driver/Exception/UnknownParameterType.php index 01a9b3d0c..a7490cc7a 100644 --- a/app/vendor/doctrine/dbal/src/Driver/Exception/UnknownParameterType.php +++ b/app/vendor/doctrine/dbal/src/Driver/Exception/UnknownParameterType.php @@ -8,11 +8,7 @@ use function sprintf; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class UnknownParameterType extends AbstractException { /** @param mixed $type */ diff --git a/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/CannotCopyStreamToStream.php b/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/CannotCopyStreamToStream.php index 231c9d473..05099faf0 100644 --- a/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/CannotCopyStreamToStream.php +++ b/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/CannotCopyStreamToStream.php @@ -6,14 +6,10 @@ use Doctrine\DBAL\Driver\AbstractException; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class CannotCopyStreamToStream extends AbstractException { - /** @psalm-param array{message: string}|null $error */ + /** @param array{message: string}|null $error */ public static function new(?array $error): self { $message = 'Could not copy source stream to temporary file'; diff --git a/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/CannotCreateTemporaryFile.php b/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/CannotCreateTemporaryFile.php index 63f7ca1e2..70a355732 100644 --- a/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/CannotCreateTemporaryFile.php +++ b/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/CannotCreateTemporaryFile.php @@ -6,14 +6,10 @@ use Doctrine\DBAL\Driver\AbstractException; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class CannotCreateTemporaryFile extends AbstractException { - /** @psalm-param array{message: string}|null $error */ + /** @param array{message: string}|null $error */ public static function new(?array $error): self { $message = 'Could not create temporary file'; diff --git a/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/ConnectionError.php b/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/ConnectionError.php index b7bd8be69..c6c40b93f 100644 --- a/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/ConnectionError.php +++ b/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/ConnectionError.php @@ -9,11 +9,7 @@ use function db2_conn_error; use function db2_conn_errormsg; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class ConnectionError extends AbstractException { /** @param resource $connection */ diff --git a/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/ConnectionFailed.php b/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/ConnectionFailed.php index 9dd04434e..0826e5c92 100644 --- a/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/ConnectionFailed.php +++ b/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/ConnectionFailed.php @@ -9,11 +9,7 @@ use function db2_conn_error; use function db2_conn_errormsg; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class ConnectionFailed extends AbstractException { public static function new(): self diff --git a/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/Factory.php b/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/Factory.php index 91b9b439c..d2d30127e 100644 --- a/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/Factory.php +++ b/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/Factory.php @@ -8,11 +8,7 @@ use function preg_match; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class Factory { /** diff --git a/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/PrepareFailed.php b/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/PrepareFailed.php index 42df5e15c..95da1cdc3 100644 --- a/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/PrepareFailed.php +++ b/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/PrepareFailed.php @@ -6,14 +6,10 @@ use Doctrine\DBAL\Driver\AbstractException; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class PrepareFailed extends AbstractException { - /** @psalm-param array{message: string}|null $error */ + /** @param array{message: string}|null $error */ public static function new(?array $error): self { if ($error === null) { diff --git a/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/StatementError.php b/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/StatementError.php index 6bf851131..d4c0d0bd1 100644 --- a/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/StatementError.php +++ b/app/vendor/doctrine/dbal/src/Driver/IBMDB2/Exception/StatementError.php @@ -9,11 +9,7 @@ use function db2_stmt_error; use function db2_stmt_errormsg; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class StatementError extends AbstractException { /** @param resource|null $statement */ diff --git a/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/ConnectionError.php b/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/ConnectionError.php index ef5b98017..f5755932b 100644 --- a/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/ConnectionError.php +++ b/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/ConnectionError.php @@ -9,11 +9,7 @@ use mysqli_sql_exception; use ReflectionProperty; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class ConnectionError extends AbstractException { public static function new(mysqli $connection): self diff --git a/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/ConnectionFailed.php b/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/ConnectionFailed.php index 44a8cab99..051f141fd 100644 --- a/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/ConnectionFailed.php +++ b/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/ConnectionFailed.php @@ -11,11 +11,7 @@ use function assert; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class ConnectionFailed extends AbstractException { public static function new(mysqli $connection): self diff --git a/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/FailedReadingStreamOffset.php b/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/FailedReadingStreamOffset.php index 6f26dbec8..f20d8bc1d 100644 --- a/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/FailedReadingStreamOffset.php +++ b/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/FailedReadingStreamOffset.php @@ -8,11 +8,7 @@ use function sprintf; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class FailedReadingStreamOffset extends AbstractException { public static function new(int $parameter): self diff --git a/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/HostRequired.php b/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/HostRequired.php index d3359fcdf..644f3fd5e 100644 --- a/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/HostRequired.php +++ b/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/HostRequired.php @@ -6,11 +6,7 @@ use Doctrine\DBAL\Driver\AbstractException; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class HostRequired extends AbstractException { public static function forPersistentConnection(): self diff --git a/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/InvalidCharset.php b/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/InvalidCharset.php index 8c6bbb476..71a5bc60b 100644 --- a/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/InvalidCharset.php +++ b/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/InvalidCharset.php @@ -11,11 +11,7 @@ use function sprintf; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class InvalidCharset extends AbstractException { public static function fromCharset(mysqli $connection, string $charset): self diff --git a/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/InvalidOption.php b/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/InvalidOption.php index 6fb46316e..abbda01c0 100644 --- a/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/InvalidOption.php +++ b/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/InvalidOption.php @@ -8,11 +8,7 @@ use function sprintf; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class InvalidOption extends AbstractException { /** @param mixed $value */ diff --git a/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/NonStreamResourceUsedAsLargeObject.php b/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/NonStreamResourceUsedAsLargeObject.php index 566d63638..7b50de545 100644 --- a/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/NonStreamResourceUsedAsLargeObject.php +++ b/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/NonStreamResourceUsedAsLargeObject.php @@ -8,11 +8,7 @@ use function sprintf; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class NonStreamResourceUsedAsLargeObject extends AbstractException { public static function new(int $parameter): self diff --git a/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/StatementError.php b/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/StatementError.php index 78dc8556b..716e2cd24 100644 --- a/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/StatementError.php +++ b/app/vendor/doctrine/dbal/src/Driver/Mysqli/Exception/StatementError.php @@ -9,11 +9,7 @@ use mysqli_stmt; use ReflectionProperty; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class StatementError extends AbstractException { public static function new(mysqli_stmt $statement): self diff --git a/app/vendor/doctrine/dbal/src/Driver/Mysqli/Result.php b/app/vendor/doctrine/dbal/src/Driver/Mysqli/Result.php index c7dc65d1d..bfd558b4f 100644 --- a/app/vendor/doctrine/dbal/src/Driver/Mysqli/Result.php +++ b/app/vendor/doctrine/dbal/src/Driver/Mysqli/Result.php @@ -20,6 +20,15 @@ final class Result implements ResultInterface { private mysqli_stmt $statement; + /** + * Maintains a reference to the Statement that generated this result. This ensures that the lifetime of the + * Statement is managed in conjunction with its associated results, so they are destroyed together + * at the appropriate time {@see Statement::__destruct()}. + * + * @phpstan-ignore property.onlyWritten + */ + private ?Statement $statementReference = null; + /** * Whether the statement result has columns. The property should be used only after the result metadata * has been fetched ({@see $metadataFetched}). Otherwise, the property value is undetermined. @@ -42,9 +51,12 @@ final class Result implements ResultInterface * * @throws Exception */ - public function __construct(mysqli_stmt $statement) - { - $this->statement = $statement; + public function __construct( + mysqli_stmt $statement, + ?Statement $statementReference = null + ) { + $this->statement = $statement; + $this->statementReference = $statementReference; $meta = $statement->result_metadata(); diff --git a/app/vendor/doctrine/dbal/src/Driver/Mysqli/Statement.php b/app/vendor/doctrine/dbal/src/Driver/Mysqli/Statement.php index fec7c95c3..be555e3dd 100644 --- a/app/vendor/doctrine/dbal/src/Driver/Mysqli/Statement.php +++ b/app/vendor/doctrine/dbal/src/Driver/Mysqli/Statement.php @@ -61,12 +61,17 @@ public function __construct(mysqli_stmt $stmt) $this->boundValues = array_fill(1, $paramCount, null); } + public function __destruct() + { + @$this->stmt->close(); + } + /** * @deprecated Use {@see bindValue()} instead. * * {@inheritDoc} * - * @psalm-assert ParameterType::* $type + * @phpstan-assert ParameterType::* $type */ public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null): bool { @@ -101,7 +106,7 @@ public function bindParam($param, &$variable, $type = ParameterType::STRING, $le /** * {@inheritDoc} * - * @psalm-assert ParameterType::* $type + * @phpstan-assert ParameterType::* $type */ public function bindValue($param, $value, $type = ParameterType::STRING): bool { @@ -159,7 +164,7 @@ public function execute($params = null): ResultInterface throw StatementError::new($this->stmt); } - return new Result($this->stmt); + return new Result($this->stmt, $this); } /** diff --git a/app/vendor/doctrine/dbal/src/Driver/OCI8/Connection.php b/app/vendor/doctrine/dbal/src/Driver/OCI8/Connection.php index 72353fa31..155b2d1d3 100644 --- a/app/vendor/doctrine/dbal/src/Driver/OCI8/Connection.php +++ b/app/vendor/doctrine/dbal/src/Driver/OCI8/Connection.php @@ -142,7 +142,7 @@ public function beginTransaction(): bool public function commit(): bool { - if (! oci_commit($this->connection)) { + if (! @oci_commit($this->connection)) { throw Error::new($this->connection); } diff --git a/app/vendor/doctrine/dbal/src/Driver/OCI8/Exception/ConnectionFailed.php b/app/vendor/doctrine/dbal/src/Driver/OCI8/Exception/ConnectionFailed.php index cefe9a3ad..691d1e31f 100644 --- a/app/vendor/doctrine/dbal/src/Driver/OCI8/Exception/ConnectionFailed.php +++ b/app/vendor/doctrine/dbal/src/Driver/OCI8/Exception/ConnectionFailed.php @@ -9,11 +9,7 @@ use function assert; use function oci_error; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class ConnectionFailed extends AbstractException { public static function new(): self diff --git a/app/vendor/doctrine/dbal/src/Driver/OCI8/Exception/Error.php b/app/vendor/doctrine/dbal/src/Driver/OCI8/Exception/Error.php index 6abdf233c..9e627c77a 100644 --- a/app/vendor/doctrine/dbal/src/Driver/OCI8/Exception/Error.php +++ b/app/vendor/doctrine/dbal/src/Driver/OCI8/Exception/Error.php @@ -9,11 +9,7 @@ use function assert; use function oci_error; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class Error extends AbstractException { /** @param resource $resource */ diff --git a/app/vendor/doctrine/dbal/src/Driver/OCI8/Exception/InvalidConfiguration.php b/app/vendor/doctrine/dbal/src/Driver/OCI8/Exception/InvalidConfiguration.php index e9d2d0ebd..ef3bb29de 100644 --- a/app/vendor/doctrine/dbal/src/Driver/OCI8/Exception/InvalidConfiguration.php +++ b/app/vendor/doctrine/dbal/src/Driver/OCI8/Exception/InvalidConfiguration.php @@ -6,11 +6,7 @@ use Doctrine\DBAL\Driver\AbstractException; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class InvalidConfiguration extends AbstractException { public static function forPersistentAndExclusive(): self diff --git a/app/vendor/doctrine/dbal/src/Driver/OCI8/Exception/NonTerminatedStringLiteral.php b/app/vendor/doctrine/dbal/src/Driver/OCI8/Exception/NonTerminatedStringLiteral.php index 776728fbe..fab0b27a8 100644 --- a/app/vendor/doctrine/dbal/src/Driver/OCI8/Exception/NonTerminatedStringLiteral.php +++ b/app/vendor/doctrine/dbal/src/Driver/OCI8/Exception/NonTerminatedStringLiteral.php @@ -8,11 +8,7 @@ use function sprintf; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class NonTerminatedStringLiteral extends AbstractException { public static function new(int $offset): self diff --git a/app/vendor/doctrine/dbal/src/Driver/OCI8/Exception/SequenceDoesNotExist.php b/app/vendor/doctrine/dbal/src/Driver/OCI8/Exception/SequenceDoesNotExist.php index 5fa43caba..c31c35142 100644 --- a/app/vendor/doctrine/dbal/src/Driver/OCI8/Exception/SequenceDoesNotExist.php +++ b/app/vendor/doctrine/dbal/src/Driver/OCI8/Exception/SequenceDoesNotExist.php @@ -6,11 +6,7 @@ use Doctrine\DBAL\Driver\AbstractException; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class SequenceDoesNotExist extends AbstractException { public static function new(): self diff --git a/app/vendor/doctrine/dbal/src/Driver/OCI8/Exception/UnknownParameterIndex.php b/app/vendor/doctrine/dbal/src/Driver/OCI8/Exception/UnknownParameterIndex.php index 2cd3fe796..d39bb4547 100644 --- a/app/vendor/doctrine/dbal/src/Driver/OCI8/Exception/UnknownParameterIndex.php +++ b/app/vendor/doctrine/dbal/src/Driver/OCI8/Exception/UnknownParameterIndex.php @@ -8,11 +8,7 @@ use function sprintf; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class UnknownParameterIndex extends AbstractException { public static function new(int $index): self diff --git a/app/vendor/doctrine/dbal/src/Driver/OCI8/Middleware/InitializeSession.php b/app/vendor/doctrine/dbal/src/Driver/OCI8/Middleware/InitializeSession.php index 314a04a65..3a356fb31 100644 --- a/app/vendor/doctrine/dbal/src/Driver/OCI8/Middleware/InitializeSession.php +++ b/app/vendor/doctrine/dbal/src/Driver/OCI8/Middleware/InitializeSession.php @@ -26,7 +26,6 @@ public function connect( 'ALTER SESSION SET' . " NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'" . " NLS_TIME_FORMAT = 'HH24:MI:SS'" - . " NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'" . " NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS'" . " NLS_TIMESTAMP_TZ_FORMAT = 'YYYY-MM-DD HH24:MI:SS TZH:TZM'" . " NLS_NUMERIC_CHARACTERS = '.,'", diff --git a/app/vendor/doctrine/dbal/src/Driver/PDO/Connection.php b/app/vendor/doctrine/dbal/src/Driver/PDO/Connection.php index 290dcc2d2..4320879c8 100644 --- a/app/vendor/doctrine/dbal/src/Driver/PDO/Connection.php +++ b/app/vendor/doctrine/dbal/src/Driver/PDO/Connection.php @@ -82,7 +82,7 @@ public function query(string $sql): ResultInterface * * @throws UnknownParameterType * - * @psalm-assert ParameterType::* $type + * @phpstan-assert ParameterType::* $type */ public function quote($value, $type = ParameterType::STRING) { diff --git a/app/vendor/doctrine/dbal/src/Driver/PDO/Exception.php b/app/vendor/doctrine/dbal/src/Driver/PDO/Exception.php index fbb81253b..0c0d1554b 100644 --- a/app/vendor/doctrine/dbal/src/Driver/PDO/Exception.php +++ b/app/vendor/doctrine/dbal/src/Driver/PDO/Exception.php @@ -7,11 +7,7 @@ use Doctrine\DBAL\Driver\AbstractException; use PDOException; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class Exception extends AbstractException { public static function new(PDOException $exception): self diff --git a/app/vendor/doctrine/dbal/src/Driver/PDO/PDOException.php b/app/vendor/doctrine/dbal/src/Driver/PDO/PDOException.php index 6eefda40a..4b0b177d2 100644 --- a/app/vendor/doctrine/dbal/src/Driver/PDO/PDOException.php +++ b/app/vendor/doctrine/dbal/src/Driver/PDO/PDOException.php @@ -6,11 +6,7 @@ use Doctrine\DBAL\Driver\Exception as DriverException; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class PDOException extends \PDOException implements DriverException { private ?string $sqlState = null; diff --git a/app/vendor/doctrine/dbal/src/Driver/PDO/ParameterTypeMap.php b/app/vendor/doctrine/dbal/src/Driver/PDO/ParameterTypeMap.php index f17b585f7..af705b032 100644 --- a/app/vendor/doctrine/dbal/src/Driver/PDO/ParameterTypeMap.php +++ b/app/vendor/doctrine/dbal/src/Driver/PDO/ParameterTypeMap.php @@ -24,11 +24,11 @@ final class ParameterTypeMap /** * Converts DBAL parameter type to PDO parameter type * - * @psalm-return PDO::PARAM_* + * @phpstan-return PDO::PARAM_* * * @throws UnknownParameterType * - * @psalm-assert ParameterType::* $type + * @phpstan-assert ParameterType::* $type */ public static function convertParamType(int $type): int { diff --git a/app/vendor/doctrine/dbal/src/Driver/PDO/PgSQL/Driver.php b/app/vendor/doctrine/dbal/src/Driver/PDO/PgSQL/Driver.php index 1c586d69d..5bfcd730c 100644 --- a/app/vendor/doctrine/dbal/src/Driver/PDO/PgSQL/Driver.php +++ b/app/vendor/doctrine/dbal/src/Driver/PDO/PgSQL/Driver.php @@ -126,6 +126,10 @@ private function constructPdoDsn(array $params): string $dsn .= 'application_name=' . $params['application_name'] . ';'; } + if (isset($params['gssencmode'])) { + $dsn .= 'gssencmode=' . $params['gssencmode'] . ';'; + } + return $dsn; } } diff --git a/app/vendor/doctrine/dbal/src/Driver/PDO/Result.php b/app/vendor/doctrine/dbal/src/Driver/PDO/Result.php index 67970ac56..506fdd4a9 100644 --- a/app/vendor/doctrine/dbal/src/Driver/PDO/Result.php +++ b/app/vendor/doctrine/dbal/src/Driver/PDO/Result.php @@ -91,7 +91,7 @@ public function free(): void } /** - * @psalm-param PDO::FETCH_* $mode + * @phpstan-param PDO::FETCH_* $mode * * @return mixed * @@ -107,7 +107,7 @@ private function fetch(int $mode) } /** - * @psalm-param PDO::FETCH_* $mode + * @phpstan-param PDO::FETCH_* $mode * * @return list * diff --git a/app/vendor/doctrine/dbal/src/Driver/PDO/SQLSrv/Statement.php b/app/vendor/doctrine/dbal/src/Driver/PDO/SQLSrv/Statement.php index cb2dfaedb..a63ff79d7 100644 --- a/app/vendor/doctrine/dbal/src/Driver/PDO/SQLSrv/Statement.php +++ b/app/vendor/doctrine/dbal/src/Driver/PDO/SQLSrv/Statement.php @@ -36,7 +36,7 @@ public function __construct(PDOStatement $statement) * * @throws UnknownParameterType * - * @psalm-assert ParameterType::* $type + * @phpstan-assert ParameterType::* $type */ public function bindParam( $param, @@ -91,7 +91,7 @@ public function bindParam( * * {@inheritDoc} * - * @psalm-assert ParameterType::* $type + * @phpstan-assert ParameterType::* $type */ public function bindValue($param, $value, $type = ParameterType::STRING): bool { diff --git a/app/vendor/doctrine/dbal/src/Driver/PDO/Statement.php b/app/vendor/doctrine/dbal/src/Driver/PDO/Statement.php index 64f318d2c..e631fad3d 100644 --- a/app/vendor/doctrine/dbal/src/Driver/PDO/Statement.php +++ b/app/vendor/doctrine/dbal/src/Driver/PDO/Statement.php @@ -29,7 +29,7 @@ public function __construct(PDOStatement $stmt) * * @throws UnknownParameterType * - * @psalm-assert ParameterType::* $type + * @phpstan-assert ParameterType::* $type */ public function bindValue($param, $value, $type = ParameterType::STRING) { @@ -64,7 +64,7 @@ public function bindValue($param, $value, $type = ParameterType::STRING) * * @throws UnknownParameterType * - * @psalm-assert ParameterType::* $type + * @phpstan-assert ParameterType::* $type */ public function bindParam( $param, diff --git a/app/vendor/doctrine/dbal/src/Driver/PgSQL/Driver.php b/app/vendor/doctrine/dbal/src/Driver/PgSQL/Driver.php index 73c97cd81..1cdaee1f2 100644 --- a/app/vendor/doctrine/dbal/src/Driver/PgSQL/Driver.php +++ b/app/vendor/doctrine/dbal/src/Driver/PgSQL/Driver.php @@ -15,6 +15,7 @@ use function func_get_args; use function implode; use function pg_connect; +use function preg_match; use function restore_error_handler; use function set_error_handler; use function sprintf; @@ -64,14 +65,24 @@ private function constructConnectionString( #[SensitiveParameter] array $params ): string { + // pg_connect used by Doctrine DBAL does not support [...] notation, + // but requires the host address in plain form like `aa:bb:99...` + $matches = []; + if (isset($params['host']) && preg_match('/^\[(.+)\]$/', $params['host'], $matches) === 1) { + $params['hostaddr'] = $matches[1]; + unset($params['host']); + } + $components = array_filter( [ 'host' => $params['host'] ?? null, + 'hostaddr' => $params['hostaddr'] ?? null, 'port' => $params['port'] ?? null, 'dbname' => $params['dbname'] ?? 'postgres', 'user' => $params['user'] ?? null, 'password' => $params['password'] ?? null, 'sslmode' => $params['sslmode'] ?? null, + 'gssencmode' => $params['gssencmode'] ?? null, ], static fn ($value) => $value !== '' && $value !== null, ); diff --git a/app/vendor/doctrine/dbal/src/Driver/PgSQL/Exception.php b/app/vendor/doctrine/dbal/src/Driver/PgSQL/Exception.php index 41e0dff19..5e7086ba0 100644 --- a/app/vendor/doctrine/dbal/src/Driver/PgSQL/Exception.php +++ b/app/vendor/doctrine/dbal/src/Driver/PgSQL/Exception.php @@ -10,11 +10,7 @@ use const PGSQL_DIAG_MESSAGE_PRIMARY; use const PGSQL_DIAG_SQLSTATE; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class Exception extends AbstractException { /** @param PgSqlResult|resource $result */ diff --git a/app/vendor/doctrine/dbal/src/Driver/PgSQL/Exception/UnexpectedValue.php b/app/vendor/doctrine/dbal/src/Driver/PgSQL/Exception/UnexpectedValue.php index ef69817b7..d295cf5e8 100644 --- a/app/vendor/doctrine/dbal/src/Driver/PgSQL/Exception/UnexpectedValue.php +++ b/app/vendor/doctrine/dbal/src/Driver/PgSQL/Exception/UnexpectedValue.php @@ -9,7 +9,6 @@ use function sprintf; -/** @psalm-immutable */ final class UnexpectedValue extends UnexpectedValueException implements Exception { public static function new(string $value, string $type): self diff --git a/app/vendor/doctrine/dbal/src/Driver/PgSQL/Exception/UnknownParameter.php b/app/vendor/doctrine/dbal/src/Driver/PgSQL/Exception/UnknownParameter.php index 4619ecc0d..dd4b2694d 100644 --- a/app/vendor/doctrine/dbal/src/Driver/PgSQL/Exception/UnknownParameter.php +++ b/app/vendor/doctrine/dbal/src/Driver/PgSQL/Exception/UnknownParameter.php @@ -6,7 +6,6 @@ use function sprintf; -/** @psalm-immutable */ final class UnknownParameter extends AbstractException { public static function new(string $param): self diff --git a/app/vendor/doctrine/dbal/src/Driver/PgSQL/Statement.php b/app/vendor/doctrine/dbal/src/Driver/PgSQL/Statement.php index 75af66f30..241f50c95 100644 --- a/app/vendor/doctrine/dbal/src/Driver/PgSQL/Statement.php +++ b/app/vendor/doctrine/dbal/src/Driver/PgSQL/Statement.php @@ -40,7 +40,7 @@ final class Statement implements StatementInterface /** @var array */ private array $parameters = []; - /** @psalm-var array */ + /** @var array */ private array $parameterTypes = []; /** @@ -81,8 +81,13 @@ public function bindValue($param, $value, $type = ParameterType::STRING): bool throw UnknownParameter::new((string) $param); } - $this->parameters[$this->parameterMap[$param]] = $value; - $this->parameterTypes[$this->parameterMap[$param]] = $type; + if ($type === ParameterType::BOOLEAN) { + $this->parameters[$this->parameterMap[$param]] = (bool) $value === false ? 'f' : 't'; + $this->parameterTypes[$this->parameterMap[$param]] = ParameterType::STRING; + } else { + $this->parameters[$this->parameterMap[$param]] = $value; + $this->parameterTypes[$this->parameterMap[$param]] = $type; + } return true; } diff --git a/app/vendor/doctrine/dbal/src/Driver/SQLSrv/Exception/Error.php b/app/vendor/doctrine/dbal/src/Driver/SQLSrv/Exception/Error.php index f39d5fc4c..e9adb0528 100644 --- a/app/vendor/doctrine/dbal/src/Driver/SQLSrv/Exception/Error.php +++ b/app/vendor/doctrine/dbal/src/Driver/SQLSrv/Exception/Error.php @@ -11,11 +11,7 @@ use const SQLSRV_ERR_ERRORS; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class Error extends AbstractException { public static function new(): self diff --git a/app/vendor/doctrine/dbal/src/Driver/SQLSrv/Result.php b/app/vendor/doctrine/dbal/src/Driver/SQLSrv/Result.php index db17e928d..6c0a368df 100644 --- a/app/vendor/doctrine/dbal/src/Driver/SQLSrv/Result.php +++ b/app/vendor/doctrine/dbal/src/Driver/SQLSrv/Result.php @@ -106,7 +106,7 @@ public function free(): void // @link http://php.net/manual/en/pdostatement.closecursor.php // @link https://github.com/php/php-src/blob/php-7.0.11/ext/pdo/pdo_stmt.c#L2075 // deliberately do not consider multiple result sets, since doctrine/dbal doesn't support them - while (sqlsrv_fetch($this->statement)) { + while (sqlsrv_fetch($this->statement) === true) { } } diff --git a/app/vendor/doctrine/dbal/src/Driver/SQLite3/Exception.php b/app/vendor/doctrine/dbal/src/Driver/SQLite3/Exception.php index 3ca1190bc..3219fc327 100644 --- a/app/vendor/doctrine/dbal/src/Driver/SQLite3/Exception.php +++ b/app/vendor/doctrine/dbal/src/Driver/SQLite3/Exception.php @@ -4,11 +4,7 @@ use Doctrine\DBAL\Driver\AbstractException; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class Exception extends AbstractException { public static function new(\Exception $exception): self diff --git a/app/vendor/doctrine/dbal/src/Driver/SQLite3/Statement.php b/app/vendor/doctrine/dbal/src/Driver/SQLite3/Statement.php index a4166aa61..01c3b8bbb 100644 --- a/app/vendor/doctrine/dbal/src/Driver/SQLite3/Statement.php +++ b/app/vendor/doctrine/dbal/src/Driver/SQLite3/Statement.php @@ -45,7 +45,7 @@ public function __construct(SQLite3 $connection, SQLite3Stmt $statement) * * {@inheritDoc} * - * @psalm-assert ParameterType::* $type + * @phpstan-assert ParameterType::* $type */ public function bindValue($param, $value, $type = ParameterType::STRING): bool { @@ -66,7 +66,7 @@ public function bindValue($param, $value, $type = ParameterType::STRING): bool * * {@inheritDoc} * - * @psalm-assert ParameterType::* $type + * @phpstan-assert ParameterType::* $type */ public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null): bool { @@ -121,9 +121,9 @@ public function execute($params = null): Result } /** - * @psalm-return value-of + * @phpstan-return value-of * - * @psalm-assert ParameterType::* $type + * @phpstan-assert ParameterType::* $type */ private function convertParamType(int $type): int { diff --git a/app/vendor/doctrine/dbal/src/DriverManager.php b/app/vendor/doctrine/dbal/src/DriverManager.php index 056f42084..7586bc479 100644 --- a/app/vendor/doctrine/dbal/src/DriverManager.php +++ b/app/vendor/doctrine/dbal/src/DriverManager.php @@ -22,7 +22,7 @@ /** * Factory for creating {@see Connection} instances. * - * @psalm-type OverrideParams = array{ + * @phpstan-type OverrideParams = array{ * application_name?: string, * charset?: string, * dbname?: string, @@ -41,7 +41,7 @@ * user?: string, * unix_socket?: string, * } - * @psalm-type Params = array{ + * @phpstan-type Params = array{ * application_name?: string, * charset?: string, * dbname?: string, @@ -98,7 +98,7 @@ final class DriverManager * @deprecated Use actual driver names instead. * * @var array - * @psalm-var array> + * @phpstan-var array> */ private static array $driverSchemeAliases = [ 'db2' => 'ibm_db2', @@ -153,9 +153,9 @@ private function __construct() * * @param Configuration|null $config The configuration to use. * @param EventManager|null $eventManager The event manager to use. - * @psalm-param Params $params + * @phpstan-param Params $params * - * @psalm-return ($params is array{wrapperClass: class-string} ? T : Connection) + * @phpstan-return ($params is array{wrapperClass: class-string} ? T : Connection) * * @throws Exception * @@ -201,7 +201,7 @@ public static function getConnection( * Returns the list of supported drivers. * * @return string[] - * @psalm-return list> + * @phpstan-return list> */ public static function getAvailableDrivers(): array { @@ -211,8 +211,8 @@ public static function getAvailableDrivers(): array /** * @throws Exception * - * @psalm-assert key-of|null $driver - * @psalm-assert class-string|null $driverClass + * @phpstan-assert key-of|null $driver + * @phpstan-assert class-string|null $driverClass */ private static function createDriver(?string $driver, ?string $driverClass): Driver { @@ -238,11 +238,11 @@ private static function createDriver(?string $driver, ?string $driverClass): Dri * updated list of parameters. * * @param mixed[] $params The list of parameters. - * @psalm-param Params $params + * @phpstan-param Params $params * * @return mixed[] A modified list of parameters with info from a database * URL extracted into indidivual parameter parts. - * @psalm-return Params + * @phpstan-return Params * * @throws Exception */ diff --git a/app/vendor/doctrine/dbal/src/Event/SchemaDropTableEventArgs.php b/app/vendor/doctrine/dbal/src/Event/SchemaDropTableEventArgs.php index f45e3a15a..6f279e965 100644 --- a/app/vendor/doctrine/dbal/src/Event/SchemaDropTableEventArgs.php +++ b/app/vendor/doctrine/dbal/src/Event/SchemaDropTableEventArgs.php @@ -4,7 +4,6 @@ use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Schema\Table; -use InvalidArgumentException; /** * Event Arguments used when the SQL query for dropping tables are generated inside {@see AbstractPlatform}. @@ -21,11 +20,7 @@ class SchemaDropTableEventArgs extends SchemaEventArgs /** @var string|null */ private $sql; - /** - * @param string|Table $table - * - * @throws InvalidArgumentException - */ + /** @param string|Table $table */ public function __construct($table, AbstractPlatform $platform) { $this->table = $table; diff --git a/app/vendor/doctrine/dbal/src/Exception.php b/app/vendor/doctrine/dbal/src/Exception.php index 3d2814c73..8475a140d 100644 --- a/app/vendor/doctrine/dbal/src/Exception.php +++ b/app/vendor/doctrine/dbal/src/Exception.php @@ -13,7 +13,6 @@ use function spl_object_hash; use function sprintf; -/** @psalm-immutable */ class Exception extends \Exception { public static function notSupported(string $method): self diff --git a/app/vendor/doctrine/dbal/src/Exception/ConnectionException.php b/app/vendor/doctrine/dbal/src/Exception/ConnectionException.php index 6b7c901a3..e96a29191 100644 --- a/app/vendor/doctrine/dbal/src/Exception/ConnectionException.php +++ b/app/vendor/doctrine/dbal/src/Exception/ConnectionException.php @@ -4,8 +4,6 @@ /** * Base class for all connection related errors detected in the driver. - * - * @psalm-immutable */ class ConnectionException extends DriverException { diff --git a/app/vendor/doctrine/dbal/src/Exception/ConnectionLost.php b/app/vendor/doctrine/dbal/src/Exception/ConnectionLost.php index c45085839..1195d98e9 100644 --- a/app/vendor/doctrine/dbal/src/Exception/ConnectionLost.php +++ b/app/vendor/doctrine/dbal/src/Exception/ConnectionLost.php @@ -2,7 +2,6 @@ namespace Doctrine\DBAL\Exception; -/** @psalm-immutable */ final class ConnectionLost extends ConnectionException { } diff --git a/app/vendor/doctrine/dbal/src/Exception/ConstraintViolationException.php b/app/vendor/doctrine/dbal/src/Exception/ConstraintViolationException.php index 435e8b19f..3959f39af 100644 --- a/app/vendor/doctrine/dbal/src/Exception/ConstraintViolationException.php +++ b/app/vendor/doctrine/dbal/src/Exception/ConstraintViolationException.php @@ -4,8 +4,6 @@ /** * Base class for all constraint violation related errors detected in the driver. - * - * @psalm-immutable */ class ConstraintViolationException extends ServerException { diff --git a/app/vendor/doctrine/dbal/src/Exception/DatabaseDoesNotExist.php b/app/vendor/doctrine/dbal/src/Exception/DatabaseDoesNotExist.php index dc71c82cb..a49f6dec8 100644 --- a/app/vendor/doctrine/dbal/src/Exception/DatabaseDoesNotExist.php +++ b/app/vendor/doctrine/dbal/src/Exception/DatabaseDoesNotExist.php @@ -2,7 +2,6 @@ namespace Doctrine\DBAL\Exception; -/** @psalm-immutable */ class DatabaseDoesNotExist extends DatabaseObjectNotFoundException { } diff --git a/app/vendor/doctrine/dbal/src/Exception/DatabaseObjectExistsException.php b/app/vendor/doctrine/dbal/src/Exception/DatabaseObjectExistsException.php index fb19f5bae..7e0ba0299 100644 --- a/app/vendor/doctrine/dbal/src/Exception/DatabaseObjectExistsException.php +++ b/app/vendor/doctrine/dbal/src/Exception/DatabaseObjectExistsException.php @@ -8,8 +8,6 @@ * A database object is considered any asset that can be created in a database * such as schemas, tables, views, sequences, triggers, constraints, indexes, * functions, stored procedures etc. - * - * @psalm-immutable */ class DatabaseObjectExistsException extends ServerException { diff --git a/app/vendor/doctrine/dbal/src/Exception/DatabaseObjectNotFoundException.php b/app/vendor/doctrine/dbal/src/Exception/DatabaseObjectNotFoundException.php index 2d3d78d99..3342bce8d 100644 --- a/app/vendor/doctrine/dbal/src/Exception/DatabaseObjectNotFoundException.php +++ b/app/vendor/doctrine/dbal/src/Exception/DatabaseObjectNotFoundException.php @@ -8,8 +8,6 @@ * A database object is considered any asset that can be created in a database * such as schemas, tables, views, sequences, triggers, constraints, indexes, * functions, stored procedures etc. - * - * @psalm-immutable */ class DatabaseObjectNotFoundException extends ServerException { diff --git a/app/vendor/doctrine/dbal/src/Exception/DatabaseRequired.php b/app/vendor/doctrine/dbal/src/Exception/DatabaseRequired.php index 49b7326cd..6889a5d23 100644 --- a/app/vendor/doctrine/dbal/src/Exception/DatabaseRequired.php +++ b/app/vendor/doctrine/dbal/src/Exception/DatabaseRequired.php @@ -8,7 +8,6 @@ use function sprintf; -/** @psalm-immutable */ class DatabaseRequired extends Exception { public static function new(string $methodName): self diff --git a/app/vendor/doctrine/dbal/src/Exception/DeadlockException.php b/app/vendor/doctrine/dbal/src/Exception/DeadlockException.php index f36be908a..fd0550a56 100644 --- a/app/vendor/doctrine/dbal/src/Exception/DeadlockException.php +++ b/app/vendor/doctrine/dbal/src/Exception/DeadlockException.php @@ -4,8 +4,6 @@ /** * Exception for a deadlock error of a transaction detected in the driver. - * - * @psalm-immutable */ class DeadlockException extends ServerException implements RetryableException { diff --git a/app/vendor/doctrine/dbal/src/Exception/DriverException.php b/app/vendor/doctrine/dbal/src/Exception/DriverException.php index 8bba9dd87..559a40c29 100644 --- a/app/vendor/doctrine/dbal/src/Exception/DriverException.php +++ b/app/vendor/doctrine/dbal/src/Exception/DriverException.php @@ -10,8 +10,6 @@ /** * Base class for all errors detected in the driver. - * - * @psalm-immutable */ class DriverException extends Exception implements TheDriverException { diff --git a/app/vendor/doctrine/dbal/src/Exception/ForeignKeyConstraintViolationException.php b/app/vendor/doctrine/dbal/src/Exception/ForeignKeyConstraintViolationException.php index f1a612b21..48d736f9e 100644 --- a/app/vendor/doctrine/dbal/src/Exception/ForeignKeyConstraintViolationException.php +++ b/app/vendor/doctrine/dbal/src/Exception/ForeignKeyConstraintViolationException.php @@ -4,8 +4,6 @@ /** * Exception for a foreign key constraint violation detected in the driver. - * - * @psalm-immutable */ class ForeignKeyConstraintViolationException extends ConstraintViolationException { diff --git a/app/vendor/doctrine/dbal/src/Exception/InvalidArgumentException.php b/app/vendor/doctrine/dbal/src/Exception/InvalidArgumentException.php index 7f58510f0..044cecfec 100644 --- a/app/vendor/doctrine/dbal/src/Exception/InvalidArgumentException.php +++ b/app/vendor/doctrine/dbal/src/Exception/InvalidArgumentException.php @@ -6,8 +6,6 @@ /** * Exception to be thrown when invalid arguments are passed to any DBAL API - * - * @psalm-immutable */ class InvalidArgumentException extends Exception { diff --git a/app/vendor/doctrine/dbal/src/Exception/InvalidFieldNameException.php b/app/vendor/doctrine/dbal/src/Exception/InvalidFieldNameException.php index 234941bf6..d960feaf8 100644 --- a/app/vendor/doctrine/dbal/src/Exception/InvalidFieldNameException.php +++ b/app/vendor/doctrine/dbal/src/Exception/InvalidFieldNameException.php @@ -4,8 +4,6 @@ /** * Exception for an invalid specified field name in a statement detected in the driver. - * - * @psalm-immutable */ class InvalidFieldNameException extends ServerException { diff --git a/app/vendor/doctrine/dbal/src/Exception/InvalidLockMode.php b/app/vendor/doctrine/dbal/src/Exception/InvalidLockMode.php index f1780c459..9c38c77c2 100644 --- a/app/vendor/doctrine/dbal/src/Exception/InvalidLockMode.php +++ b/app/vendor/doctrine/dbal/src/Exception/InvalidLockMode.php @@ -6,7 +6,6 @@ use function sprintf; -/** @psalm-immutable */ class InvalidLockMode extends Exception { public static function fromLockMode(int $lockMode): self diff --git a/app/vendor/doctrine/dbal/src/Exception/LockWaitTimeoutException.php b/app/vendor/doctrine/dbal/src/Exception/LockWaitTimeoutException.php index 62aa10fca..bfc3a498a 100644 --- a/app/vendor/doctrine/dbal/src/Exception/LockWaitTimeoutException.php +++ b/app/vendor/doctrine/dbal/src/Exception/LockWaitTimeoutException.php @@ -4,8 +4,6 @@ /** * Exception for a lock wait timeout error of a transaction detected in the driver. - * - * @psalm-immutable */ class LockWaitTimeoutException extends ServerException implements RetryableException { diff --git a/app/vendor/doctrine/dbal/src/Exception/MalformedDsnException.php b/app/vendor/doctrine/dbal/src/Exception/MalformedDsnException.php index 01cd7c200..3f9b87443 100644 --- a/app/vendor/doctrine/dbal/src/Exception/MalformedDsnException.php +++ b/app/vendor/doctrine/dbal/src/Exception/MalformedDsnException.php @@ -4,7 +4,6 @@ use InvalidArgumentException; -/** @psalm-immutable */ class MalformedDsnException extends InvalidArgumentException { public static function new(): self diff --git a/app/vendor/doctrine/dbal/src/Exception/NoKeyValue.php b/app/vendor/doctrine/dbal/src/Exception/NoKeyValue.php index 545ade3ec..be5508a34 100644 --- a/app/vendor/doctrine/dbal/src/Exception/NoKeyValue.php +++ b/app/vendor/doctrine/dbal/src/Exception/NoKeyValue.php @@ -6,11 +6,7 @@ use function sprintf; -/** - * @internal - * - * @psalm-immutable - */ +/** @internal */ final class NoKeyValue extends Exception { public static function fromColumnCount(int $columnCount): self diff --git a/app/vendor/doctrine/dbal/src/Exception/NonUniqueFieldNameException.php b/app/vendor/doctrine/dbal/src/Exception/NonUniqueFieldNameException.php index 9ff662733..fd56f8969 100644 --- a/app/vendor/doctrine/dbal/src/Exception/NonUniqueFieldNameException.php +++ b/app/vendor/doctrine/dbal/src/Exception/NonUniqueFieldNameException.php @@ -4,8 +4,6 @@ /** * Exception for a non-unique/ambiguous specified field name in a statement detected in the driver. - * - * @psalm-immutable */ class NonUniqueFieldNameException extends ServerException { diff --git a/app/vendor/doctrine/dbal/src/Exception/NotNullConstraintViolationException.php b/app/vendor/doctrine/dbal/src/Exception/NotNullConstraintViolationException.php index 113b737bb..e327bc94d 100644 --- a/app/vendor/doctrine/dbal/src/Exception/NotNullConstraintViolationException.php +++ b/app/vendor/doctrine/dbal/src/Exception/NotNullConstraintViolationException.php @@ -4,8 +4,6 @@ /** * Exception for a NOT NULL constraint violation detected in the driver. - * - * @psalm-immutable */ class NotNullConstraintViolationException extends ConstraintViolationException { diff --git a/app/vendor/doctrine/dbal/src/Exception/ReadOnlyException.php b/app/vendor/doctrine/dbal/src/Exception/ReadOnlyException.php index 621363af9..a846f2501 100644 --- a/app/vendor/doctrine/dbal/src/Exception/ReadOnlyException.php +++ b/app/vendor/doctrine/dbal/src/Exception/ReadOnlyException.php @@ -4,8 +4,6 @@ /** * Exception for a write operation attempt on a read-only database element detected in the driver. - * - * @psalm-immutable */ class ReadOnlyException extends ServerException { diff --git a/app/vendor/doctrine/dbal/src/Exception/RetryableException.php b/app/vendor/doctrine/dbal/src/Exception/RetryableException.php index 79e325199..4cb94b100 100644 --- a/app/vendor/doctrine/dbal/src/Exception/RetryableException.php +++ b/app/vendor/doctrine/dbal/src/Exception/RetryableException.php @@ -6,8 +6,6 @@ /** * Marker interface for all exceptions where retrying the transaction makes sense. - * - * @psalm-immutable */ interface RetryableException extends Throwable { diff --git a/app/vendor/doctrine/dbal/src/Exception/SchemaDoesNotExist.php b/app/vendor/doctrine/dbal/src/Exception/SchemaDoesNotExist.php index de6fa5c00..13813838e 100644 --- a/app/vendor/doctrine/dbal/src/Exception/SchemaDoesNotExist.php +++ b/app/vendor/doctrine/dbal/src/Exception/SchemaDoesNotExist.php @@ -2,7 +2,6 @@ namespace Doctrine\DBAL\Exception; -/** @psalm-immutable */ class SchemaDoesNotExist extends DatabaseObjectNotFoundException { } diff --git a/app/vendor/doctrine/dbal/src/Exception/ServerException.php b/app/vendor/doctrine/dbal/src/Exception/ServerException.php index 194bc9cdd..c88c3863b 100644 --- a/app/vendor/doctrine/dbal/src/Exception/ServerException.php +++ b/app/vendor/doctrine/dbal/src/Exception/ServerException.php @@ -4,8 +4,6 @@ /** * Base class for all server related errors detected in the driver. - * - * @psalm-immutable */ class ServerException extends DriverException { diff --git a/app/vendor/doctrine/dbal/src/Exception/SyntaxErrorException.php b/app/vendor/doctrine/dbal/src/Exception/SyntaxErrorException.php index 2603ac274..0b413b719 100644 --- a/app/vendor/doctrine/dbal/src/Exception/SyntaxErrorException.php +++ b/app/vendor/doctrine/dbal/src/Exception/SyntaxErrorException.php @@ -4,8 +4,6 @@ /** * Exception for a syntax error in a statement detected in the driver. - * - * @psalm-immutable */ class SyntaxErrorException extends ServerException { diff --git a/app/vendor/doctrine/dbal/src/Exception/TableExistsException.php b/app/vendor/doctrine/dbal/src/Exception/TableExistsException.php index b6575a25d..ff0df89af 100644 --- a/app/vendor/doctrine/dbal/src/Exception/TableExistsException.php +++ b/app/vendor/doctrine/dbal/src/Exception/TableExistsException.php @@ -4,8 +4,6 @@ /** * Exception for an already existing table referenced in a statement detected in the driver. - * - * @psalm-immutable */ class TableExistsException extends DatabaseObjectExistsException { diff --git a/app/vendor/doctrine/dbal/src/Exception/TableNotFoundException.php b/app/vendor/doctrine/dbal/src/Exception/TableNotFoundException.php index 445a38b5a..aeaa0057d 100644 --- a/app/vendor/doctrine/dbal/src/Exception/TableNotFoundException.php +++ b/app/vendor/doctrine/dbal/src/Exception/TableNotFoundException.php @@ -4,8 +4,6 @@ /** * Exception for an unknown table referenced in a statement detected in the driver. - * - * @psalm-immutable */ class TableNotFoundException extends DatabaseObjectNotFoundException { diff --git a/app/vendor/doctrine/dbal/src/Exception/TransactionRolledBack.php b/app/vendor/doctrine/dbal/src/Exception/TransactionRolledBack.php new file mode 100644 index 000000000..c3605a468 --- /dev/null +++ b/app/vendor/doctrine/dbal/src/Exception/TransactionRolledBack.php @@ -0,0 +1,7 @@ + $className) { foreach (Type::getType($typeName)->getMappedDatabaseTypes($this) as $dbType) { + $dbType = strtolower($dbType); $this->doctrineTypeMapping[$dbType] = $typeName; } } @@ -1793,7 +1794,7 @@ public function getForUpdateSQL() * * @param string $fromClause The FROM clause to append the hint for the given lock mode to * @param int $lockMode One of the Doctrine\DBAL\LockMode::* constants - * @psalm-param LockMode::* $lockMode + * @phpstan-param LockMode::* $lockMode */ public function appendLockHint(string $fromClause, int $lockMode): string { @@ -2052,7 +2053,7 @@ public function getDropUniqueConstraintSQL(string $name, string $tableName): str * on this platform. * * @param int $createFlags - * @psalm-param int-mask-of $createFlags + * @phpstan-param int-mask-of $createFlags * * @return list The list of SQL statements. * @@ -2225,7 +2226,7 @@ private function buildCreateTableSQL(Table $table, bool $createIndexes, bool $cr } /** - * @param list $tables + * @param Table[] $tables * * @return list * @@ -4563,7 +4564,7 @@ protected function createReservedKeywordsList(): KeywordList * @deprecated Implement {@see createReservedKeywordsList()} instead. * * @return string - * @psalm-return class-string + * @phpstan-return class-string * * @throws Exception If not supported on this platform. */ @@ -4692,6 +4693,11 @@ public function columnsEqual(Column $column1, Column $column2): bool return false; } + // If disableTypeComments is true, we do not need to check types, all comparison is already done above + if ($this->disableTypeComments) { + return true; + } + return $column1->getType() === $column2->getType(); } diff --git a/app/vendor/doctrine/dbal/src/Platforms/Keywords/KeywordList.php b/app/vendor/doctrine/dbal/src/Platforms/Keywords/KeywordList.php index 584277395..d8b4f4630 100644 --- a/app/vendor/doctrine/dbal/src/Platforms/Keywords/KeywordList.php +++ b/app/vendor/doctrine/dbal/src/Platforms/Keywords/KeywordList.php @@ -9,7 +9,7 @@ /** * Abstract interface for a SQL reserved keyword dictionary. * - * @psalm-consistent-constructor + * @phpstan-consistent-constructor */ abstract class KeywordList { diff --git a/app/vendor/doctrine/dbal/src/Platforms/Keywords/MySQL84Keywords.php b/app/vendor/doctrine/dbal/src/Platforms/Keywords/MySQL84Keywords.php new file mode 100644 index 000000000..b057e71fd --- /dev/null +++ b/app/vendor/doctrine/dbal/src/Platforms/Keywords/MySQL84Keywords.php @@ -0,0 +1,64 @@ +getDropConstraintSQL($constraintName, $table); } + if ($table !== null) { + $indexName = $index instanceof Index ? $index->getQuotedName($this) : $index; + $tableName = $table instanceof Table ? $table->getQuotedName($this) : $table; + + if (strpos($tableName, '.') !== false) { + [$schema] = explode('.', $tableName); + $index = $schema . '.' . $indexName; + } + } + return parent::getDropIndexSQL($index, $table); } @@ -1193,6 +1201,19 @@ public function getTruncateTableSQL($tableName, $cascade = false) return $sql; } + /** + * Get the snippet used to retrieve the default value for a given column + */ + public function getDefaultColumnValueSQLSnippet(): string + { + return <<<'SQL' + SELECT pg_get_expr(adbin, adrelid) + FROM pg_attrdef + WHERE c.oid = pg_attrdef.adrelid + AND pg_attrdef.adnum=a.attnum + SQL; + } + /** * {@inheritDoc} */ diff --git a/app/vendor/doctrine/dbal/src/Platforms/SQLServerPlatform.php b/app/vendor/doctrine/dbal/src/Platforms/SQLServerPlatform.php index c8cd20b56..eed1cbab4 100644 --- a/app/vendor/doctrine/dbal/src/Platforms/SQLServerPlatform.php +++ b/app/vendor/doctrine/dbal/src/Platforms/SQLServerPlatform.php @@ -38,9 +38,13 @@ use function preg_match; use function preg_match_all; use function sprintf; +use function str_contains; +use function str_ends_with; use function str_replace; +use function str_starts_with; use function strpos; use function strtoupper; +use function substr; use function substr_count; use const PREG_OFFSET_CAPTURE; @@ -399,6 +403,13 @@ public function getCreatePrimaryKeySQL(Index $index, $table) return $sql . ' (' . $this->getIndexFieldDeclarationListSQL($index) . ')'; } + private function unquoteSingleIdentifier(string $possiblyQuotedName): string + { + return str_starts_with($possiblyQuotedName, '[') && str_ends_with($possiblyQuotedName, ']') + ? substr($possiblyQuotedName, 1, -1) + : $possiblyQuotedName; + } + /** * Returns the SQL statement for creating a column comment. * @@ -419,23 +430,20 @@ public function getCreatePrimaryKeySQL(Index $index, $table) protected function getCreateColumnCommentSQL($tableName, $columnName, $comment) { if (strpos($tableName, '.') !== false) { - [$schemaSQL, $tableSQL] = explode('.', $tableName); - $schemaSQL = $this->quoteStringLiteral($schemaSQL); - $tableSQL = $this->quoteStringLiteral($tableSQL); + [$schemaName, $tableName] = explode('.', $tableName); } else { - $schemaSQL = "'dbo'"; - $tableSQL = $this->quoteStringLiteral($tableName); + $schemaName = 'dbo'; } return $this->getAddExtendedPropertySQL( 'MS_Description', $comment, 'SCHEMA', - $schemaSQL, + $this->quoteStringLiteral($this->unquoteSingleIdentifier($schemaName)), 'TABLE', - $tableSQL, + $this->quoteStringLiteral($this->unquoteSingleIdentifier($tableName)), 'COLUMN', - $columnName, + $this->quoteStringLiteral($this->unquoteSingleIdentifier($columnName)), ); } @@ -806,23 +814,20 @@ private function alterColumnRequiresDropDefaultConstraint(ColumnDiff $columnDiff protected function getAlterColumnCommentSQL($tableName, $columnName, $comment) { if (strpos($tableName, '.') !== false) { - [$schemaSQL, $tableSQL] = explode('.', $tableName); - $schemaSQL = $this->quoteStringLiteral($schemaSQL); - $tableSQL = $this->quoteStringLiteral($tableSQL); + [$schemaName, $tableName] = explode('.', $tableName); } else { - $schemaSQL = "'dbo'"; - $tableSQL = $this->quoteStringLiteral($tableName); + $schemaName = 'dbo'; } return $this->getUpdateExtendedPropertySQL( 'MS_Description', $comment, 'SCHEMA', - $schemaSQL, + $this->quoteStringLiteral($this->unquoteSingleIdentifier($schemaName)), 'TABLE', - $tableSQL, + $this->quoteStringLiteral($this->unquoteSingleIdentifier($tableName)), 'COLUMN', - $columnName, + $this->quoteStringLiteral($this->unquoteSingleIdentifier($columnName)), ); } @@ -845,22 +850,19 @@ protected function getAlterColumnCommentSQL($tableName, $columnName, $comment) protected function getDropColumnCommentSQL($tableName, $columnName) { if (strpos($tableName, '.') !== false) { - [$schemaSQL, $tableSQL] = explode('.', $tableName); - $schemaSQL = $this->quoteStringLiteral($schemaSQL); - $tableSQL = $this->quoteStringLiteral($tableSQL); + [$schemaName, $tableName] = explode('.', $tableName); } else { - $schemaSQL = "'dbo'"; - $tableSQL = $this->quoteStringLiteral($tableName); + $schemaName = 'dbo'; } return $this->getDropExtendedPropertySQL( 'MS_Description', 'SCHEMA', - $schemaSQL, + $this->quoteStringLiteral($this->unquoteSingleIdentifier($schemaName)), 'TABLE', - $tableSQL, + $this->quoteStringLiteral($this->unquoteSingleIdentifier($tableName)), 'COLUMN', - $columnName, + $this->quoteStringLiteral($this->unquoteSingleIdentifier($columnName)), ); } @@ -907,10 +909,13 @@ public function getAddExtendedPropertySQL( $level2Name = null ) { return 'EXEC sp_addextendedproperty ' . - 'N' . $this->quoteStringLiteral($name) . ', N' . $this->quoteStringLiteral((string) $value) . ', ' . - 'N' . $this->quoteStringLiteral((string) $level0Type) . ', ' . $level0Name . ', ' . - 'N' . $this->quoteStringLiteral((string) $level1Type) . ', ' . $level1Name . ', ' . - 'N' . $this->quoteStringLiteral((string) $level2Type) . ', ' . $level2Name; + 'N' . $this->quoteStringLiteral($name) . ', N' . $this->quoteStringLiteral($value ?? '') . ', ' . + 'N' . $this->quoteStringLiteral($level0Type ?? '') . ', ' . $level0Name . ', ' . + 'N' . $this->quoteStringLiteral($level1Type ?? '') . ', ' . $level1Name . + ($level2Type !== null || $level2Name !== null + ? ', N' . $this->quoteStringLiteral($level2Type ?? '') . ', ' . $level2Name + : '' + ); } /** @@ -941,9 +946,12 @@ public function getDropExtendedPropertySQL( ) { return 'EXEC sp_dropextendedproperty ' . 'N' . $this->quoteStringLiteral($name) . ', ' . - 'N' . $this->quoteStringLiteral((string) $level0Type) . ', ' . $level0Name . ', ' . - 'N' . $this->quoteStringLiteral((string) $level1Type) . ', ' . $level1Name . ', ' . - 'N' . $this->quoteStringLiteral((string) $level2Type) . ', ' . $level2Name; + 'N' . $this->quoteStringLiteral($level0Type ?? '') . ', ' . $level0Name . ', ' . + 'N' . $this->quoteStringLiteral($level1Type ?? '') . ', ' . $level1Name . + ($level2Type !== null || $level2Name !== null + ? ', N' . $this->quoteStringLiteral($level2Type ?? '') . ', ' . $level2Name + : '' + ); } /** @@ -975,10 +983,13 @@ public function getUpdateExtendedPropertySQL( $level2Name = null ) { return 'EXEC sp_updateextendedproperty ' . - 'N' . $this->quoteStringLiteral($name) . ', N' . $this->quoteStringLiteral((string) $value) . ', ' . - 'N' . $this->quoteStringLiteral((string) $level0Type) . ', ' . $level0Name . ', ' . - 'N' . $this->quoteStringLiteral((string) $level1Type) . ', ' . $level1Name . ', ' . - 'N' . $this->quoteStringLiteral((string) $level2Type) . ', ' . $level2Name; + 'N' . $this->quoteStringLiteral($name) . ', N' . $this->quoteStringLiteral($value ?? '') . ', ' . + 'N' . $this->quoteStringLiteral($level0Type ?? '') . ', ' . $level0Name . ', ' . + 'N' . $this->quoteStringLiteral($level1Type ?? '') . ', ' . $level1Name . + ($level2Type !== null || $level2Name !== null + ? ', N' . $this->quoteStringLiteral($level2Type ?? '') . ', ' . $level2Name + : '' + ); } /** @@ -1296,7 +1307,7 @@ public function getAsciiStringTypeDeclarationSQL(array $column): string { $length = $column['length'] ?? null; - if (! isset($column['fixed'])) { + if (empty($column['fixed'])) { return sprintf('VARCHAR(%d)', $length ?? 255); } @@ -1549,12 +1560,14 @@ protected function initializeDoctrineTypeMappings() 'smalldatetime' => Types::DATETIME_MUTABLE, 'smallint' => Types::SMALLINT, 'smallmoney' => Types::INTEGER, + 'sysname' => Types::STRING, 'text' => Types::TEXT, 'time' => Types::TIME_MUTABLE, 'tinyint' => Types::SMALLINT, 'uniqueidentifier' => Types::GUID, 'varbinary' => Types::BINARY, 'varchar' => Types::STRING, + 'xml' => Types::TEXT, ]; } @@ -1765,15 +1778,19 @@ private function generateIdentifierName($identifier): string protected function getCommentOnTableSQL(string $tableName, ?string $comment): string { - return sprintf( - <<<'SQL' - EXEC sys.sp_addextendedproperty @name=N'MS_Description', - @value=N%s, @level0type=N'SCHEMA', @level0name=N'dbo', - @level1type=N'TABLE', @level1name=N%s - SQL - , - $this->quoteStringLiteral((string) $comment), - $this->quoteStringLiteral($tableName), + if (str_contains($tableName, '.')) { + [$schemaName, $tableName] = explode('.', $tableName); + } else { + $schemaName = 'dbo'; + } + + return $this->getAddExtendedPropertySQL( + 'MS_Description', + $comment, + 'SCHEMA', + $this->quoteStringLiteral($schemaName), + 'TABLE', + $this->quoteStringLiteral($this->unquoteSingleIdentifier($tableName)), ); } diff --git a/app/vendor/doctrine/dbal/src/Platforms/SqlitePlatform.php b/app/vendor/doctrine/dbal/src/Platforms/SqlitePlatform.php index ea9a44413..b2e1280d0 100644 --- a/app/vendor/doctrine/dbal/src/Platforms/SqlitePlatform.php +++ b/app/vendor/doctrine/dbal/src/Platforms/SqlitePlatform.php @@ -908,7 +908,7 @@ public function getTemporaryTableName($tableName) */ public function canEmulateSchemas() { - Deprecation::trigger( + Deprecation::triggerIfCalledFromOutside( 'doctrine/dbal', 'https://github.com/doctrine/dbal/pull/4805', 'SqlitePlatform::canEmulateSchemas() is deprecated.', @@ -950,11 +950,6 @@ public function getCreateIndexSQL(Index $index, $table) $name = $index->getQuotedName($this); $columns = $index->getColumns(); - if (strpos($table, '.') !== false) { - [$schema, $table] = explode('.', $table); - $name = $schema . '.' . $name; - } - if (count($columns) === 0) { throw new InvalidArgumentException(sprintf( 'Incomplete or invalid index definition %s on table %s', @@ -967,6 +962,11 @@ public function getCreateIndexSQL(Index $index, $table) return $this->getCreatePrimaryKeySQL($index, $table); } + if (strpos($table, '.') !== false) { + [$schema, $table] = explode('.', $table, 2); + $name = $schema . '.' . $name; + } + $query = 'CREATE ' . $this->getCreateIndexSQLFlags($index) . 'INDEX ' . $name . ' ON ' . $table; $query .= ' (' . $this->getIndexFieldDeclarationListSQL($index) . ')' . $this->getPartialIndexSQL($index); @@ -1025,7 +1025,7 @@ public function getCreateConstraintSQL(Constraint $constraint, $table) * {@inheritDoc} * * @param int|null $createFlags - * @psalm-param int-mask-of|null $createFlags + * @phpstan-param int-mask-of|null $createFlags */ public function getCreateTableSQL(Table $table, $createFlags = null) { @@ -1150,7 +1150,12 @@ public function getAlterTableSQL(TableDiff $diff) $sql = []; $tableSql = []; if (! $this->onSchemaAlterTable($diff, $tableSql)) { - $dataTable = new Table('__temp__' . $table->getName()); + $tableName = $table->getName(); + if (strpos($tableName, '.') !== false) { + [, $tableName] = explode('.', $tableName, 2); + } + + $dataTable = new Table('__temp__' . $tableName); $newTable = new Table( $table->getQuotedName($this), diff --git a/app/vendor/doctrine/dbal/src/Portability/Converter.php b/app/vendor/doctrine/dbal/src/Portability/Converter.php index d0503977b..effbf986f 100644 --- a/app/vendor/doctrine/dbal/src/Portability/Converter.php +++ b/app/vendor/doctrine/dbal/src/Portability/Converter.php @@ -151,7 +151,7 @@ private static function convertEmptyStringToNull($value) * @param T $value * * @return T|string - * @psalm-return (T is string ? string : T) + * @phpstan-return (T is string ? string : T) * * @template T */ @@ -228,7 +228,7 @@ private function createConvert(?callable $function, callable $id): callable return /** * @param T $value * - * @psalm-return (T is false ? false : T) + * @phpstan-return (T is false ? false : T) * * @template T */ diff --git a/app/vendor/doctrine/dbal/src/Query.php b/app/vendor/doctrine/dbal/src/Query.php index bfc9b14e2..e4ab80e7c 100644 --- a/app/vendor/doctrine/dbal/src/Query.php +++ b/app/vendor/doctrine/dbal/src/Query.php @@ -8,8 +8,6 @@ /** * An SQL query together with its bound parameters. - * - * @psalm-immutable */ final class Query { @@ -35,8 +33,6 @@ final class Query /** * @param array $params * @param array $types - * - * @psalm-suppress ImpurePropertyAssignment */ public function __construct(string $sql, array $params, array $types) { diff --git a/app/vendor/doctrine/dbal/src/Query/Expression/CompositeExpression.php b/app/vendor/doctrine/dbal/src/Query/Expression/CompositeExpression.php index 4cad8ec1d..c241ff7f2 100644 --- a/app/vendor/doctrine/dbal/src/Query/Expression/CompositeExpression.php +++ b/app/vendor/doctrine/dbal/src/Query/Expression/CompositeExpression.php @@ -149,7 +149,7 @@ public function with($part, ...$parts): self * Retrieves the amount of expressions on composite expression. * * @return int - * @psalm-return int<0, max> + * @phpstan-return int<0, max> */ #[ReturnTypeWillChange] public function count() diff --git a/app/vendor/doctrine/dbal/src/Query/QueryBuilder.php b/app/vendor/doctrine/dbal/src/Query/QueryBuilder.php index f099e756b..208579c93 100644 --- a/app/vendor/doctrine/dbal/src/Query/QueryBuilder.php +++ b/app/vendor/doctrine/dbal/src/Query/QueryBuilder.php @@ -113,14 +113,14 @@ class QueryBuilder /** * The type of query this is. Can be select, update or delete. * - * @psalm-var self::SELECT|self::DELETE|self::UPDATE|self::INSERT + * @phpstan-var self::SELECT|self::DELETE|self::UPDATE|self::INSERT */ private int $type = self::SELECT; /** * The state of the query object. Can be dirty or clean. * - * @psalm-var self::STATE_* + * @phpstan-var self::STATE_* */ private int $state = self::STATE_CLEAN; @@ -219,7 +219,7 @@ public function getConnection() * @deprecated The builder state is an internal concern. * * @return int Either QueryBuilder::STATE_DIRTY or QueryBuilder::STATE_CLEAN. - * @psalm-return self::STATE_* + * @phpstan-return self::STATE_* */ public function getState() { @@ -1734,7 +1734,7 @@ public function __clone() /** * Enables caching of the results of this query, for given amount of seconds - * and optionally specified witch key to use for the cache entry. + * and optionally specified which key to use for the cache entry. * * @return $this */ diff --git a/app/vendor/doctrine/dbal/src/Query/QueryException.php b/app/vendor/doctrine/dbal/src/Query/QueryException.php index 90d1f47d9..bfb5eafc3 100644 --- a/app/vendor/doctrine/dbal/src/Query/QueryException.php +++ b/app/vendor/doctrine/dbal/src/Query/QueryException.php @@ -6,7 +6,6 @@ use function implode; -/** @psalm-immutable */ class QueryException extends Exception { /** diff --git a/app/vendor/doctrine/dbal/src/Result.php b/app/vendor/doctrine/dbal/src/Result.php index fdc7daa94..f63b07f07 100644 --- a/app/vendor/doctrine/dbal/src/Result.php +++ b/app/vendor/doctrine/dbal/src/Result.php @@ -184,7 +184,7 @@ public function iterateAssociative(): Traversable } /** - * {@inheritDoc} + * @return Traversable * * @throws Exception */ @@ -264,7 +264,7 @@ private function ensureHasKeyValue(): void * * @deprecated Use {@see fetchNumeric()}, {@see fetchAssociative()} or {@see fetchOne()} instead. * - * @psalm-param FetchMode::* $mode + * @phpstan-param FetchMode::* $mode * * @return mixed * @@ -303,7 +303,7 @@ public function fetch(int $mode = FetchMode::ASSOCIATIVE) * * @deprecated Use {@see fetchAllNumeric()}, {@see fetchAllAssociative()} or {@see fetchFirstColumn()} instead. * - * @psalm-param FetchMode::* $mode + * @phpstan-param FetchMode::* $mode * * @return list * diff --git a/app/vendor/doctrine/dbal/src/SQL/Builder/CreateSchemaObjectsSQLBuilder.php b/app/vendor/doctrine/dbal/src/SQL/Builder/CreateSchemaObjectsSQLBuilder.php index 2e392e661..74579b3e0 100644 --- a/app/vendor/doctrine/dbal/src/SQL/Builder/CreateSchemaObjectsSQLBuilder.php +++ b/app/vendor/doctrine/dbal/src/SQL/Builder/CreateSchemaObjectsSQLBuilder.php @@ -34,7 +34,7 @@ public function buildSQL(Schema $schema): array } /** - * @param list $namespaces + * @param string[] $namespaces * * @return list * @@ -54,7 +54,7 @@ private function buildNamespaceStatements(array $namespaces): array } /** - * @param list
$tables + * @param Table[] $tables * * @return list * @@ -66,7 +66,7 @@ private function buildTableStatements(array $tables): array } /** - * @param list $sequences + * @param Sequence[] $sequences * * @return list * diff --git a/app/vendor/doctrine/dbal/src/SQL/Parser.php b/app/vendor/doctrine/dbal/src/SQL/Parser.php index ae0d4428f..418af799f 100644 --- a/app/vendor/doctrine/dbal/src/SQL/Parser.php +++ b/app/vendor/doctrine/dbal/src/SQL/Parser.php @@ -7,14 +7,9 @@ use Doctrine\DBAL\SQL\Parser\Visitor; use function array_merge; -use function assert; -use function current; use function implode; -use function key; -use function next; use function preg_last_error; use function preg_match; -use function reset; use function sprintf; use function strlen; @@ -45,6 +40,7 @@ final class Parser private const OTHER = '[^' . self::SPECIAL_CHARS . ']+'; private string $sqlPattern; + private string $tokenPattern; public function __construct(bool $mySQLStringEscaping) { @@ -69,7 +65,12 @@ public function __construct(bool $mySQLStringEscaping) self::OTHER, ]); - $this->sqlPattern = sprintf('(%s)', implode('|', $patterns)); + $this->sqlPattern = sprintf('(%s)', implode('|', $patterns)); + $this->tokenPattern = '~\\G' + . '(?P' . self::NAMED_PARAMETER . ')' + . '|(?P' . self::POSITIONAL_PARAMETER . ')' + . '|(?P' . $this->sqlPattern . '|' . self::SPECIAL . ')' + . '~s'; } /** @@ -79,40 +80,26 @@ public function __construct(bool $mySQLStringEscaping) */ public function parse(string $sql, Visitor $visitor): void { - /** @var array $patterns */ - $patterns = [ - self::NAMED_PARAMETER => static function (string $sql) use ($visitor): void { - $visitor->acceptNamedParameter($sql); - }, - self::POSITIONAL_PARAMETER => static function (string $sql) use ($visitor): void { - $visitor->acceptPositionalParameter($sql); - }, - $this->sqlPattern => static function (string $sql) use ($visitor): void { - $visitor->acceptOther($sql); - }, - self::SPECIAL => static function (string $sql) use ($visitor): void { - $visitor->acceptOther($sql); - }, - ]; - $offset = 0; - - while (($handler = current($patterns)) !== false) { - if (preg_match('~\G' . key($patterns) . '~s', $sql, $matches, 0, $offset) === 1) { - $handler($matches[0]); - reset($patterns); - - $offset += strlen($matches[0]); + $length = strlen($sql); + while ($offset < $length) { + if (preg_match($this->tokenPattern, $sql, $matches, 0, $offset) === 1) { + $match = $matches[0]; + if ($matches['named'] !== '') { + $visitor->acceptNamedParameter($match); + } elseif ($matches['positional'] !== '') { + $visitor->acceptPositionalParameter($match); + } else { + $visitor->acceptOther($match); + } + + $offset += strlen($match); } elseif (preg_last_error() !== PREG_NO_ERROR) { // @codeCoverageIgnoreStart throw RegularExpressionError::new(); // @codeCoverageIgnoreEnd - } else { - next($patterns); } } - - assert($offset === strlen($sql)); } private function getMySQLStringLiteralPattern(string $delimiter): string diff --git a/app/vendor/doctrine/dbal/src/Schema/AbstractAsset.php b/app/vendor/doctrine/dbal/src/Schema/AbstractAsset.php index ab8fdec03..6934133ff 100644 --- a/app/vendor/doctrine/dbal/src/Schema/AbstractAsset.php +++ b/app/vendor/doctrine/dbal/src/Schema/AbstractAsset.php @@ -20,7 +20,8 @@ * The abstract asset allows to reset the name of all assets without publishing this to the public userland. * * This encapsulation hack is necessary to keep a consistent state of the database schema. Say we have a list of tables - * array($tableName => Table($tableName)); if you want to rename the table, you have to make sure + * array($tableName => Table($tableName)); if you want to rename the table, you have to make sure this does not get + * recreated during schema migration. */ abstract class AbstractAsset { diff --git a/app/vendor/doctrine/dbal/src/Schema/AbstractSchemaManager.php b/app/vendor/doctrine/dbal/src/Schema/AbstractSchemaManager.php index 7e1fd93ff..2e38bb88c 100644 --- a/app/vendor/doctrine/dbal/src/Schema/AbstractSchemaManager.php +++ b/app/vendor/doctrine/dbal/src/Schema/AbstractSchemaManager.php @@ -31,7 +31,7 @@ * Base class for schema managers. Schema managers are used to inspect and/or * modify the database schema/structure. * - * @template T of AbstractPlatform + * @template-covariant T of AbstractPlatform */ abstract class AbstractSchemaManager { @@ -1740,6 +1740,10 @@ public function getSchemaSearchPaths() */ public function extractDoctrineTypeFromComment($comment, $currentType) { + if ($this->_conn->getConfiguration()->getDisableTypeComments()) { + return $currentType; + } + if ($comment !== null && preg_match('(\(DC2Type:(((?!\)).)+)\))', $comment, $match) === 1) { return $match[1]; } @@ -1757,6 +1761,10 @@ public function extractDoctrineTypeFromComment($comment, $currentType) */ public function removeDoctrineTypeFromComment($comment, $type) { + if ($this->_conn->getConfiguration()->getDisableTypeComments()) { + return $comment; + } + if ($comment === null) { return null; } diff --git a/app/vendor/doctrine/dbal/src/Schema/Comparator.php b/app/vendor/doctrine/dbal/src/Schema/Comparator.php index 28e7f2f73..8114ec5e2 100644 --- a/app/vendor/doctrine/dbal/src/Schema/Comparator.php +++ b/app/vendor/doctrine/dbal/src/Schema/Comparator.php @@ -636,7 +636,7 @@ public function diffColumn(Column $column1, Column $column2) // null != 0, null != false, null != '' etc. This affects platform's table alteration SQL generation. if ( ($properties1['default'] === null) !== ($properties2['default'] === null) - || $properties1['default'] != $properties2['default'] + || $properties1['default'] != $properties2['default'] // @phpstan-ignore notEqual.notAllowed ) { $changedProperties[] = 'default'; } diff --git a/app/vendor/doctrine/dbal/src/Schema/Exception/ColumnAlreadyExists.php b/app/vendor/doctrine/dbal/src/Schema/Exception/ColumnAlreadyExists.php index cc7acea03..a0d62d20d 100644 --- a/app/vendor/doctrine/dbal/src/Schema/Exception/ColumnAlreadyExists.php +++ b/app/vendor/doctrine/dbal/src/Schema/Exception/ColumnAlreadyExists.php @@ -8,7 +8,6 @@ use function sprintf; -/** @psalm-immutable */ final class ColumnAlreadyExists extends SchemaException { public static function new(string $tableName, string $columnName): self diff --git a/app/vendor/doctrine/dbal/src/Schema/Exception/ColumnDoesNotExist.php b/app/vendor/doctrine/dbal/src/Schema/Exception/ColumnDoesNotExist.php index c9036a07c..7c4bb633c 100644 --- a/app/vendor/doctrine/dbal/src/Schema/Exception/ColumnDoesNotExist.php +++ b/app/vendor/doctrine/dbal/src/Schema/Exception/ColumnDoesNotExist.php @@ -8,7 +8,6 @@ use function sprintf; -/** @psalm-immutable */ final class ColumnDoesNotExist extends SchemaException { public static function new(string $columnName, string $table): self diff --git a/app/vendor/doctrine/dbal/src/Schema/Exception/ForeignKeyDoesNotExist.php b/app/vendor/doctrine/dbal/src/Schema/Exception/ForeignKeyDoesNotExist.php index bf57cd4ff..4833de5c0 100644 --- a/app/vendor/doctrine/dbal/src/Schema/Exception/ForeignKeyDoesNotExist.php +++ b/app/vendor/doctrine/dbal/src/Schema/Exception/ForeignKeyDoesNotExist.php @@ -8,7 +8,6 @@ use function sprintf; -/** @psalm-immutable */ final class ForeignKeyDoesNotExist extends SchemaException { public static function new(string $foreignKeyName, string $table): self diff --git a/app/vendor/doctrine/dbal/src/Schema/Exception/IndexAlreadyExists.php b/app/vendor/doctrine/dbal/src/Schema/Exception/IndexAlreadyExists.php index 25facb58a..292bf81e4 100644 --- a/app/vendor/doctrine/dbal/src/Schema/Exception/IndexAlreadyExists.php +++ b/app/vendor/doctrine/dbal/src/Schema/Exception/IndexAlreadyExists.php @@ -8,7 +8,6 @@ use function sprintf; -/** @psalm-immutable */ final class IndexAlreadyExists extends SchemaException { public static function new(string $indexName, string $table): self diff --git a/app/vendor/doctrine/dbal/src/Schema/Exception/IndexDoesNotExist.php b/app/vendor/doctrine/dbal/src/Schema/Exception/IndexDoesNotExist.php index 9f4024185..526819726 100644 --- a/app/vendor/doctrine/dbal/src/Schema/Exception/IndexDoesNotExist.php +++ b/app/vendor/doctrine/dbal/src/Schema/Exception/IndexDoesNotExist.php @@ -8,7 +8,6 @@ use function sprintf; -/** @psalm-immutable */ final class IndexDoesNotExist extends SchemaException { public static function new(string $indexName, string $table): self diff --git a/app/vendor/doctrine/dbal/src/Schema/Exception/IndexNameInvalid.php b/app/vendor/doctrine/dbal/src/Schema/Exception/IndexNameInvalid.php index 5230f506e..d69b7a930 100644 --- a/app/vendor/doctrine/dbal/src/Schema/Exception/IndexNameInvalid.php +++ b/app/vendor/doctrine/dbal/src/Schema/Exception/IndexNameInvalid.php @@ -8,7 +8,6 @@ use function sprintf; -/** @psalm-immutable */ final class IndexNameInvalid extends SchemaException { public static function new(string $indexName): self diff --git a/app/vendor/doctrine/dbal/src/Schema/Exception/InvalidTableName.php b/app/vendor/doctrine/dbal/src/Schema/Exception/InvalidTableName.php index 50e2d3af9..763e920f6 100644 --- a/app/vendor/doctrine/dbal/src/Schema/Exception/InvalidTableName.php +++ b/app/vendor/doctrine/dbal/src/Schema/Exception/InvalidTableName.php @@ -8,7 +8,6 @@ use function sprintf; -/** @psalm-immutable */ final class InvalidTableName extends SchemaException { public static function new(string $tableName): self diff --git a/app/vendor/doctrine/dbal/src/Schema/Exception/NamedForeignKeyRequired.php b/app/vendor/doctrine/dbal/src/Schema/Exception/NamedForeignKeyRequired.php index 92d237e7a..453286136 100644 --- a/app/vendor/doctrine/dbal/src/Schema/Exception/NamedForeignKeyRequired.php +++ b/app/vendor/doctrine/dbal/src/Schema/Exception/NamedForeignKeyRequired.php @@ -11,7 +11,6 @@ use function implode; use function sprintf; -/** @psalm-immutable */ final class NamedForeignKeyRequired extends SchemaException { public static function new(Table $localTable, ForeignKeyConstraint $foreignKey): self diff --git a/app/vendor/doctrine/dbal/src/Schema/Exception/NamespaceAlreadyExists.php b/app/vendor/doctrine/dbal/src/Schema/Exception/NamespaceAlreadyExists.php index 008bd5f0e..527e196ef 100644 --- a/app/vendor/doctrine/dbal/src/Schema/Exception/NamespaceAlreadyExists.php +++ b/app/vendor/doctrine/dbal/src/Schema/Exception/NamespaceAlreadyExists.php @@ -8,7 +8,6 @@ use function sprintf; -/** @psalm-immutable */ final class NamespaceAlreadyExists extends SchemaException { public static function new(string $namespaceName): self diff --git a/app/vendor/doctrine/dbal/src/Schema/Exception/SequenceAlreadyExists.php b/app/vendor/doctrine/dbal/src/Schema/Exception/SequenceAlreadyExists.php index d719c6a06..206220ef7 100644 --- a/app/vendor/doctrine/dbal/src/Schema/Exception/SequenceAlreadyExists.php +++ b/app/vendor/doctrine/dbal/src/Schema/Exception/SequenceAlreadyExists.php @@ -8,7 +8,6 @@ use function sprintf; -/** @psalm-immutable */ final class SequenceAlreadyExists extends SchemaException { public static function new(string $sequenceName): self diff --git a/app/vendor/doctrine/dbal/src/Schema/Exception/SequenceDoesNotExist.php b/app/vendor/doctrine/dbal/src/Schema/Exception/SequenceDoesNotExist.php index 3f948835c..6b4912d52 100644 --- a/app/vendor/doctrine/dbal/src/Schema/Exception/SequenceDoesNotExist.php +++ b/app/vendor/doctrine/dbal/src/Schema/Exception/SequenceDoesNotExist.php @@ -8,7 +8,6 @@ use function sprintf; -/** @psalm-immutable */ final class SequenceDoesNotExist extends SchemaException { public static function new(string $sequenceName): self diff --git a/app/vendor/doctrine/dbal/src/Schema/Exception/TableAlreadyExists.php b/app/vendor/doctrine/dbal/src/Schema/Exception/TableAlreadyExists.php index d7b235937..c5a64f6b8 100644 --- a/app/vendor/doctrine/dbal/src/Schema/Exception/TableAlreadyExists.php +++ b/app/vendor/doctrine/dbal/src/Schema/Exception/TableAlreadyExists.php @@ -8,7 +8,6 @@ use function sprintf; -/** @psalm-immutable */ final class TableAlreadyExists extends SchemaException { public static function new(string $tableName): self diff --git a/app/vendor/doctrine/dbal/src/Schema/Exception/TableDoesNotExist.php b/app/vendor/doctrine/dbal/src/Schema/Exception/TableDoesNotExist.php index 7c6dda9ab..47c5f0eab 100644 --- a/app/vendor/doctrine/dbal/src/Schema/Exception/TableDoesNotExist.php +++ b/app/vendor/doctrine/dbal/src/Schema/Exception/TableDoesNotExist.php @@ -8,7 +8,6 @@ use function sprintf; -/** @psalm-immutable */ final class TableDoesNotExist extends SchemaException { public static function new(string $tableName): self diff --git a/app/vendor/doctrine/dbal/src/Schema/Exception/UniqueConstraintDoesNotExist.php b/app/vendor/doctrine/dbal/src/Schema/Exception/UniqueConstraintDoesNotExist.php index dad6116c6..0ce19f756 100644 --- a/app/vendor/doctrine/dbal/src/Schema/Exception/UniqueConstraintDoesNotExist.php +++ b/app/vendor/doctrine/dbal/src/Schema/Exception/UniqueConstraintDoesNotExist.php @@ -8,7 +8,6 @@ use function sprintf; -/** @psalm-immutable */ final class UniqueConstraintDoesNotExist extends SchemaException { public static function new(string $constraintName, string $table): self diff --git a/app/vendor/doctrine/dbal/src/Schema/Exception/UnknownColumnOption.php b/app/vendor/doctrine/dbal/src/Schema/Exception/UnknownColumnOption.php index 7a7c6f87a..d128e224f 100644 --- a/app/vendor/doctrine/dbal/src/Schema/Exception/UnknownColumnOption.php +++ b/app/vendor/doctrine/dbal/src/Schema/Exception/UnknownColumnOption.php @@ -8,7 +8,6 @@ use function sprintf; -/** @psalm-immutable */ final class UnknownColumnOption extends SchemaException { public static function new(string $name): self diff --git a/app/vendor/doctrine/dbal/src/Schema/ForeignKeyConstraint.php b/app/vendor/doctrine/dbal/src/Schema/ForeignKeyConstraint.php index 2f0311cd6..dc69c629a 100644 --- a/app/vendor/doctrine/dbal/src/Schema/ForeignKeyConstraint.php +++ b/app/vendor/doctrine/dbal/src/Schema/ForeignKeyConstraint.php @@ -251,6 +251,10 @@ public function getUnqualifiedForeignTableName() $name = substr($name, $position + 1); } + if ($this->isIdentifierQuoted($name)) { + $name = $this->trimQuotes($name); + } + return strtolower($name); } diff --git a/app/vendor/doctrine/dbal/src/Schema/MySQLSchemaManager.php b/app/vendor/doctrine/dbal/src/Schema/MySQLSchemaManager.php index 3c00d00e2..6e444d213 100644 --- a/app/vendor/doctrine/dbal/src/Schema/MySQLSchemaManager.php +++ b/app/vendor/doctrine/dbal/src/Schema/MySQLSchemaManager.php @@ -557,31 +557,13 @@ protected function selectForeignKeyColumns(string $databaseName, ?string $tableN */ protected function fetchTableOptionsByTable(string $databaseName, ?string $tableName = null): array { - $sql = <<<'SQL' - SELECT t.TABLE_NAME, - t.ENGINE, - t.AUTO_INCREMENT, - t.TABLE_COMMENT, - t.CREATE_OPTIONS, - t.TABLE_COLLATION, - ccsa.CHARACTER_SET_NAME - FROM information_schema.TABLES t - INNER JOIN information_schema.COLLATION_CHARACTER_SET_APPLICABILITY ccsa - ON ccsa.COLLATION_NAME = t.TABLE_COLLATION -SQL; - - $conditions = ['t.TABLE_SCHEMA = ?']; - $params = [$databaseName]; + $sql = $this->_platform->fetchTableOptionsByTable($tableName !== null); + $params = [$databaseName]; if ($tableName !== null) { - $conditions[] = 't.TABLE_NAME = ?'; - $params[] = $tableName; + $params[] = $tableName; } - $conditions[] = "t.TABLE_TYPE = 'BASE TABLE'"; - - $sql .= ' WHERE ' . implode(' AND ', $conditions); - /** @var array> $metadata */ $metadata = $this->_conn->executeQuery($sql, $params) ->fetchAllAssociativeIndexed(); diff --git a/app/vendor/doctrine/dbal/src/Schema/OracleSchemaManager.php b/app/vendor/doctrine/dbal/src/Schema/OracleSchemaManager.php index 073752214..3608e0566 100644 --- a/app/vendor/doctrine/dbal/src/Schema/OracleSchemaManager.php +++ b/app/vendor/doctrine/dbal/src/Schema/OracleSchemaManager.php @@ -107,8 +107,6 @@ protected function _getPortableTableDefinition($table) /** * {@inheritDoc} - * - * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html */ protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) { diff --git a/app/vendor/doctrine/dbal/src/Schema/PostgreSQLSchemaManager.php b/app/vendor/doctrine/dbal/src/Schema/PostgreSQLSchemaManager.php index 13fde63b2..0510d1a82 100644 --- a/app/vendor/doctrine/dbal/src/Schema/PostgreSQLSchemaManager.php +++ b/app/vendor/doctrine/dbal/src/Schema/PostgreSQLSchemaManager.php @@ -287,8 +287,6 @@ protected function _getPortableTableDefinition($table) /** * {@inheritDoc} - * - * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html */ protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) { @@ -296,9 +294,16 @@ protected function _getPortableTableIndexesList($tableIndexes, $tableName = null foreach ($tableIndexes as $row) { $colNumbers = array_map('intval', explode(' ', $row['indkey'])); $columnNameSql = sprintf( - 'SELECT attnum, attname FROM pg_attribute WHERE attrelid=%d AND attnum IN (%s) ORDER BY attnum ASC', + <<<'SQL' + SELECT attnum, + quote_ident(attname) AS attname + FROM pg_attribute + WHERE attrelid = %d + AND attnum IN (%s) + ORDER BY attnum + SQL, $row['indrelid'], - implode(' ,', $colNumbers), + implode(', ', $colNumbers), ); $indexColumns = $this->_conn->fetchAllAssociative($columnNameSql); @@ -463,6 +468,7 @@ protected function _getPortableTableColumnDefinition($tableColumn) $length = null; break; + case 'json': case 'text': case '_varchar': case 'varchar': @@ -603,6 +609,8 @@ protected function selectTableNames(string $databaseName): Result AND table_name != 'geometry_columns' AND table_name != 'spatial_ref_sys' AND table_type = 'BASE TABLE' +ORDER BY + quote_ident(table_name) SQL; return $this->_conn->executeQuery($sql, [$databaseName]); @@ -613,10 +621,10 @@ protected function selectTableColumns(string $databaseName, ?string $tableName = $sql = 'SELECT'; if ($tableName === null) { - $sql .= ' c.relname AS table_name, n.nspname AS schema_name,'; + $sql .= ' quote_ident(c.relname) AS table_name, quote_ident(n.nspname) AS schema_name,'; } - $sql .= <<<'SQL' + $sql .= sprintf(<<<'SQL' a.attnum, quote_ident(a.attname) AS field, t.typname AS type, @@ -632,11 +640,7 @@ protected function selectTableColumns(string $databaseName, ?string $tableName = AND pg_index.indkey[0] = a.attnum AND pg_index.indisprimary = 't' ) AS pri, - (SELECT pg_get_expr(adbin, adrelid) - FROM pg_attrdef - WHERE c.oid = pg_attrdef.adrelid - AND pg_attrdef.adnum=a.attnum - ) AS default, + (%s) AS default, (SELECT pg_description.description FROM pg_description WHERE pg_description.objoid = c.oid AND a.attnum = pg_description.objsubid ) AS comment @@ -651,7 +655,7 @@ protected function selectTableColumns(string $databaseName, ?string $tableName = ON d.objid = c.oid AND d.deptype = 'e' AND d.classid = (SELECT oid FROM pg_class WHERE relname = 'pg_class') -SQL; +SQL, $this->_platform->getDefaultColumnValueSQLSnippet()); $conditions = array_merge([ 'a.attnum > 0', @@ -669,7 +673,7 @@ protected function selectIndexColumns(string $databaseName, ?string $tableName = $sql = 'SELECT'; if ($tableName === null) { - $sql .= ' tc.relname AS table_name, tn.nspname AS schema_name,'; + $sql .= ' quote_ident(tc.relname) AS table_name, quote_ident(tn.nspname) AS schema_name,'; } $sql .= <<<'SQL' @@ -693,7 +697,7 @@ protected function selectIndexColumns(string $databaseName, ?string $tableName = 'c.relnamespace = n.oid', ], $this->buildQueryConditions($tableName)); - $sql .= ' WHERE ' . implode(' AND ', $conditions) . ')'; + $sql .= ' WHERE ' . implode(' AND ', $conditions) . ') ORDER BY quote_ident(ic.relname)'; return $this->_conn->executeQuery($sql); } @@ -703,7 +707,7 @@ protected function selectForeignKeyColumns(string $databaseName, ?string $tableN $sql = 'SELECT'; if ($tableName === null) { - $sql .= ' tc.relname AS table_name, tn.nspname AS schema_name,'; + $sql .= ' quote_ident(tc.relname) AS table_name, quote_ident(tn.nspname) AS schema_name,'; } $sql .= <<<'SQL' @@ -720,7 +724,7 @@ protected function selectForeignKeyColumns(string $databaseName, ?string $tableN $conditions = array_merge(['n.oid = c.relnamespace'], $this->buildQueryConditions($tableName)); - $sql .= ' WHERE ' . implode(' AND ', $conditions) . ") AND r.contype = 'f'"; + $sql .= ' WHERE ' . implode(' AND ', $conditions) . ") AND r.contype = 'f' ORDER BY quote_ident(r.conname)"; return $this->_conn->executeQuery($sql); } @@ -731,7 +735,8 @@ protected function selectForeignKeyColumns(string $databaseName, ?string $tableN protected function fetchTableOptionsByTable(string $databaseName, ?string $tableName = null): array { $sql = <<<'SQL' -SELECT c.relname, +SELECT n.nspname AS schema_name, + c.relname AS table_name, CASE c.relpersistence WHEN 'u' THEN true ELSE false END as unlogged, obj_description(c.oid, 'pg_class') AS comment FROM pg_class c @@ -743,7 +748,12 @@ protected function fetchTableOptionsByTable(string $databaseName, ?string $table $sql .= ' WHERE ' . implode(' AND ', $conditions); - return $this->_conn->fetchAllAssociativeIndexed($sql); + $tableOptions = []; + foreach ($this->_conn->iterateAssociative($sql) as $row) { + $tableOptions[$this->_getPortableTableDefinition($row)] = $row; + } + + return $tableOptions; } /** diff --git a/app/vendor/doctrine/dbal/src/Schema/SQLServerSchemaManager.php b/app/vendor/doctrine/dbal/src/Schema/SQLServerSchemaManager.php index acef511ab..e82ccded1 100644 --- a/app/vendor/doctrine/dbal/src/Schema/SQLServerSchemaManager.php +++ b/app/vendor/doctrine/dbal/src/Schema/SQLServerSchemaManager.php @@ -197,7 +197,7 @@ protected function _getPortableTableColumnDefinition($tableColumn) private function parseDefaultExpression(string $value): ?string { - while (preg_match('/^\((.*)\)$/s', $value, $matches)) { + while (preg_match('/^\((.*)\)$/s', $value, $matches) === 1) { $value = $matches[1]; } @@ -227,9 +227,15 @@ protected function _getPortableTableForeignKeysList($tableForeignKeys) $name = $tableForeignKey['ForeignKey']; if (! isset($foreignKeys[$name])) { + $referencedTableName = $tableForeignKey['ReferenceTableName']; + + if ($tableForeignKey['ReferenceSchemaName'] !== 'dbo') { + $referencedTableName = $tableForeignKey['ReferenceSchemaName'] . '.' . $referencedTableName; + } + $foreignKeys[$name] = [ 'local_columns' => [$tableForeignKey['ColumnName']], - 'foreign_table' => $tableForeignKey['ReferenceTableName'], + 'foreign_table' => $referencedTableName, 'foreign_columns' => [$tableForeignKey['ReferenceColumnName']], 'name' => $name, 'options' => [ @@ -556,31 +562,29 @@ protected function fetchTableOptionsByTable(string $databaseName, ?string $table { $sql = <<<'SQL' SELECT - tbl.name, + scm.name AS schema_name, + tbl.name AS table_name, p.value AS [table_comment] FROM sys.tables AS tbl + JOIN sys.schemas AS scm + ON tbl.schema_id = scm.schema_id INNER JOIN sys.extended_properties AS p ON p.major_id=tbl.object_id AND p.minor_id=0 AND p.class=1 SQL; - $conditions = ["SCHEMA_NAME(tbl.schema_id) = N'dbo'", "p.name = N'MS_Description'"]; - $params = []; + $conditions = ["p.name = N'MS_Description'"]; if ($tableName !== null) { - $conditions[] = "tbl.name = N'" . $tableName . "'"; + $conditions[] = $this->getTableWhereClause($tableName, 'scm.name', 'tbl.name'); } $sql .= ' WHERE ' . implode(' AND ', $conditions); - /** @var array> $metadata */ - $metadata = $this->_conn->executeQuery($sql, $params) - ->fetchAllAssociativeIndexed(); - $tableOptions = []; - foreach ($metadata as $table => $data) { + foreach ($this->_conn->iterateAssociative($sql) as $data) { $data = array_change_key_case($data, CASE_LOWER); - $tableOptions[$table] = [ + $tableOptions[$this->_getPortableTableDefinition($data)] = [ 'comment' => $data['table_comment'], ]; } diff --git a/app/vendor/doctrine/dbal/src/Schema/SchemaException.php b/app/vendor/doctrine/dbal/src/Schema/SchemaException.php index 4ec091f8d..24a9dd346 100644 --- a/app/vendor/doctrine/dbal/src/Schema/SchemaException.php +++ b/app/vendor/doctrine/dbal/src/Schema/SchemaException.php @@ -19,7 +19,6 @@ use function sprintf; -/** @psalm-immutable */ class SchemaException extends Exception { /** @deprecated Use {@see TableDoesNotExist} instead. */ diff --git a/app/vendor/doctrine/dbal/src/Schema/SqliteSchemaManager.php b/app/vendor/doctrine/dbal/src/Schema/SqliteSchemaManager.php index 13f5c5147..4b96739e1 100644 --- a/app/vendor/doctrine/dbal/src/Schema/SqliteSchemaManager.php +++ b/app/vendor/doctrine/dbal/src/Schema/SqliteSchemaManager.php @@ -202,7 +202,7 @@ public function listTableForeignKeys($table, $database = null) { $table = $this->normalizeName($table); - $columns = $this->selectForeignKeyColumns('', $table) + $columns = $this->selectForeignKeyColumns($database ?? 'main', $table) ->fetchAllAssociative(); if (count($columns) > 0) { @@ -222,8 +222,6 @@ protected function _getPortableTableDefinition($table) /** * {@inheritDoc} - * - * @link http://ezcomponents.org/docs/api/trunk/DatabaseSchema/ezcDbSchemaPgsqlReader.html */ protected function _getPortableTableIndexesList($tableIndexes, $tableName = null) { @@ -510,9 +508,8 @@ protected function _getPortableTableForeignKeyDefinition($tableForeignKey): Fore private function parseColumnCollationFromSQL(string $column, string $sql): ?string { - $pattern = '{(?:\W' . preg_quote($column) . '\W|\W' - . preg_quote($this->_platform->quoteSingleIdentifier($column)) - . '\W)[^,(]+(?:\([^()]+\)[^,]*)?(?:(?:DEFAULT|CHECK)\s*(?:\(.*?\))?[^,]*)*COLLATE\s+["\']?([^\s,"\')]+)}is'; + $pattern = '{' . $this->buildIdentifierPattern($column) + . '[^,(]+(?:\([^()]+\)[^,]*)?(?:(?:DEFAULT|CHECK)\s*(?:\(.*?\))?[^,]*)*COLLATE\s+["\']?([^\s,"\')]+)}is'; if (preg_match($pattern, $sql, $match) !== 1) { return null; @@ -524,9 +521,7 @@ private function parseColumnCollationFromSQL(string $column, string $sql): ?stri private function parseTableCommentFromSQL(string $table, string $sql): ?string { $pattern = '/\s* # Allow whitespace characters at start of line -CREATE\sTABLE # Match "CREATE TABLE" -(?:\W"' . preg_quote($this->_platform->quoteSingleIdentifier($table), '/') . '"\W|\W' . preg_quote($table, '/') - . '\W) # Match table name (quoted and unquoted) +CREATE\sTABLE' . $this->buildIdentifierPattern($table) . ' ( # Start capture (?:\s*--[^\n]*\n?)+ # Capture anything that starts with whitespaces followed by -- until the end of the line(s) )/ix'; @@ -542,8 +537,8 @@ private function parseTableCommentFromSQL(string $table, string $sql): ?string private function parseColumnCommentFromSQL(string $column, string $sql): ?string { - $pattern = '{[\s(,](?:\W' . preg_quote($this->_platform->quoteSingleIdentifier($column)) - . '\W|\W' . preg_quote($column) . '\W)(?:\([^)]*?\)|[^,(])*?,?((?:(?!\n))(?:\s*--[^\n]*\n?)+)}i'; + $pattern = '{[\s(,]' . $this->buildIdentifierPattern($column) + . '(?:\([^)]*?\)|[^,(])*?,?((?:(?!\n))(?:\s*--[^\n]*\n?)+)}i'; if (preg_match($pattern, $sql, $match) !== 1) { return null; @@ -554,6 +549,22 @@ private function parseColumnCommentFromSQL(string $column, string $sql): ?string return $comment === '' ? null : $comment; } + /** + * Returns a regular expression pattern that matches the given unquoted or quoted identifier. + */ + private function buildIdentifierPattern(string $identifier): string + { + return '(?:' . implode('|', array_map( + static function (string $sql): string { + return '\W' . preg_quote($sql, '/') . '\W'; + }, + [ + $identifier, + $this->_platform->quoteSingleIdentifier($identifier), + ], + )) . ')'; + } + /** @throws Exception */ private function getCreateTableSQL(string $table): string { @@ -704,7 +715,9 @@ protected function selectTableColumns(string $databaseName, ?string $tableName = if ($tableName !== null) { $conditions[] = 't.name = ?'; - $params[] = str_replace('.', '__', $tableName); + $params[] = $this->_platform->canEmulateSchemas() + ? str_replace('.', '__', $tableName) + : $tableName; } $sql .= ' WHERE ' . implode(' AND ', $conditions) . ' ORDER BY t.name, c.cid'; @@ -729,7 +742,9 @@ protected function selectIndexColumns(string $databaseName, ?string $tableName = if ($tableName !== null) { $conditions[] = 't.name = ?'; - $params[] = str_replace('.', '__', $tableName); + $params[] = $this->_platform->canEmulateSchemas() + ? str_replace('.', '__', $tableName) + : $tableName; } $sql .= ' WHERE ' . implode(' AND ', $conditions) . ' ORDER BY t.name, i.seq'; @@ -744,7 +759,7 @@ protected function selectForeignKeyColumns(string $databaseName, ?string $tableN p.* FROM sqlite_master t JOIN pragma_foreign_key_list(t.name) p - ON p."seq" != "-1" + ON p."seq" != '-1' SQL; $conditions = [ @@ -755,7 +770,9 @@ protected function selectForeignKeyColumns(string $databaseName, ?string $tableN if ($tableName !== null) { $conditions[] = 't.name = ?'; - $params[] = str_replace('.', '__', $tableName); + $params[] = $this->_platform->canEmulateSchemas() + ? str_replace('.', '__', $tableName) + : $tableName; } $sql .= ' WHERE ' . implode(' AND ', $conditions) . ' ORDER BY t.name, p.id DESC, p.seq'; diff --git a/app/vendor/doctrine/dbal/src/Tools/Console/Command/ReservedWordsCommand.php b/app/vendor/doctrine/dbal/src/Tools/Console/Command/ReservedWordsCommand.php index e63315466..2204b2e2a 100644 --- a/app/vendor/doctrine/dbal/src/Tools/Console/Command/ReservedWordsCommand.php +++ b/app/vendor/doctrine/dbal/src/Tools/Console/Command/ReservedWordsCommand.php @@ -9,6 +9,7 @@ use Doctrine\DBAL\Platforms\Keywords\MariaDb102Keywords; use Doctrine\DBAL\Platforms\Keywords\MySQL57Keywords; use Doctrine\DBAL\Platforms\Keywords\MySQL80Keywords; +use Doctrine\DBAL\Platforms\Keywords\MySQL84Keywords; use Doctrine\DBAL\Platforms\Keywords\MySQLKeywords; use Doctrine\DBAL\Platforms\Keywords\OracleKeywords; use Doctrine\DBAL\Platforms\Keywords\PostgreSQL100Keywords; @@ -59,6 +60,7 @@ public function __construct(ConnectionProvider $connectionProvider) 'mysql' => new MySQLKeywords(), 'mysql57' => new MySQL57Keywords(), 'mysql80' => new MySQL80Keywords(), + 'mysql84' => new MySQL84Keywords(), 'oracle' => new OracleKeywords(), 'pgsql' => new PostgreSQL94Keywords(), 'pgsql100' => new PostgreSQL100Keywords(), @@ -130,6 +132,7 @@ protected function configure() * mysql * mysql57 * mysql80 + * mysql84 * oracle * pgsql * pgsql100 diff --git a/app/vendor/doctrine/dbal/src/Tools/DsnParser.php b/app/vendor/doctrine/dbal/src/Tools/DsnParser.php index 4ac0484d1..753701491 100644 --- a/app/vendor/doctrine/dbal/src/Tools/DsnParser.php +++ b/app/vendor/doctrine/dbal/src/Tools/DsnParser.php @@ -19,7 +19,7 @@ use function strpos; use function substr; -/** @psalm-import-type Params from DriverManager */ +/** @phpstan-import-type Params from DriverManager */ final class DsnParser { /** @var array> */ @@ -32,7 +32,7 @@ public function __construct(array $schemeMapping = []) } /** - * @psalm-return Params + * @phpstan-return Params * * @throws MalformedDsnException */ diff --git a/app/vendor/doctrine/dbal/src/Types/ConversionException.php b/app/vendor/doctrine/dbal/src/Types/ConversionException.php index 154b06d3e..2401aaeb9 100644 --- a/app/vendor/doctrine/dbal/src/Types/ConversionException.php +++ b/app/vendor/doctrine/dbal/src/Types/ConversionException.php @@ -19,8 +19,6 @@ /** * Conversion Exception is thrown when the database to PHP conversion fails. - * - * @psalm-immutable */ class ConversionException extends Exception { diff --git a/app/vendor/doctrine/dbal/src/Types/DateTimeTzImmutableType.php b/app/vendor/doctrine/dbal/src/Types/DateTimeTzImmutableType.php index e700f68d4..70f2c78b6 100644 --- a/app/vendor/doctrine/dbal/src/Types/DateTimeTzImmutableType.php +++ b/app/vendor/doctrine/dbal/src/Types/DateTimeTzImmutableType.php @@ -22,7 +22,7 @@ public function getName() /** * {@inheritDoc} * - * @psalm-param T $value + * @phpstan-param T $value * * @return (T is null ? null : string) * diff --git a/app/vendor/doctrine/dbal/src/Types/DateTimeTzType.php b/app/vendor/doctrine/dbal/src/Types/DateTimeTzType.php index 1980fd334..b3b5db813 100644 --- a/app/vendor/doctrine/dbal/src/Types/DateTimeTzType.php +++ b/app/vendor/doctrine/dbal/src/Types/DateTimeTzType.php @@ -11,18 +11,19 @@ use function get_class; /** - * DateTime type saving additional timezone information. + * DateTime type accepting additional information about timezone offsets. * * Caution: Databases are not necessarily experts at storing timezone related - * data of dates. First, of all the supported vendors only PostgreSQL and Oracle - * support storing Timezone data. But those two don't save the actual timezone - * attached to a DateTime instance (for example "Europe/Berlin" or "America/Montreal") - * but the current offset of them related to UTC. That means depending on daylight saving times - * or not you may get different offsets. + * data of dates. First, of not all the supported vendors support storing Timezone data, and some of + * them only use the offset to calculate the timestamp in its default timezone (usually UTC) and persist + * the value without the offset information. They even don't save the actual timezone names attached + * to a DateTime instance (for example "Europe/Berlin" or "America/Montreal") but the current offset + * of them related to UTC. That means, depending on daylight saving times or not, you may get different + * offsets. * - * This datatype makes only sense to use, if your application works with an offset, not - * with an actual timezone that uses transitions. Otherwise your DateTime instance - * attached with a timezone such as Europe/Berlin gets saved into the database with + * This datatype makes only sense to use, if your application only needs to accept the timezone offset, + * not the actual timezone that uses transitions. Otherwise your DateTime instance + * attached with a timezone such as "Europe/Berlin" gets saved into the database with * the offset and re-created from persistence with only the offset, not the original timezone * attached. */ diff --git a/app/vendor/doctrine/dbal/src/Types/DateType.php b/app/vendor/doctrine/dbal/src/Types/DateType.php index 842e8bd09..86a5ab1ec 100644 --- a/app/vendor/doctrine/dbal/src/Types/DateType.php +++ b/app/vendor/doctrine/dbal/src/Types/DateType.php @@ -34,7 +34,7 @@ public function getSQLDeclaration(array $column, AbstractPlatform $platform) /** * {@inheritDoc} * - * @psalm-param T $value + * @phpstan-param T $value * * @return (T is null ? null : string) * diff --git a/app/vendor/doctrine/deprecations/README.md b/app/vendor/doctrine/deprecations/README.md index 93caf83f8..8b806d1f0 100644 --- a/app/vendor/doctrine/deprecations/README.md +++ b/app/vendor/doctrine/deprecations/README.md @@ -150,6 +150,67 @@ class MyTest extends TestCase } ``` +## Displaying deprecations after running a PHPUnit test suite + +It is possible to integrate this library with PHPUnit to display all +deprecations triggered during the test suite execution. + +```xml + + + + + + + + + + + + src + + + +``` + +Note that you can still trigger Deprecations in your code, provided you use the +`#[WithoutErrorHandler]` attribute to disable PHPUnit's error handler for tests +that call it. Be wary that this will disable all error handling, meaning it +will mask any warnings or errors that would otherwise be caught by PHPUnit. + +At the moment, it is not possible to disable deduplication with an environment +variable, but you can use a bootstrap file to achieve that: + +```php +// tests/bootstrap.php + + … + +``` + ## What is a deprecation identifier? An identifier for deprecations is just a link to any resource, most often a diff --git a/app/vendor/doctrine/deprecations/composer.json b/app/vendor/doctrine/deprecations/composer.json index f8319f9a2..91ba9e653 100644 --- a/app/vendor/doctrine/deprecations/composer.json +++ b/app/vendor/doctrine/deprecations/composer.json @@ -8,20 +8,21 @@ "php": "^7.1 || ^8.0" }, "require-dev": { - "doctrine/coding-standard": "^9", - "phpstan/phpstan": "1.4.10 || 1.10.15", - "phpstan/phpstan-phpunit": "^1.0", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "psalm/plugin-phpunit": "0.18.4", - "psr/log": "^1 || ^2 || ^3", - "vimeo/psalm": "4.30.0 || 5.12.0" + "doctrine/coding-standard": "^9 || ^12 || ^13", + "phpstan/phpstan": "1.4.10 || 2.1.11", + "phpstan/phpstan-phpunit": "^1.0 || ^2", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12", + "psr/log": "^1 || ^2 || ^3" + }, + "conflict": { + "phpunit/phpunit": "<=7.5 || >=13" }, "suggest": { "psr/log": "Allows logging deprecations via PSR-3 logger implementation" }, "autoload": { "psr-4": { - "Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations" + "Doctrine\\Deprecations\\": "src" } }, "autoload-dev": { diff --git a/app/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/Deprecation.php b/app/vendor/doctrine/deprecations/src/Deprecation.php similarity index 95% rename from app/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/Deprecation.php rename to app/vendor/doctrine/deprecations/src/Deprecation.php index bad5070ad..1801e6c7c 100644 --- a/app/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/Deprecation.php +++ b/app/vendor/doctrine/deprecations/src/Deprecation.php @@ -173,9 +173,7 @@ public static function triggerIfCalledFromOutside(string $package, string $link, self::delegateTriggerToBackend($message, $backtrace, $link, $package); } - /** - * @param list $backtrace - */ + /** @param list $backtrace */ private static function delegateTriggerToBackend(string $message, array $backtrace, string $link, string $package): void { $type = self::$type ?? self::getTypeFromEnv(); @@ -226,19 +224,19 @@ private static function basename(string $filename): string public static function enableTrackingDeprecations(): void { - self::$type = self::$type ?? 0; + self::$type = self::$type ?? self::getTypeFromEnv(); self::$type |= self::TYPE_TRACK_DEPRECATIONS; } public static function enableWithTriggerError(): void { - self::$type = self::$type ?? 0; + self::$type = self::$type ?? self::getTypeFromEnv(); self::$type |= self::TYPE_TRIGGER_ERROR; } public static function enableWithPsrLogger(LoggerInterface $logger): void { - self::$type = self::$type ?? 0; + self::$type = self::$type ?? self::getTypeFromEnv(); self::$type |= self::TYPE_PSR_LOGGER; self::$logger = $logger; } @@ -289,9 +287,7 @@ public static function getTriggeredDeprecations(): array return self::$triggeredDeprecations; } - /** - * @return int-mask-of - */ + /** @return int-mask-of */ private static function getTypeFromEnv(): int { switch ($_SERVER['DOCTRINE_DEPRECATIONS'] ?? $_ENV['DOCTRINE_DEPRECATIONS'] ?? null) { diff --git a/app/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/PHPUnit/VerifyDeprecations.php b/app/vendor/doctrine/deprecations/src/PHPUnit/VerifyDeprecations.php similarity index 92% rename from app/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/PHPUnit/VerifyDeprecations.php rename to app/vendor/doctrine/deprecations/src/PHPUnit/VerifyDeprecations.php index 4c3366a97..a6c7ad6fb 100644 --- a/app/vendor/doctrine/deprecations/lib/Doctrine/Deprecations/PHPUnit/VerifyDeprecations.php +++ b/app/vendor/doctrine/deprecations/src/PHPUnit/VerifyDeprecations.php @@ -5,6 +5,8 @@ namespace Doctrine\Deprecations\PHPUnit; use Doctrine\Deprecations\Deprecation; +use PHPUnit\Framework\Attributes\After; +use PHPUnit\Framework\Attributes\Before; use function sprintf; @@ -26,17 +28,15 @@ public function expectNoDeprecationWithIdentifier(string $identifier): void $this->doctrineNoDeprecationsExpectations[$identifier] = Deprecation::getTriggeredDeprecations()[$identifier] ?? 0; } - /** - * @before - */ + /** @before */ + #[Before] public function enableDeprecationTracking(): void { Deprecation::enableTrackingDeprecations(); } - /** - * @after - */ + /** @after */ + #[After] public function verifyDeprecationsAreTriggered(): void { foreach ($this->doctrineDeprecationsExpectations as $identifier => $expectation) { diff --git a/app/vendor/doctrine/event-manager/composer.json b/app/vendor/doctrine/event-manager/composer.json index 756e93dbd..4ea788b44 100644 --- a/app/vendor/doctrine/event-manager/composer.json +++ b/app/vendor/doctrine/event-manager/composer.json @@ -41,10 +41,10 @@ "php": "^8.1" }, "require-dev": { - "doctrine/coding-standard": "^10", + "doctrine/coding-standard": "^12", "phpstan/phpstan": "^1.8.8", - "phpunit/phpunit": "^9.5", - "vimeo/psalm": "^4.28" + "phpunit/phpunit": "^10.5", + "vimeo/psalm": "^5.24" }, "conflict": { "doctrine/common": "<2.9" diff --git a/app/vendor/doctrine/event-manager/phpstan.neon.dist b/app/vendor/doctrine/event-manager/phpstan.neon.dist deleted file mode 100644 index 1517ec8c4..000000000 --- a/app/vendor/doctrine/event-manager/phpstan.neon.dist +++ /dev/null @@ -1,5 +0,0 @@ -parameters: - level: 9 - paths: - - src/ - - tests/ diff --git a/app/vendor/doctrine/event-manager/psalm-baseline.xml b/app/vendor/doctrine/event-manager/psalm-baseline.xml new file mode 100644 index 000000000..bc48ad847 --- /dev/null +++ b/app/vendor/doctrine/event-manager/psalm-baseline.xml @@ -0,0 +1,8 @@ + + + + + listeners[$event])]]> + + + diff --git a/app/vendor/doctrine/event-manager/psalm.xml b/app/vendor/doctrine/event-manager/psalm.xml deleted file mode 100644 index 4e9226bdb..000000000 --- a/app/vendor/doctrine/event-manager/psalm.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - diff --git a/app/vendor/doctrine/sql-formatter/CONTRIBUTING.md b/app/vendor/doctrine/sql-formatter/CONTRIBUTING.md index 31aa160f3..a7a6ce7d3 100644 --- a/app/vendor/doctrine/sql-formatter/CONTRIBUTING.md +++ b/app/vendor/doctrine/sql-formatter/CONTRIBUTING.md @@ -8,7 +8,6 @@ Make sure you read our [contributing guide][contributing guide on the website]. ```shell composer install -composer bin all install ``` ## Running checks locally @@ -18,7 +17,6 @@ Here is a script to run all checks, you can use it as a git hook: ```shell #!/bin/bash -eu vendor/bin/phpunit --testdox -vendor/bin/psalm echo '' | vendor/bin/phpcs vendor/bin/phpstan analyze ``` diff --git a/app/vendor/doctrine/sql-formatter/composer.json b/app/vendor/doctrine/sql-formatter/composer.json index d95f87549..d02639a49 100644 --- a/app/vendor/doctrine/sql-formatter/composer.json +++ b/app/vendor/doctrine/sql-formatter/composer.json @@ -6,10 +6,13 @@ "license": "MIT", "type": "library", "require": { - "php": "^7.1 || ^8.0" + "php": "^8.1" }, "require-dev": { - "bamarni/composer-bin-plugin": "^1.4" + "doctrine/coding-standard": "^12", + "ergebnis/phpunit-slow-test-detector": "^2.14", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.5" }, "authors": [ { @@ -29,12 +32,9 @@ } }, "config": { - "allow-plugins": { - "bamarni/composer-bin-plugin": true - }, "sort-packages": true, - "platform": { - "php": "7.1.0" + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true } }, "bin": ["bin/sql-formatter"] diff --git a/app/vendor/doctrine/sql-formatter/src/CliHighlighter.php b/app/vendor/doctrine/sql-formatter/src/CliHighlighter.php index c5f388996..524b3ba5e 100644 --- a/app/vendor/doctrine/sql-formatter/src/CliHighlighter.php +++ b/app/vendor/doctrine/sql-formatter/src/CliHighlighter.php @@ -6,18 +6,14 @@ use function sprintf; -use const PHP_EOL; - final class CliHighlighter implements Highlighter { public const HIGHLIGHT_FUNCTIONS = 'functions'; /** @var array */ - private $escapeSequences; + private array $escapeSequences; - /** - * @param array $escapeSequences - */ + /** @param array $escapeSequences */ public function __construct(array $escapeSequences = []) { $this->escapeSequences = $escapeSequences + [ @@ -48,7 +44,8 @@ public function highlightToken(int $type, string $value): string return $prefix . $value . "\x1b[0m"; } - private function prefix(int $type): ?string + /** @param Token::TOKEN_TYPE_* $type */ + private function prefix(int $type): string|null { if (! isset(self::TOKEN_TYPE_TO_HIGHLIGHT[$type])) { return null; @@ -61,10 +58,10 @@ public function highlightError(string $value): string { return sprintf( '%s%s%s%s', - PHP_EOL, + "\n", $this->escapeSequences[self::HIGHLIGHT_ERROR], $value, - "\x1b[0m" + "\x1b[0m", ); } diff --git a/app/vendor/doctrine/sql-formatter/src/Cursor.php b/app/vendor/doctrine/sql-formatter/src/Cursor.php index 0b54a6699..1b203dbeb 100644 --- a/app/vendor/doctrine/sql-formatter/src/Cursor.php +++ b/app/vendor/doctrine/sql-formatter/src/Cursor.php @@ -6,21 +6,16 @@ final class Cursor { - /** @var int */ - private $position = -1; + private int $position = -1; - /** @var Token[] */ - private $tokens; - - /** - * @param Token[] $tokens - */ - public function __construct(array $tokens) - { - $this->tokens = $tokens; + /** @param list $tokens */ + public function __construct( + private readonly array $tokens, + ) { } - public function next(?int $exceptTokenType = null): ?Token + /** @param Token::TOKEN_TYPE_* $exceptTokenType */ + public function next(int|null $exceptTokenType = null): Token|null { while ($token = $this->tokens[++$this->position] ?? null) { if ($exceptTokenType !== null && $token->isOfType($exceptTokenType)) { @@ -33,7 +28,8 @@ public function next(?int $exceptTokenType = null): ?Token return null; } - public function previous(?int $exceptTokenType = null): ?Token + /** @param Token::TOKEN_TYPE_* $exceptTokenType */ + public function previous(int|null $exceptTokenType = null): Token|null { while ($token = $this->tokens[--$this->position] ?? null) { if ($exceptTokenType !== null && $token->isOfType($exceptTokenType)) { diff --git a/app/vendor/doctrine/sql-formatter/src/Highlighter.php b/app/vendor/doctrine/sql-formatter/src/Highlighter.php index 02c5c97fd..c232883ab 100644 --- a/app/vendor/doctrine/sql-formatter/src/Highlighter.php +++ b/app/vendor/doctrine/sql-formatter/src/Highlighter.php @@ -32,6 +32,8 @@ interface Highlighter /** * Highlights a token depending on its type. + * + * @param Token::TOKEN_TYPE_* $type */ public function highlightToken(int $type, string $value): string; diff --git a/app/vendor/doctrine/sql-formatter/src/HtmlHighlighter.php b/app/vendor/doctrine/sql-formatter/src/HtmlHighlighter.php index 98946b5c5..71f5933c2 100644 --- a/app/vendor/doctrine/sql-formatter/src/HtmlHighlighter.php +++ b/app/vendor/doctrine/sql-formatter/src/HtmlHighlighter.php @@ -10,27 +10,22 @@ use const ENT_COMPAT; use const ENT_IGNORE; -use const PHP_EOL; final class HtmlHighlighter implements Highlighter { public const HIGHLIGHT_PRE = 'pre'; - /** - * This flag tells us if queries need to be enclosed in
 tags
-     *
-     * @var bool
-     */
-    private $usePre;
-
     /** @var array */
-    private $htmlAttributes;
+    private readonly array $htmlAttributes;
 
     /**
      * @param array $htmlAttributes
+     * @param bool                  $usePre         This flag tells us if queries need to be enclosed in 
 tags
      */
-    public function __construct(array $htmlAttributes = [], bool $usePre = true)
-    {
+    public function __construct(
+        array $htmlAttributes = [],
+        private readonly bool $usePre = true,
+    ) {
         $this->htmlAttributes = $htmlAttributes + [
             self::HIGHLIGHT_QUOTE => 'style="color: blue;"',
             self::HIGHLIGHT_BACKTICK_QUOTE => 'style="color: purple;"',
@@ -43,7 +38,6 @@ public function __construct(array $htmlAttributes = [], bool $usePre = true)
             self::HIGHLIGHT_VARIABLE => 'style="color: orange;"',
             self::HIGHLIGHT_PRE => 'style="color: black; background-color: white;"',
         ];
-        $this->usePre         = $usePre;
     }
 
     public function highlightToken(int $type, string $value): string
@@ -62,7 +56,8 @@ public function highlightToken(int $type, string $value): string
         return '' . $value . '';
     }
 
-    public function attributes(int $type): ?string
+    /** @param Token::TOKEN_TYPE_* $type */
+    public function attributes(int $type): string|null
     {
         if (! isset(self::TOKEN_TYPE_TO_HIGHLIGHT[$type])) {
             return null;
@@ -75,9 +70,9 @@ public function highlightError(string $value): string
     {
         return sprintf(
             '%s%s',
-            PHP_EOL,
+            "\n",
             $this->htmlAttributes[self::HIGHLIGHT_ERROR],
-            $value
+            $value,
         );
     }
 
diff --git a/app/vendor/doctrine/sql-formatter/src/SqlFormatter.php b/app/vendor/doctrine/sql-formatter/src/SqlFormatter.php
index 624c3bbb4..aee3f236b 100644
--- a/app/vendor/doctrine/sql-formatter/src/SqlFormatter.php
+++ b/app/vendor/doctrine/sql-formatter/src/SqlFormatter.php
@@ -11,30 +11,31 @@
 
 namespace Doctrine\SqlFormatter;
 
+use function array_pop;
 use function array_search;
-use function array_shift;
-use function array_unshift;
 use function assert;
-use function current;
+use function end;
+use function in_array;
 use function preg_replace;
-use function reset;
 use function rtrim;
 use function str_repeat;
 use function str_replace;
 use function strlen;
+use function strtoupper;
+use function substr;
 use function trim;
 
 use const PHP_SAPI;
 
 final class SqlFormatter
 {
-    /** @var Highlighter */
-    private $highlighter;
+    private readonly Highlighter $highlighter;
+    private readonly Tokenizer $tokenizer;
 
-    /** @var Tokenizer */
-    private $tokenizer;
+    private const INDENT_TYPE_BLOCK   = 'block';
+    private const INDENT_TYPE_SPECIAL = 'special';
 
-    public function __construct(?Highlighter $highlighter = null)
+    public function __construct(Highlighter|null $highlighter = null)
     {
         $this->tokenizer   = new Tokenizer();
         $this->highlighter = $highlighter ?? (PHP_SAPI === 'cli' ? new CliHighlighter() : new HtmlHighlighter());
@@ -66,33 +67,71 @@ public function format(string $string, string $indentString = '  '): string
         $inlineIndented        = false;
         $clauseLimit           = false;
 
+        $appendNewLineIfNotAddedFx  = static function () use (&$addedNewline, &$return, $tab, &$indentLevel): void {
+            // Add a newline if not already added
+            if ($addedNewline) { // @phpstan-ignore if.alwaysFalse
+                return;
+            }
+
+            $return  = rtrim($return, ' ' . $tab);
+            $return .= "\n" . str_repeat($tab, $indentLevel);
+        };
+        $decreaseIndentationLevelFx = static function () use (&$return, &$indentTypes, $tab, &$indentLevel): void {
+            array_pop($indentTypes);
+            $indentLevel--;
+
+            // Redo the indentation since it may be different now
+            $lastPossiblyIndentLine = substr($return, -($indentLevel + 2));
+            if (rtrim($lastPossiblyIndentLine, $tab) !== "\n") {
+                return;
+            }
+
+            $rtrimLength = $indentLevel + 1;
+            while (substr($return, -($rtrimLength + 2), 1) === "\n") {
+                $rtrimLength++;
+            }
+
+            $return = substr($return, 0, -$rtrimLength) . str_repeat($tab, $indentLevel);
+        };
+
         // Tokenize String
         $cursor = $this->tokenizer->tokenize($string);
 
         // Format token by token
         while ($token = $cursor->next(Token::TOKEN_TYPE_WHITESPACE)) {
+            $prevNotWhitespaceToken = $cursor->subCursor()->previous(Token::TOKEN_TYPE_WHITESPACE);
+            $tokenValueUpper        = strtoupper($token->value());
+            if ($prevNotWhitespaceToken !== null && $prevNotWhitespaceToken->value() === '.') {
+                $tokenValueUpper = false;
+            }
+
             $highlighted = $this->highlighter->highlightToken(
                 $token->type(),
-                $token->value()
+                $token->value(),
             );
 
             // If we are increasing the special indent level now
             if ($increaseSpecialIndent) {
                 $indentLevel++;
                 $increaseSpecialIndent = false;
-                array_unshift($indentTypes, 'special');
+                $indentTypes[]         = self::INDENT_TYPE_SPECIAL;
             }
 
             // If we are increasing the block indent level now
             if ($increaseBlockIndent) {
                 $indentLevel++;
                 $increaseBlockIndent = false;
-                array_unshift($indentTypes, 'block');
+                $indentTypes[]       = self::INDENT_TYPE_BLOCK;
             }
 
             // If we need a new line before the token
             if ($newline) {
-                $return       = rtrim($return, ' ');
+                $return = rtrim($return, ' ');
+
+                if ($prevNotWhitespaceToken !== null && $prevNotWhitespaceToken->value() === ';') {
+                    $return .= "\n";
+                }
+
                 $return      .= "\n" . str_repeat($tab, $indentLevel);
                 $newline      = false;
                 $addedNewline = true;
@@ -104,7 +143,7 @@ public function format(string $string, string $indentString = '  '): string
             if ($token->isOfType(Token::TOKEN_TYPE_COMMENT, Token::TOKEN_TYPE_BLOCK_COMMENT)) {
                 if ($token->isOfType(Token::TOKEN_TYPE_BLOCK_COMMENT)) {
                     $indent      = str_repeat($tab, $indentLevel);
-                    $return      = rtrim($return, " \t");
+                    $return      = rtrim($return, ' ' . $tab);
                     $return     .= "\n" . $indent;
                     $highlighted = str_replace("\n", "\n" . $indent, $highlighted);
                 }
@@ -120,8 +159,8 @@ public function format(string $string, string $indentString = '  '): string
                     $return = rtrim($return, ' ');
 
                     if ($inlineIndented) {
-                        array_shift($indentTypes);
-                        $indentLevel--;
+                        $decreaseIndentationLevelFx();
+
                         $return  = rtrim($return, ' ');
                         $return .= "\n" . str_repeat($tab, $indentLevel);
                     }
@@ -152,7 +191,7 @@ public function format(string $string, string $indentString = '  '): string
                 for ($j = 1; $j <= 250; $j++) {
                     // Reached end of string
                     $next = $subCursor->next(Token::TOKEN_TYPE_WHITESPACE);
-                    if (! $next) {
+                    if ($next === null) {
                         break;
                     }
 
@@ -175,7 +214,7 @@ public function format(string $string, string $indentString = '  '): string
                             Token::TOKEN_TYPE_RESERVED_TOPLEVEL,
                             Token::TOKEN_TYPE_RESERVED_NEWLINE,
                             Token::TOKEN_TYPE_COMMENT,
-                            Token::TOKEN_TYPE_BLOCK_COMMENT
+                            Token::TOKEN_TYPE_BLOCK_COMMENT,
                         )
                     ) {
                         break;
@@ -192,7 +231,7 @@ public function format(string $string, string $indentString = '  '): string
 
                 // Take out the preceding space unless there was whitespace there in the original query
                 $prevToken = $cursor->subCursor()->previous();
-                if ($prevToken && ! $prevToken->isOfType(Token::TOKEN_TYPE_WHITESPACE)) {
+                if ($prevToken !== null && ! $prevToken->isOfType(Token::TOKEN_TYPE_WHITESPACE)) {
                     $return = rtrim($return, ' ');
                 }
 
@@ -206,17 +245,12 @@ public function format(string $string, string $indentString = '  '): string
                 // Remove whitespace before the closing parentheses
                 $return = rtrim($return, ' ');
 
-                $indentLevel--;
-
-                // Reset indent level
-                while ($j = array_shift($indentTypes)) {
-                    if ($j !== 'special') {
-                        break;
-                    }
-
-                    $indentLevel--;
+                while (end($indentTypes) === self::INDENT_TYPE_SPECIAL) {
+                    $decreaseIndentationLevelFx();
                 }
 
+                $decreaseIndentationLevelFx();
+
                 if ($indentLevel < 0) {
                     // This is an error
                     $indentLevel = 0;
@@ -225,40 +259,61 @@ public function format(string $string, string $indentString = '  '): string
                     continue;
                 }
 
-                // Add a newline before the closing parentheses (if not already added)
-                if (! $addedNewline) {
-                    $return .= "\n" . str_repeat($tab, $indentLevel);
-                }
+                $appendNewLineIfNotAddedFx();
             } elseif ($token->isOfType(Token::TOKEN_TYPE_RESERVED_TOPLEVEL)) {
                 // Top level reserved words start a new line and increase the special indent level
                 $increaseSpecialIndent = true;
 
-                // If the last indent type was 'special', decrease the special indent for this round
-                reset($indentTypes);
-                if (current($indentTypes) === 'special') {
-                    $indentLevel--;
-                    array_shift($indentTypes);
+                // If the last indent type was special, decrease the special indent for this round
+                if (end($indentTypes) === self::INDENT_TYPE_SPECIAL) {
+                    $decreaseIndentationLevelFx();
                 }
 
                 // Add a newline after the top level reserved word
                 $newline = true;
-                // Add a newline before the top level reserved word (if not already added)
-                if (! $addedNewline) {
-                    $return  = rtrim($return, ' ');
-                    $return .= "\n" . str_repeat($tab, $indentLevel);
-                } else {
-                    // If we already added a newline, redo the indentation since it may be different now
-                    $return = rtrim($return, $tab) . str_repeat($tab, $indentLevel);
-                }
+
+                $appendNewLineIfNotAddedFx();
 
                 if ($token->hasExtraWhitespace()) {
                     $highlighted = preg_replace('/\s+/', ' ', $highlighted);
                 }
 
-                //if SQL 'LIMIT' clause, start variable to reset newline
-                if ($token->value() === 'LIMIT' && ! $inlineParentheses) {
+                // if SQL 'LIMIT' clause, start variable to reset newline
+                if ($tokenValueUpper === 'LIMIT' && ! $inlineParentheses) {
                     $clauseLimit = true;
                 }
+            } elseif ($token->value() === ';') {
+                // If the last indent type was special, decrease the special indent for this round
+                if (end($indentTypes) === self::INDENT_TYPE_SPECIAL) {
+                    $decreaseIndentationLevelFx();
+                }
+
+                $newline = true;
+            } elseif ($tokenValueUpper === 'CASE') {
+                $increaseBlockIndent = true;
+            } elseif ($tokenValueUpper === 'BEGIN') {
+                $newline             = true;
+                $increaseBlockIndent = true;
+            } elseif ($tokenValueUpper === 'LOOP') {
+                // https://docs.oracle.com/en/database/oracle/oracle-database/19/lnpls/basic-LOOP-statement.html
+
+                if ($prevNotWhitespaceToken !== null && strtoupper($prevNotWhitespaceToken->value()) !== 'END') {
+                    $newline             = true;
+                    $increaseBlockIndent = true;
+                }
+            } elseif (in_array($tokenValueUpper, ['WHEN', 'THEN', 'ELSE', 'END'], true)) {
+                if ($tokenValueUpper !== 'THEN') {
+                    $decreaseIndentationLevelFx();
+
+                    if ($prevNotWhitespaceToken !== null && strtoupper($prevNotWhitespaceToken->value()) !== 'CASE') {
+                        $appendNewLineIfNotAddedFx();
+                    }
+                }
+
+                if ($tokenValueUpper === 'THEN' || $tokenValueUpper === 'ELSE') {
+                    $newline             = true;
+                    $increaseBlockIndent = true;
+                }
             } elseif (
                 $clauseLimit &&
                 $token->value() !== ',' &&
@@ -268,7 +323,7 @@ public function format(string $string, string $indentString = '  '): string
                 $clauseLimit = false;
             } elseif ($token->value() === ',' && ! $inlineParentheses) {
                 // Commas start a new line (unless within inline parentheses or SQL 'LIMIT' clause)
-                //If the previous TOKEN_VALUE is 'LIMIT', resets new line
+                // If the previous TOKEN_VALUE is 'LIMIT', resets new line
                 if ($clauseLimit === true) {
                     $newline     = false;
                     $clauseLimit = false;
@@ -277,22 +332,18 @@ public function format(string $string, string $indentString = '  '): string
                     $newline = true;
                 }
             } elseif ($token->isOfType(Token::TOKEN_TYPE_RESERVED_NEWLINE)) {
-            // Newline reserved words start a new line
-                // Add a newline before the reserved word (if not already added)
-                if (! $addedNewline) {
-                    $return  = rtrim($return, ' ');
-                    $return .= "\n" . str_repeat($tab, $indentLevel);
-                }
+                // Newline reserved words start a new line
+
+                $appendNewLineIfNotAddedFx();
 
                 if ($token->hasExtraWhitespace()) {
                     $highlighted = preg_replace('/\s+/', ' ', $highlighted);
                 }
             } elseif ($token->isOfType(Token::TOKEN_TYPE_BOUNDARY)) {
                 // Multiple boundary characters in a row should not have spaces between them (not including parentheses)
-                $prevNotWhitespaceToken = $cursor->subCursor()->previous(Token::TOKEN_TYPE_WHITESPACE);
-                if ($prevNotWhitespaceToken && $prevNotWhitespaceToken->isOfType(Token::TOKEN_TYPE_BOUNDARY)) {
+                if ($prevNotWhitespaceToken !== null && $prevNotWhitespaceToken->isOfType(Token::TOKEN_TYPE_BOUNDARY)) {
                     $prevToken = $cursor->subCursor()->previous();
-                    if ($prevToken && ! $prevToken->isOfType(Token::TOKEN_TYPE_WHITESPACE)) {
+                    if ($prevToken !== null && ! $prevToken->isOfType(Token::TOKEN_TYPE_WHITESPACE)) {
                         $return = rtrim($return, ' ');
                     }
                 }
@@ -320,12 +371,12 @@ public function format(string $string, string $indentString = '  '): string
             }
 
             $nextNotWhitespace = $cursor->subCursor()->next(Token::TOKEN_TYPE_WHITESPACE);
-            if (! $nextNotWhitespace || ! $nextNotWhitespace->isOfType(Token::TOKEN_TYPE_NUMBER)) {
+            if ($nextNotWhitespace === null || ! $nextNotWhitespace->isOfType(Token::TOKEN_TYPE_NUMBER)) {
                 continue;
             }
 
             $prev = $cursor->subCursor()->previous(Token::TOKEN_TYPE_WHITESPACE);
-            if (! $prev) {
+            if ($prev === null) {
                 continue;
             }
 
@@ -334,7 +385,7 @@ public function format(string $string, string $indentString = '  '): string
                     Token::TOKEN_TYPE_QUOTE,
                     Token::TOKEN_TYPE_BACKTICK_QUOTE,
                     Token::TOKEN_TYPE_WORD,
-                    Token::TOKEN_TYPE_NUMBER
+                    Token::TOKEN_TYPE_NUMBER,
                 )
             ) {
                 continue;
@@ -344,15 +395,15 @@ public function format(string $string, string $indentString = '  '): string
         }
 
         // If there are unmatched parentheses
-        if (array_search('block', $indentTypes) !== false) {
+        if (array_search(self::INDENT_TYPE_BLOCK, $indentTypes) !== false) {
             $return  = rtrim($return, ' ');
             $return .= $this->highlighter->highlightErrorMessage(
-                'WARNING: unclosed parentheses or section'
+                'WARNING: unclosed parentheses or section',
             );
         }
 
         // Replace tab characters with the configuration tab character
-        $return = trim(str_replace("\t", $indentString, $return));
+        $return = trim(str_replace($tab, $indentString, $return));
 
         return $this->highlighter->output($return);
     }
@@ -373,7 +424,7 @@ public function highlight(string $string): string
         while ($token = $cursor->next()) {
             $return .= $this->highlighter->highlightToken(
                 $token->type(),
-                $token->value()
+                $token->value(),
             );
         }
 
@@ -405,7 +456,7 @@ public function compress(string $string): string
                 $token->isOfType(
                     Token::TOKEN_TYPE_RESERVED,
                     Token::TOKEN_TYPE_RESERVED_NEWLINE,
-                    Token::TOKEN_TYPE_RESERVED_TOPLEVEL
+                    Token::TOKEN_TYPE_RESERVED_TOPLEVEL,
                 )
             ) {
                 $newValue = preg_replace('/\s+/', ' ', $token->value());
diff --git a/app/vendor/doctrine/sql-formatter/src/Token.php b/app/vendor/doctrine/sql-formatter/src/Token.php
index b3be48bfc..a0d2a049c 100644
--- a/app/vendor/doctrine/sql-formatter/src/Token.php
+++ b/app/vendor/doctrine/sql-formatter/src/Token.php
@@ -4,8 +4,9 @@
 
 namespace Doctrine\SqlFormatter;
 
+use function assert;
 use function in_array;
-use function strpos;
+use function str_contains;
 
 final class Token
 {
@@ -21,23 +22,14 @@ final class Token
     public const TOKEN_TYPE_COMMENT           = 8;
     public const TOKEN_TYPE_BLOCK_COMMENT     = 9;
     public const TOKEN_TYPE_NUMBER            = 10;
-    public const TOKEN_TYPE_ERROR             = 11;
-    public const TOKEN_TYPE_VARIABLE          = 12;
-
-    // Constants for different components of a token
-    public const TOKEN_TYPE  = 0;
-    public const TOKEN_VALUE = 1;
-
-    /** @var int */
-    private $type;
-
-    /** @var string */
-    private $value;
-
-    public function __construct(int $type, string $value)
-    {
-        $this->type  = $type;
-        $this->value = $value;
+    public const TOKEN_TYPE_VARIABLE          = 11;
+
+    /** @param self::TOKEN_TYPE_* $type */
+    public function __construct(
+        private readonly int $type,
+        private readonly string $value,
+    ) {
+        assert($value !== '');
     }
 
     public function value(): string
@@ -45,11 +37,13 @@ public function value(): string
         return $this->value;
     }
 
+    /** @return self::TOKEN_TYPE_* */
     public function type(): int
     {
         return $this->type;
     }
 
+    /** @param self::TOKEN_TYPE_* ...$types */
     public function isOfType(int ...$types): bool
     {
         return in_array($this->type, $types, true);
@@ -57,9 +51,9 @@ public function isOfType(int ...$types): bool
 
     public function hasExtraWhitespace(): bool
     {
-        return strpos($this->value(), ' ') !== false ||
-            strpos($this->value(), "\n") !== false ||
-            strpos($this->value(), "\t") !== false;
+        return str_contains($this->value(), ' ') ||
+            str_contains($this->value(), "\n") ||
+            str_contains($this->value(), "\t");
     }
 
     public function withValue(string $value): self
diff --git a/app/vendor/doctrine/sql-formatter/src/Tokenizer.php b/app/vendor/doctrine/sql-formatter/src/Tokenizer.php
index ac9fb7aa4..f8f35a679 100644
--- a/app/vendor/doctrine/sql-formatter/src/Tokenizer.php
+++ b/app/vendor/doctrine/sql-formatter/src/Tokenizer.php
@@ -4,33 +4,35 @@
 
 namespace Doctrine\SqlFormatter;
 
-use function array_combine;
-use function array_keys;
+use function array_key_last;
 use function array_map;
-use function arsort;
+use function array_pop;
 use function assert;
+use function count;
 use function implode;
+use function is_int;
 use function preg_match;
 use function preg_quote;
+use function reset;
 use function str_replace;
+use function str_starts_with;
 use function strlen;
-use function strpos;
 use function strtoupper;
 use function substr;
+use function usort;
 
-/**
- * @internal
- */
+/** @internal */
 final class Tokenizer
 {
     /**
      * Reserved words (for syntax highlighting)
      *
-     * @var string[]
+     * @var list
      */
-    private $reserved = [
+    private array $reserved = [
         'ACCESSIBLE',
         'ACTION',
+        'ADD',
         'AFTER',
         'AGAINST',
         'AGGREGATE',
@@ -39,6 +41,7 @@ final class Tokenizer
         'ALTER',
         'ANALYSE',
         'ANALYZE',
+        'AND',
         'AS',
         'ASC',
         'AUTOCOMMIT',
@@ -46,13 +49,18 @@ final class Tokenizer
         'BACKUP',
         'BEGIN',
         'BETWEEN',
+        'BIGINT',
+        'BINARY',
         'BINLOG',
+        'BLOB',
         'BOTH',
+        'BY',
         'CASCADE',
         'CASE',
         'CHANGE',
         'CHANGED',
-        'CHARACTER SET',
+        'CHAR',
+        'CHARACTER',
         'CHARSET',
         'CHECK',
         'CHECKSUM',
@@ -70,7 +78,7 @@ final class Tokenizer
         'CONVERT',
         'CREATE',
         'CROSS',
-        'CURRENT ROW',
+        'CURRENT',
         'CURRENT_TIMESTAMP',
         'DATABASE',
         'DATABASES',
@@ -78,6 +86,7 @@ final class Tokenizer
         'DAY_HOUR',
         'DAY_MINUTE',
         'DAY_SECOND',
+        'DECIMAL',
         'DEFAULT',
         'DEFINER',
         'DELAYED',
@@ -89,6 +98,8 @@ final class Tokenizer
         'DISTINCTROW',
         'DIV',
         'DO',
+        'DOUBLE',
+        'DROP',
         'DUMPFILE',
         'DUPLICATE',
         'DYNAMIC',
@@ -96,27 +107,35 @@ final class Tokenizer
         'ENCLOSED',
         'END',
         'ENGINE',
-        'ENGINE_TYPE',
         'ENGINES',
+        'ENGINE_TYPE',
         'ESCAPE',
         'ESCAPED',
         'EVENTS',
+        'EXCEPT',
+        'EXCLUDE',
         'EXEC',
         'EXECUTE',
         'EXISTS',
         'EXPLAIN',
         'EXTENDED',
+        'FALSE',
         'FAST',
+        'FETCH',
         'FIELDS',
         'FILE',
         'FILTER',
         'FIRST',
         'FIXED',
+        'FLOAT',
+        'FLOAT4',
+        'FLOAT8',
         'FLUSH',
+        'FOLLOWING',
         'FOR',
         'FORCE',
-        'FOLLOWING',
         'FOREIGN',
+        'FROM',
         'FULL',
         'FULLTEXT',
         'FUNCTION',
@@ -125,6 +144,7 @@ final class Tokenizer
         'GRANTS',
         'GROUP',
         'GROUPS',
+        'HAVING',
         'HEAP',
         'HIGH_PRIORITY',
         'HOSTS',
@@ -139,21 +159,33 @@ final class Tokenizer
         'INDEX',
         'INDEXES',
         'INFILE',
+        'INNER',
         'INSERT',
         'INSERT_ID',
         'INSERT_METHOD',
+        'INT',
+        'INT1',
+        'INT2',
+        'INT3',
+        'INT4',
+        'INT8',
+        'INTEGER',
+        'INTERSECT',
         'INTERVAL',
         'INTO',
         'INVOKER',
         'IS',
         'ISOLATION',
+        'JOIN',
         'KEY',
         'KEYS',
         'KILL',
         'LAST_INSERT_ID',
         'LEADING',
+        'LEFT',
         'LEVEL',
         'LIKE',
+        'LIMIT',
         'LINEAR',
         'LINES',
         'LOAD',
@@ -161,6 +193,9 @@ final class Tokenizer
         'LOCK',
         'LOCKS',
         'LOGS',
+        'LONG',
+        'LONGBLOB',
+        'LONGTEXT',
         'LOW_PRIORITY',
         'MARIA',
         'MASTER',
@@ -174,28 +209,32 @@ final class Tokenizer
         'MAX_UPDATES_PER_HOUR',
         'MAX_USER_CONNECTIONS',
         'MEDIUM',
+        'MEDIUMBLOB',
+        'MEDIUMINT',
+        'MEDIUMTEXT',
         'MERGE',
         'MINUTE',
         'MINUTE_SECOND',
         'MIN_ROWS',
         'MODE',
+        'MODIFY',
         'MONTH',
         'MRG_MYISAM',
         'MYISAM',
         'NAMES',
         'NATURAL',
-        'NO OTHERS',
         'NOT',
-        'NOW()',
         'NULL',
+        'NUMERIC',
         'OFFSET',
         'ON',
         'OPEN',
         'OPTIMIZE',
         'OPTION',
         'OPTIONALLY',
-        'ON UPDATE',
-        'ON DELETE',
+        'OR',
+        'ORDER',
+        'OUTER',
         'OUTFILE',
         'OVER',
         'PACK_KEYS',
@@ -212,14 +251,15 @@ final class Tokenizer
         'PROCESSLIST',
         'PURGE',
         'QUICK',
-        'RANGE',
         'RAID0',
         'RAID_CHUNKS',
         'RAID_CHUNKSIZE',
         'RAID_TYPE',
+        'RANGE',
         'READ',
         'READ_ONLY',
         'READ_WRITE',
+        'REAL',
         'RECURSIVE',
         'REFERENCES',
         'REGEXP',
@@ -235,6 +275,7 @@ final class Tokenizer
         'RETURN',
         'RETURNS',
         'REVOKE',
+        'RIGHT',
         'RLIKE',
         'ROLLBACK',
         'ROW',
@@ -242,13 +283,16 @@ final class Tokenizer
         'ROW_FORMAT',
         'SECOND',
         'SECURITY',
+        'SELECT',
         'SEPARATOR',
         'SERIALIZABLE',
         'SESSION',
+        'SET',
         'SHARE',
         'SHOW',
         'SHUTDOWN',
         'SLAVE',
+        'SMALLINT',
         'SONAME',
         'SOUNDS',
         'SQL',
@@ -257,20 +301,20 @@ final class Tokenizer
         'SQL_BIG_SELECTS',
         'SQL_BIG_TABLES',
         'SQL_BUFFER_RESULT',
+        'SQL_CACHE',
         'SQL_CALC_FOUND_ROWS',
         'SQL_LOG_BIN',
         'SQL_LOG_OFF',
         'SQL_LOG_UPDATE',
         'SQL_LOW_PRIORITY_UPDATES',
         'SQL_MAX_JOIN_SIZE',
+        'SQL_NO_CACHE',
         'SQL_QUOTE_SHOW_CREATE',
         'SQL_SAFE_UPDATES',
         'SQL_SELECT_LIMIT',
         'SQL_SLAVE_SKIP_COUNTER',
         'SQL_SMALL_RESULT',
         'SQL_WARNINGS',
-        'SQL_CACHE',
-        'SQL_NO_CACHE',
         'START',
         'STARTING',
         'STATUS',
@@ -286,6 +330,9 @@ final class Tokenizer
         'TERMINATED',
         'THEN',
         'TIES',
+        'TINYBLOB',
+        'TINYINT',
+        'TINYTEXT',
         'TO',
         'TRAILING',
         'TRANSACTIONAL',
@@ -295,18 +342,27 @@ final class Tokenizer
         'TYPES',
         'UNBOUNDED',
         'UNCOMMITTED',
+        'UNION',
         'UNIQUE',
         'UNLOCK',
         'UNSIGNED',
+        'UPDATE',
         'USAGE',
         'USE',
         'USING',
+        'VALUES',
+        'VARBINARY',
+        'VARCHAR',
+        'VARCHARACTER',
         'VARIABLES',
         'VIEW',
         'WHEN',
+        'WHERE',
+        'WINDOW',
         'WITH',
         'WORK',
         'WRITE',
+        'XOR',
         'YEAR_MONTH',
     ];
 
@@ -314,54 +370,57 @@ final class Tokenizer
      * For SQL formatting
      * These keywords will all be on their own line
      *
-     * @var string[]
+     * @var list
      */
-    private $reservedToplevel = [
-        'WITH',
-        'SELECT',
-        'FROM',
-        'WHERE',
-        'SET',
-        'ORDER BY',
-        'GROUP BY',
-        'LIMIT',
-        'DROP',
-        'VALUES',
-        'UPDATE',
-        'HAVING',
+    private array $reservedToplevel = [
         'ADD',
-        'CHANGE',
-        'MODIFY',
         'ALTER TABLE',
+        'CHANGE',
         'DELETE FROM',
-        'UNION ALL',
-        'UNION',
+        'DROP',
         'EXCEPT',
+        'FETCH',
+        'FROM',
+        'GROUP BY',
+        'GROUPS',
+        'HAVING',
         'INTERSECT',
+        'LIMIT',
+        'MODIFY',
+        'OFFSET',
+        'ORDER BY',
         'PARTITION BY',
-        'ROWS',
         'RANGE',
-        'GROUPS',
+        'ROWS',
+        'SELECT',
+        'SET',
+        'UNION',
+        'UNION ALL',
+        'UPDATE',
+        'VALUES',
+        'WHERE',
         'WINDOW',
+        'WITH',
     ];
 
-    /** @var string[] */
-    private $reservedNewline = [
-        'LEFT OUTER JOIN',
-        'RIGHT OUTER JOIN',
-        'LEFT JOIN',
-        'RIGHT JOIN',
-        'OUTER JOIN',
+    /** @var list */
+    private array $reservedNewline = [
+        'AND',
+        'EXCLUDE',
         'INNER JOIN',
         'JOIN',
-        'XOR',
+        'LEFT JOIN',
+        'LEFT OUTER JOIN',
         'OR',
-        'AND',
-        'EXCLUDE',
+        'OUTER JOIN',
+        'RIGHT JOIN',
+        'RIGHT OUTER JOIN',
+        'STRAIGHT_JOIN',
+        'XOR',
     ];
 
-    /** @var string[] */
-    private $functions = [
+    /** @var list */
+    private array $functions = [
         'ABS',
         'ACOS',
         'ADDDATE',
@@ -394,21 +453,16 @@ final class Tokenizer
         'CEIL',
         'CEILING',
         'CENTROID',
-        'CHAR',
         'CHARACTER_LENGTH',
-        'CHARSET',
         'CHAR_LENGTH',
         'CHECKSUM_AGG',
         'COALESCE',
         'COERCIBILITY',
-        'COLLATION',
         'COMPRESS',
         'CONCAT',
         'CONCAT_WS',
         'CONNECTION_ID',
-        'CONTAINS',
         'CONV',
-        'CONVERT',
         'CONVERT_TZ',
         'CONVEXHULL',
         'COS',
@@ -421,23 +475,19 @@ final class Tokenizer
         'CURDATE',
         'CURRENT_DATE',
         'CURRENT_TIME',
-        'CURRENT_TIMESTAMP',
         'CURRENT_USER',
         'CURTIME',
-        'DATABASE',
         'DATE',
         'DATEDIFF',
         'DATE_ADD',
         'DATE_DIFF',
         'DATE_FORMAT',
         'DATE_SUB',
-        'DAY',
         'DAYNAME',
         'DAYOFMONTH',
         'DAYOFWEEK',
         'DAYOFYEAR',
         'DECODE',
-        'DEFAULT',
         'DEGREES',
         'DENSE_RANK',
         'DES_DECRYPT',
@@ -485,17 +535,12 @@ final class Tokenizer
         'GROUP_CONCAT',
         'GROUP_UNIQUE_USERS',
         'HEX',
-        'HOUR',
-        'IF',
-        'IFNULL',
         'INET_ATON',
         'INET_NTOA',
-        'INSERT',
         'INSTR',
         'INTERIORRINGN',
         'INTERSECTION',
         'INTERSECTS',
-        'INTERVAL',
         'ISCLOSED',
         'ISEMPTY',
         'ISNULL',
@@ -505,12 +550,10 @@ final class Tokenizer
         'IS_USED_LOCK',
         'LAG',
         'LAST_DAY',
-        'LAST_INSERT_ID',
         'LAST_VALUE',
         'LCASE',
         'LEAD',
         'LEAST',
-        'LEFT',
         'LENGTH',
         'LINEFROMTEXT',
         'LINEFROMWKB',
@@ -545,11 +588,9 @@ final class Tokenizer
         'MICROSECOND',
         'MID',
         'MIN',
-        'MINUTE',
         'MLINEFROMTEXT',
         'MLINEFROMWKB',
         'MOD',
-        'MONTH',
         'MONTHNAME',
         'MPOINTFROMTEXT',
         'MPOINTFROMWKB',
@@ -565,6 +606,7 @@ final class Tokenizer
         'MULTIPOLYGONFROMTEXT',
         'MULTIPOLYGONFROMWKB',
         'NAME_CONST',
+        'NOW',
         'NTH_VALUE',
         'NTILE',
         'NULLIF',
@@ -576,10 +618,9 @@ final class Tokenizer
         'OLD_PASSWORD',
         'ORD',
         'OVERLAPS',
-        'PASSWORD',
-        'PERCENT_RANK',
         'PERCENTILE_CONT',
         'PERCENTILE_DISC',
+        'PERCENT_RANK',
         'PERIOD_ADD',
         'PERIOD_DIFF',
         'PI',
@@ -604,16 +645,13 @@ final class Tokenizer
         'RELATED',
         'RELEASE_LOCK',
         'REPEAT',
-        'REPLACE',
         'REVERSE',
-        'RIGHT',
         'ROUND',
         'ROW_COUNT',
         'ROW_NUMBER',
         'RPAD',
         'RTRIM',
         'SCHEMA',
-        'SECOND',
         'SEC_TO_TIME',
         'SESSION_USER',
         'SHA',
@@ -627,13 +665,13 @@ final class Tokenizer
         'SRID',
         'STARTPOINT',
         'STD',
-        'STDEV',
-        'STDEVP',
         'STDDEV',
         'STDDEV_POP',
         'STDDEV_SAMP',
-        'STRING_AGG',
+        'STDEV',
+        'STDEVP',
         'STRCMP',
+        'STRING_AGG',
         'STR_TO_DATE',
         'SUBDATE',
         'SUBSTR',
@@ -655,7 +693,6 @@ final class Tokenizer
         'TOUCHES',
         'TO_DAYS',
         'TRIM',
-        'TRUNCATE',
         'UCASE',
         'UNCOMPRESS',
         'UNCOMPRESSED_LENGTH',
@@ -685,29 +722,15 @@ final class Tokenizer
         'YEARWEEK',
     ];
 
-    // Regular expressions for tokenizing
-
-    /** @var string */
-    private $regexBoundaries;
-
-    /** @var string */
-    private $regexReserved;
-
-    /** @var string */
-    private $regexReservedNewline;
-
-    /** @var string */
-    private $regexReservedToplevel;
-
-    /** @var string */
-    private $regexFunction;
+    /** Regular expression for tokenizing. */
+    private readonly string $tokenizeRegex;
 
     /**
      * Punctuation that can be used as a boundary between other tokens
      *
-     * @var string[]
+     * @var list
      */
-    private $boundaries = [
+    private array $boundaries = [
         ',',
         ';',
         '::', // PostgreSQL cast operator
@@ -731,270 +754,177 @@ final class Tokenizer
     ];
 
     /**
-     * Stuff that only needs to be done once. Builds regular expressions and
-     * sorts the reserved words.
+     * Stuff that only needs to be done once. Builds tokenizing regular expression.
      */
     public function __construct()
     {
-        // Sort reserved word list from longest word to shortest, 3x faster than usort
-        $reservedMap = array_combine($this->reserved, array_map('strlen', $this->reserved));
-        assert($reservedMap !== false);
-        arsort($reservedMap);
-        $this->reserved = array_keys($reservedMap);
-
-        // Set up regular expressions
-        $this->regexBoundaries       = '(' . implode(
-            '|',
-            $this->quoteRegex($this->boundaries)
-        ) . ')';
-        $this->regexReserved         = '(' . implode(
-            '|',
-            $this->quoteRegex($this->reserved)
-        ) . ')';
-        $this->regexReservedToplevel = str_replace(' ', '\\s+', '(' . implode(
-            '|',
-            $this->quoteRegex($this->reservedToplevel)
-        ) . ')');
-        $this->regexReservedNewline  = str_replace(' ', '\\s+', '(' . implode(
-            '|',
-            $this->quoteRegex($this->reservedNewline)
-        ) . ')');
-
-        $this->regexFunction = '(' . implode('|', $this->quoteRegex($this->functions)) . ')';
-    }
-
-    /**
-     * Takes a SQL string and breaks it into tokens.
-     * Each token is an associative array with type and value.
-     *
-     * @param string $string The SQL string
-     */
-    public function tokenize(string $string): Cursor
-    {
-        $tokens = [];
-
-        // Used to make sure the string keeps shrinking on each iteration
-        $oldStringLen = strlen($string) + 1;
-
-        $token = null;
-
-        $currentLength = strlen($string);
-
-        // Keep processing the string until it is empty
-        while ($currentLength) {
-            // If the string stopped shrinking, there was a problem
-            if ($oldStringLen <= $currentLength) {
-                $tokens[] = new Token(Token::TOKEN_TYPE_ERROR, $string);
-
-                return new Cursor($tokens);
-            }
-
-            $oldStringLen =  $currentLength;
-
-            // Get the next token and the token type
-            $token       = $this->createNextToken($string, $token);
-            $tokenLength = strlen($token->value());
-
-            $tokens[] = $token;
-
-            // Advance the string
-            $string = substr($string, $tokenLength);
-
-            $currentLength -= $tokenLength;
-        }
-
-        return new Cursor($tokens);
+        $this->tokenizeRegex = $this->makeTokenizeRegex($this->makeTokenizeRegexes());
     }
 
     /**
-     * Return the next token and token type in a SQL string.
-     * Quoted strings, comments, reserved words, whitespace, and punctuation
-     * are all their own tokens.
+     * Make regex from a list of values matching longest value first.
      *
-     * @param string     $string   The SQL string
-     * @param Token|null $previous The result of the previous createNextToken() call
+     * Optimized for speed by matching alternative branch only once
+     * https://github.com/PCRE2Project/pcre2/issues/411 .
      *
-     * @return Token An associative array containing the type and value of the token.
+     * @param list $values
      */
-    private function createNextToken(string $string, ?Token $previous = null): Token
+    private function makeRegexFromList(array $values, bool $sorted = false): string
     {
-        $matches = [];
-        // Whitespace
-        if (preg_match('/^\s+/', $string, $matches)) {
-            return new Token(Token::TOKEN_TYPE_WHITESPACE, $matches[0]);
+        // sort list alphabetically and from longest word to shortest
+        if (! $sorted) {
+            usort($values, static function (string $a, string $b) {
+                return str_starts_with($a, $b) || str_starts_with($b, $a)
+                    ? strlen($b) <=> strlen($a)
+                    : $a <=> $b;
+            });
         }
 
-        // Comment
-        if (
-            $string[0] === '#' ||
-            (isset($string[1]) && ($string[0] === '-' && $string[1] === '-') ||
-            (isset($string[1]) && $string[0] === '/' && $string[1] === '*'))
-        ) {
-            // Comment until end of line
-            if ($string[0] === '-' || $string[0] === '#') {
-                $last = strpos($string, "\n");
-                $type = Token::TOKEN_TYPE_COMMENT;
-            } else { // Comment until closing comment tag
-                $pos = strpos($string, '*/', 2);
-                assert($pos !== false);
-                $last = $pos + 2;
-                $type = Token::TOKEN_TYPE_BLOCK_COMMENT;
-            }
+        /** @var array> $valuesBySharedPrefix */
+        $valuesBySharedPrefix = [];
+        $items                = [];
+        $prefix               = null;
 
-            if ($last === false) {
-                $last = strlen($string);
+        foreach ($values as $v) {
+            if ($prefix !== null && ! str_starts_with($v, substr($prefix, 0, 1))) {
+                $valuesBySharedPrefix[$prefix] = $items;
+                $items                         = [];
+                $prefix                        = null;
             }
 
-            return new Token($type, substr($string, 0, $last));
+            $items[] = $v;
+
+            if ($prefix === null) {
+                $prefix = $v;
+            } else {
+                while (! str_starts_with($v, $prefix)) {
+                    $prefix = substr($prefix, 0, -1);
+                }
+            }
         }
 
-        // Quoted String
-        if ($string[0] === '"' || $string[0] === '\'' || $string[0] === '`' || $string[0] === '[') {
-            return new Token(
-                ($string[0] === '`' || $string[0] === '['
-                    ? Token::TOKEN_TYPE_BACKTICK_QUOTE
-                    : Token::TOKEN_TYPE_QUOTE),
-                $this->getQuotedString($string)
-            );
+        if ($items !== []) {
+            $valuesBySharedPrefix[$prefix] = $items;
+            $items                         = [];
+            $prefix                        = null;
         }
 
-        // User-defined Variable
-        if (($string[0] === '@' || $string[0] === ':') && isset($string[1])) {
-            $value = null;
-            $type  = Token::TOKEN_TYPE_VARIABLE;
+        $regex = '(?>';
 
-            // If the variable name is quoted
-            if ($string[1] === '"' || $string[1] === '\'' || $string[1] === '`') {
-                $value = $string[0] . $this->getQuotedString(substr($string, 1));
-            } else {
-                // Non-quoted variable name
-                preg_match('/^(' . $string[0] . '[a-zA-Z0-9\._\$]+)/', $string, $matches);
-                if ($matches) {
-                    $value = $matches[1];
-                }
+        foreach ($valuesBySharedPrefix as $prefix => $items) {
+            if ($regex !== '(?>') {
+                $regex .= '|';
             }
 
-            if ($value !== null) {
-                return new Token($type, $value);
+            if (is_int($prefix)) {
+                $prefix = (string) $prefix;
             }
-        }
 
-        // Number (decimal, binary, or hex)
-        if (
-            preg_match(
-                '/^([0-9]+(\.[0-9]+)?|0x[0-9a-fA-F]+|0b[01]+)($|\s|"\'`|' . $this->regexBoundaries . ')/',
-                $string,
-                $matches
-            )
-        ) {
-            return new Token(Token::TOKEN_TYPE_NUMBER, $matches[1]);
-        }
+            $regex .= preg_quote($prefix, '/');
 
-        // Boundary Character (punctuation and symbols)
-        if (preg_match('/^(' . $this->regexBoundaries . ')/', $string, $matches)) {
-            return new Token(Token::TOKEN_TYPE_BOUNDARY, $matches[1]);
+            $regex .= count($items) === 1
+                ? preg_quote(substr(reset($items), strlen($prefix)), '/')
+                : $this->makeRegexFromList(array_map(static fn ($v) => substr($v, strlen($prefix)), $items), true);
         }
 
-        // A reserved word cannot be preceded by a '.'
-        // this makes it so in "mytable.from", "from" is not considered a reserved word
-        if (! $previous || $previous->value() !== '.') {
-            $upper = strtoupper($string);
-            // Top Level Reserved Word
-            if (
-                preg_match(
-                    '/^(' . $this->regexReservedToplevel . ')($|\s|' . $this->regexBoundaries . ')/',
-                    $upper,
-                    $matches
-                )
-            ) {
-                return new Token(
-                    Token::TOKEN_TYPE_RESERVED_TOPLEVEL,
-                    substr($upper, 0, strlen($matches[1]))
-                );
-            }
+        return $regex . ')';
+    }
 
-            // Newline Reserved Word
-            if (
-                preg_match(
-                    '/^(' . $this->regexReservedNewline . ')($|\s|' . $this->regexBoundaries . ')/',
-                    $upper,
-                    $matches
+    /** @return array */
+    private function makeTokenizeRegexes(): array
+    {
+        // Set up regular expressions
+        $regexBoundaries       = $this->makeRegexFromList($this->boundaries);
+        $regexReserved         = $this->makeRegexFromList($this->reserved);
+        $regexReservedToplevel = str_replace(' ', '\s+', $this->makeRegexFromList($this->reservedToplevel));
+        $regexReservedNewline  = str_replace(' ', '\s+', $this->makeRegexFromList($this->reservedNewline));
+        $regexFunction         = $this->makeRegexFromList($this->functions);
+
+        return [
+            Token::TOKEN_TYPE_WHITESPACE => '\s+',
+            Token::TOKEN_TYPE_COMMENT => '(?:--|#)[^\n]*+',
+            Token::TOKEN_TYPE_BLOCK_COMMENT => '/\*(?:[^*]+|\*(?!/))*+(?:\*|$)(?:/|$)',
+            // 1. backtick quoted string using `` to escape
+            // 2. square bracket quoted string (SQL Server) using ]] to escape
+            Token::TOKEN_TYPE_BACKTICK_QUOTE => <<<'EOD'
+                (?>(?x)
+                    `(?:[^`]+|`(?:`|$))*+(?:`|$)
+                    |\[(?:[^\]]+|\](?:\]|$))*+(?:\]|$)
                 )
-            ) {
-                return new Token(
-                    Token::TOKEN_TYPE_RESERVED_NEWLINE,
-                    substr($upper, 0, strlen($matches[1]))
-                );
-            }
-
-            // Other Reserved Word
-            if (
-                preg_match(
-                    '/^(' . $this->regexReserved . ')($|\s|' . $this->regexBoundaries . ')/',
-                    $upper,
-                    $matches
+                EOD,
+            // 3. double quoted string using "" or \" to escape
+            // 4. single quoted string using '' or \' to escape
+            Token::TOKEN_TYPE_QUOTE => <<<'EOD'
+                (?>(?sx)
+                    '(?:[^'\\]+|\\(?:.|$)|'(?:'|$))*+(?:'|$)
+                    |"(?:[^"\\]+|\\(?:.|$)|"(?:"|$))*+(?:"|$)
                 )
-            ) {
-                return new Token(
-                    Token::TOKEN_TYPE_RESERVED,
-                    substr($upper, 0, strlen($matches[1]))
-                );
-            }
-        }
+                EOD,
+            // User-defined variable, possibly with quoted name
+            Token::TOKEN_TYPE_VARIABLE => '[@:](?:[\w.$]++|(?&t_' . Token::TOKEN_TYPE_BACKTICK_QUOTE . ')|(?&t_' . Token::TOKEN_TYPE_QUOTE . '))',
+            // decimal, binary, or hex
+            Token::TOKEN_TYPE_NUMBER => '(?:\d+(?:\.\d+)?|0x[\da-fA-F]+|0b[01]+)(?=$|\s|"\'`|' . $regexBoundaries . ')',
+            // punctuation and symbols
+            Token::TOKEN_TYPE_BOUNDARY => $regexBoundaries,
+            // A reserved word cannot be preceded by a '.'
+            // this makes it so in "mytable.from", "from" is not considered a reserved word
+            Token::TOKEN_TYPE_RESERVED_TOPLEVEL => '(? '(? '(? '.*?(?=$|\s|["\'`]|' . $regexBoundaries . ')',
+        ];
+    }
 
-        // A function must be succeeded by '('
-        // this makes it so "count(" is considered a function, but "count" alone is not
-        $upper = strtoupper($string);
-        // function
-        if (preg_match('/^(' . $this->regexFunction . '[(]|\s|[)])/', $upper, $matches)) {
-            return new Token(
-                Token::TOKEN_TYPE_RESERVED,
-                substr($upper, 0, strlen($matches[1]) - 1)
-            );
-        }
+    /** @param array $regexes */
+    private function makeTokenizeRegex(array $regexes): string
+    {
+        $parts = [];
 
-        // Non reserved word
-        preg_match('/^(.*?)($|\s|["\'`]|' . $this->regexBoundaries . ')/', $string, $matches);
+        foreach ($regexes as $type => $regex) {
+            $parts[] = '(?' . $regex . ')';
+        }
 
-        return new Token(Token::TOKEN_TYPE_WORD, $matches[1]);
+        return '~\G(?:' . implode('|', $parts) . ')~';
     }
 
     /**
-     * Helper function for building regular expressions for reserved words and boundary characters
-     *
-     * @param string[] $strings The strings to be quoted
+     * Takes a SQL string and breaks it into tokens.
+     * Each token is an associative array with type and value.
      *
-     * @return string[] The quoted strings
+     * @param string $string The SQL string
      */
-    private function quoteRegex(array $strings): array
+    public function tokenize(string $string): Cursor
     {
-        return array_map(static function (string $string): string {
-            return preg_quote($string, '/');
-        }, $strings);
-    }
+        $tokenizeRegex = $this->tokenizeRegex;
+        $upper         = strtoupper($string);
 
-    private function getQuotedString(string $string): string
-    {
-        $ret = '';
-
-        // This checks for the following patterns:
-        // 1. backtick quoted string using `` to escape
-        // 2. square bracket quoted string (SQL Server) using ]] to escape
-        // 3. double quoted string using "" or \" to escape
-        // 4. single quoted string using '' or \' to escape
-        if (
-            preg_match(
-                '/^(((`[^`]*($|`))+)|
-            ((\[[^\]]*($|\]))(\][^\]]*($|\]))*)|
-            (("[^"\\\\]*(?:\\\\.[^"\\\\]*)*("|$))+)|
-            ((\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*(\'|$))+))/sx',
-                $string,
-                $matches
-            )
-        ) {
-            $ret = $matches[1];
+        $tokens = [];
+        $offset = 0;
+
+        while ($offset < strlen($string)) {
+            // Get the next token and the token type
+            preg_match($tokenizeRegex, $upper, $matches, 0, $offset);
+            assert(($matches[0] ?? '') !== '');
+
+            while (is_int($lastMatchesKey = array_key_last($matches))) {
+                array_pop($matches);
+            }
+
+            assert(str_starts_with($lastMatchesKey, 't_'));
+
+            /** @var Token::TOKEN_TYPE_* $tokenType */
+            $tokenType = (int) substr($lastMatchesKey, 2);
+
+            $token = new Token($tokenType, substr($string, $offset, strlen($matches[0])));
+
+            $offset += strlen($token->value());
+
+            $tokens[] = $token;
         }
 
-        return $ret;
+        return new Cursor($tokens);
     }
 }
diff --git a/app/vendor/jasny/twig-extensions/.github/workflows/php.yml b/app/vendor/jasny/twig-extensions/.github/workflows/php.yml
new file mode 100644
index 000000000..996e27ff0
--- /dev/null
+++ b/app/vendor/jasny/twig-extensions/.github/workflows/php.yml
@@ -0,0 +1,51 @@
+name: PHP
+
+on:
+  push:
+    branches: [ master ]
+  pull_request:
+    branches: [ master ]
+
+jobs:
+  run:
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        include:
+          - php: 7.4
+            composer: '--prefer-lowest'
+            desc: "Lowest versions"
+          - php: 7.4
+          - php: 8.0
+          - php: 8.1
+          - php: 8.2
+            coverage: '--coverage-clover /tmp/clover.xml'
+          - php: 8.3
+    name: PHP ${{ matrix.php }} ${{ matrix.desc }}
+
+    steps:
+    - uses: actions/checkout@v4
+      with:
+        fetch-depth: 2
+
+    - name: Setup PHP
+      uses: shivammathur/setup-php@v2
+      with:
+        php-version: ${{ matrix.php }}
+        coverage: xdebug
+
+    - name: Validate composer.json and composer.lock
+      run: composer validate
+
+    - name: Install dependencies
+      run: composer update --prefer-dist --no-progress ${{ matrix.composer }}
+
+    - name: Run PHPUnit
+      run: vendor/bin/phpunit ${{ matrix.coverage }}
+
+    - name: Upload Scrutinizer coverage
+      uses: sudo-bot/action-scrutinizer@latest
+      if: ${{ matrix.coverage }}
+      with:
+        cli-args: "--format=php-clover build/logs/clover.xml --revision=${{ github.event.pull_request.head.sha || github.sha }}"
diff --git a/app/vendor/jasny/twig-extensions/.gitignore b/app/vendor/jasny/twig-extensions/.gitignore
index 1c9815dfd..749cf921c 100644
--- a/app/vendor/jasny/twig-extensions/.gitignore
+++ b/app/vendor/jasny/twig-extensions/.gitignore
@@ -1,3 +1,4 @@
 /vendor
 /composer.lock
 .phpunit.result.cache
+.idea
diff --git a/app/vendor/jasny/twig-extensions/.travis.yml b/app/vendor/jasny/twig-extensions/.travis.yml
deleted file mode 100644
index 9b93acb79..000000000
--- a/app/vendor/jasny/twig-extensions/.travis.yml
+++ /dev/null
@@ -1,26 +0,0 @@
-language: php
-
-addons:
-  apt:
-    packages:
-      - language-pack-nl
-
-php:
-  - 7.2
-  - 7.3
-  - 7.4
-
-branches:
-  only:
-    - master
-
-install:
-  - composer install
-  - wget https://scrutinizer-ci.com/ocular.phar -O "$HOME/ocular.phar"
-
-script:
-  - vendor/bin/phpunit --coverage-clover cache/logs/clover.xml
-
-after_success:
-  - php "$HOME/ocular.phar" code-coverage:upload --format=php-clover cache/logs/clover.xml
-
diff --git a/app/vendor/jasny/twig-extensions/README.md b/app/vendor/jasny/twig-extensions/README.md
index ad9aac353..49634ff05 100644
--- a/app/vendor/jasny/twig-extensions/README.md
+++ b/app/vendor/jasny/twig-extensions/README.md
@@ -1,10 +1,9 @@
 Jasny Twig Extensions
 =======================
 
-[![Build Status](https://travis-ci.org/jasny/twig-extensions.svg?branch=master)](https://travis-ci.org/jasny/twig-extensions)
+[![PHP](https://github.com/jasny/twig-extensions/actions/workflows/php.yml/badge.svg)](https://github.com/jasny/twig-extensions/actions/workflows/php.yml)
 [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/jasny/twig-extensions/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/jasny/twig-extensions/?branch=master)
 [![Code Coverage](https://scrutinizer-ci.com/g/jasny/twig-extensions/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/jasny/twig-extensions/?branch=master)
-[![SensioLabsInsight](https://insight.sensiolabs.com/projects/20fdb2a4-7565-441b-8920-48a7c09113a1/mini.png)](https://insight.sensiolabs.com/projects/20fdb2a4-7565-441b-8920-48a7c09113a1)
 [![Packagist Stable Version](https://img.shields.io/packagist/v/jasny/twig-extensions.svg)](https://packagist.org/packages/jasny/twig-extensions)
 [![Packagist License](https://img.shields.io/packagist/l/jasny/twig-extensions.svg)](https://packagist.org/packages/jasny/twig-extensions)
 
@@ -26,7 +25,7 @@ $twig->addExtension(new Jasny\Twig\TextExtension());
 $twig->addExtension(new Jasny\Twig\ArrayExtension());
 ```
 
-To use in a symfony project [register the extensions as a service](http://symfony.com/doc/current/cookbook/templating/twig_extension.html#register-an-extension-as-a-service).
+To use in a Symfony project [register the extensions as a service](http://symfony.com/doc/current/cookbook/templating/twig_extension.html#register-an-extension-as-a-service).
 
 ```yaml
 services:
@@ -54,7 +53,7 @@ services:
 
 ## Date extension
 
-Format a date base on the current locale. Requires the [intl extension](http://www.php.net/intl).
+Format a date based on the current locale. Requires the [intl extension](http://www.php.net/intl).
 
 * localdate     - Format the date value as a string based on the current locale
 * localtime     - Format the time value as a string based on the current locale
@@ -81,7 +80,7 @@ Exposes [PCRE](http://www.php.net/pcre) to Twig.
 
 * preg_quote   - Quote regular expression characters
 * preg_match   - Perform a regular expression match
-* preg_get     - Perform a regular expression match and returns the matched group
+* preg_get     - Perform a regular expression match and return the matched group
 * preg_get_all - Perform a regular expression match and return the group for all matches
 * preg_grep    - Perform a regular expression match and return an array of entries that match the pattern
 * preg_replace - Perform a regular expression search and replace
@@ -106,9 +105,9 @@ Convert text to HTML + string functions
 
 * paragraph - Add HTML paragraph and line breaks to text
 * line - Get a single line of text
-* less - Cut of text on a pagebreak
-* truncate - Cut of text if it's to long
-* linkify - Turn all URLs in clickable links (also supports Twitter @user and #subject)
+* less - Cut of text on a page break
+* truncate - Cut off text if it's too long
+* linkify - Turn all URLs into clickable links (also supports Twitter @user and #subject)
 
 
 ## Array ##
diff --git a/app/vendor/jasny/twig-extensions/composer.json b/app/vendor/jasny/twig-extensions/composer.json
index 8cfec9c45..aec67db4a 100644
--- a/app/vendor/jasny/twig-extensions/composer.json
+++ b/app/vendor/jasny/twig-extensions/composer.json
@@ -16,8 +16,8 @@
         "source": "https://github.com/jasny/twig-extensions"
     },
     "require": {
-        "php": ">=7.0.0",
-        "twig/twig": "^2.0 | ^3.0"
+        "php": ">=7.4.0",
+        "twig/twig": "^2.7 | ^3.0"
     },
     "suggest": {
         "ext-intl": "Required for the use of the LocalDate Twig extension",
@@ -29,14 +29,25 @@
         }
     },
     "require-dev": {
-        "php": ">=7.2.0",
         "ext-intl": "*",
         "ext-pcre": "*",
-        "jasny/php-code-quality": "^2.5"
+        "ext-json": "*",
+        "phpstan/phpstan": "^1.12.0",
+        "phpunit/phpunit": "^9.6",
+        "squizlabs/php_codesniffer": "^3.10"
     },
     "autoload-dev": {
-        "classmap": [
-            "tests/support/"
+        "psr-4": {
+          "Jasny\\Twig\\Tests\\": "tests/"
+        }
+    },
+    "minimum-stability": "dev",
+    "prefer-stable": true,
+    "scripts": {
+        "test": [
+            "phpstan analyse",
+            "XDEBUG_MODE=coverage phpunit --testdox --colors=always --coverage-text",
+            "phpcs -p src"
         ]
     }
 }
diff --git a/app/vendor/jasny/twig-extensions/phpstan.neon b/app/vendor/jasny/twig-extensions/phpstan.neon
new file mode 100644
index 000000000..3703eb2f1
--- /dev/null
+++ b/app/vendor/jasny/twig-extensions/phpstan.neon
@@ -0,0 +1,5 @@
+parameters:
+    level: 5
+    paths:
+        - src
+
diff --git a/app/vendor/jasny/twig-extensions/phpunit.xml.dist b/app/vendor/jasny/twig-extensions/phpunit.xml.dist
index 656c48c77..df2914038 100644
--- a/app/vendor/jasny/twig-extensions/phpunit.xml.dist
+++ b/app/vendor/jasny/twig-extensions/phpunit.xml.dist
@@ -1,24 +1,13 @@
 
-
-
-    
-        
-            tests/
-        
-    
-    
-        
-            src
-        
-    
-    
-        
-        
+
+  
+    
+      src
+    
+  
+  
+    
+      tests/
+    
+  
 
-
diff --git a/app/vendor/jasny/twig-extensions/src/ArrayExtension.php b/app/vendor/jasny/twig-extensions/src/ArrayExtension.php
index 04cc11172..6ffe7824e 100644
--- a/app/vendor/jasny/twig-extensions/src/ArrayExtension.php
+++ b/app/vendor/jasny/twig-extensions/src/ArrayExtension.php
@@ -12,10 +12,8 @@ class ArrayExtension extends AbstractExtension
 {
     /**
      * Return extension name
-     *
-     * @return string
      */
-    public function getName()
+    public function getName(): string
     {
         return 'jasny/array';
     }
@@ -38,22 +36,16 @@ public function getFilters()
 
     /**
      * Calculate the sum of values in an array
-     *
-     * @param array $array
-     * @return int
      */
-    public function sum($array)
+    public function sum(?array $array): ?int
     {
         return isset($array) ? array_sum((array)$array) : null;
     }
 
     /**
      * Calculate the product of values in an array
-     *
-     * @param array $array
-     * @return int
      */
-    public function product($array)
+    public function product(?array $array): ?int
     {
         return isset($array) ? array_product((array)$array) : null;
     }
@@ -61,10 +53,10 @@ public function product($array)
     /**
      * Return all the values of an array or object
      *
-     * @param array|object $array
-     * @return array
+     * @param array|object|null $array
+     * @return array|null
      */
-    public function values($array)
+    public function values($array): ?array
     {
         return isset($array) ? array_values((array)$array) : null;
     }
@@ -72,10 +64,10 @@ public function values($array)
     /**
      * Cast value to an array
      *
-     * @param object|mixed $value
+     * @param mixed $value
      * @return array
      */
-    public function asArray($value)
+    public function asArray($value): array
     {
         return is_object($value) ? get_object_vars($value) : (array)$value;
     }
@@ -84,9 +76,9 @@ public function asArray($value)
      * Cast an array to an HTML attribute string
      *
      * @param mixed $array
-     * @return string
+     * @return string|null
      */
-    public function htmlAttributes($array)
+    public function htmlAttributes($array): ?string
     {
         if (!isset($array)) {
             return null;
diff --git a/app/vendor/jasny/twig-extensions/src/DateExtension.php b/app/vendor/jasny/twig-extensions/src/DateExtension.php
index 3c504a19d..363ecd7f7 100644
--- a/app/vendor/jasny/twig-extensions/src/DateExtension.php
+++ b/app/vendor/jasny/twig-extensions/src/DateExtension.php
@@ -1,7 +1,8 @@
-getFormat($dateFormat) : null;
-        $timetype = isset($timeFormat) ? $this->getFormat($timeFormat) : null;
+        $dateType = isset($dateFormat) ? $this->getFormat($dateFormat) : null;
+        $timeType = isset($timeFormat) ? $this->getFormat($timeFormat) : null;
 
         $calendarConst = $calendar === 'traditional' ? \IntlDateFormatter::TRADITIONAL : \IntlDateFormatter::GREGORIAN;
 
         $pattern = $this->getDateTimePattern(
-            isset($datetype) ? $datetype : $dateFormat,
-            isset($timetype) ? $timetype : $timeFormat,
+            $dateType ?? $dateFormat,
+            $timeType ?? $timeFormat,
             $calendarConst
         );
 
-        return new \IntlDateFormatter(\Locale::getDefault(), $datetype, $timetype, null, $calendarConst, $pattern);
+        return new \IntlDateFormatter(\Locale::getDefault(), $dateType, $timeType, null, $calendarConst, $pattern);
     }
 
     /**
      * Format the date/time value as a string based on the current locale
      *
-     * @param string|false $format  'short', 'medium', 'long', 'full', 'none' or false
+     * @param string $format  'short', 'medium', 'long', 'full', 'none' or false
      * @return int|null
      */
-    protected function getFormat($format)
+    protected function getFormat(string $format): ?int
     {
-        if ($format === false) {
-            $format = 'none';
-        }
-
         $types = [
             'none' => \IntlDateFormatter::NONE,
             'short' => \IntlDateFormatter::SHORT,
@@ -111,26 +106,26 @@ protected function getFormat($format)
             'full' => \IntlDateFormatter::FULL
         ];
 
-        return isset($types[$format]) ? $types[$format] : null;
+        return $types[$format] ?? null;
     }
 
     /**
      * Get the date/time pattern.
      *
-     * @param int|string $datetype
-     * @param int|string $timetype
-     * @param int        $calendar
+     * @param int|string|null $dateType
+     * @param int|string|null $timeType
+     * @param int $calendar
      * @return string
      */
-    protected function getDateTimePattern($datetype, $timetype, $calendar = \IntlDateFormatter::GREGORIAN)
+    protected function getDateTimePattern($dateType, $timeType, int $calendar = \IntlDateFormatter::GREGORIAN): ?string
     {
-        if (is_int($datetype) && is_int($timetype)) {
+        if (is_int($dateType) && is_int($timeType)) {
             return null;
         }
 
         return $this->getDatePattern(
-            isset($datetype) ? $datetype : \IntlDateFormatter::SHORT,
-            isset($timetype) ? $timetype : \IntlDateFormatter::SHORT,
+            $dateType ?? \IntlDateFormatter::SHORT,
+            $timeType ?? \IntlDateFormatter::SHORT,
             $calendar
         );
     }
@@ -138,17 +133,20 @@ protected function getDateTimePattern($datetype, $timetype, $calendar = \IntlDat
     /**
      * Get the formatter to create a date and/or time pattern
      *
-     * @param int|string $datetype
-     * @param int|string $timetype
+     * @param int|string $dateType
+     * @param int|string $timeType
      * @param int        $calendar
      * @return \IntlDateFormatter
      */
-    protected function getDatePatternFormatter($datetype, $timetype, $calendar = \IntlDateFormatter::GREGORIAN)
-    {
+    protected function getDatePatternFormatter(
+        $dateType,
+        $timeType,
+        int $calendar = \IntlDateFormatter::GREGORIAN
+    ): \IntlDateFormatter {
         return \IntlDateFormatter::create(
             \Locale::getDefault(),
-            is_int($datetype) ? $datetype : \IntlDateFormatter::NONE,
-            is_int($timetype) ? $timetype : \IntlDateFormatter::NONE,
+            is_int($dateType) ? $dateType : \IntlDateFormatter::NONE,
+            is_int($timeType) ? $timeType : \IntlDateFormatter::NONE,
             \IntlTimeZone::getGMT(),
             $calendar
         );
@@ -158,37 +156,41 @@ protected function getDatePatternFormatter($datetype, $timetype, $calendar = \In
      * Get the date and/or time pattern
      * Default date pattern is short date pattern with 4 digit year.
      *
-     * @param int|string $datetype
-     * @param int|string $timetype
-     * @param int        $calendar
+     * @param int|string $dateType
+     * @param int|string $timeType
+     * @param int $calendar
      * @return string
      */
-    protected function getDatePattern($datetype, $timetype, $calendar = \IntlDateFormatter::GREGORIAN)
+    protected function getDatePattern($dateType, $timeType, int $calendar = \IntlDateFormatter::GREGORIAN): string
     {
         $createPattern =
-            (is_int($datetype) && $datetype !== \IntlDateFormatter::NONE) ||
-            (is_int($timetype) && $timetype !== \IntlDateFormatter::NONE);
+            (is_int($dateType) && $dateType !== \IntlDateFormatter::NONE) ||
+            (is_int($timeType) && $timeType !== \IntlDateFormatter::NONE);
 
-        $pattern = $createPattern ? $this->getDatePatternFormatter($datetype, $timetype, $calendar)->getPattern() : '';
+        $pattern = $createPattern ? $this->getDatePatternFormatter($dateType, $timeType, $calendar)->getPattern() : '';
 
         return trim(
-            (is_string($datetype) ? $datetype . ' ' : '') .
+            (is_string($dateType) ? $dateType . ' ' : '') .
             preg_replace('/\byy?\b/', 'yyyy', $pattern) .
-            (is_string($timetype) ? ' ' . $timetype : '')
+            (is_string($timeType) ? ' ' . $timeType : '')
         );
     }
 
     /**
      * Format the date and/or time value as a string based on the current locale
      *
-     * @param \DateTime|int|string $value
-     * @param string               $dateFormat  null, 'short', 'medium', 'long', 'full' or pattern
-     * @param string               $timeFormat  null, 'short', 'medium', 'long', 'full' or pattern
-     * @param string               $calendar    'gregorian' or 'traditional'
-     * @return string
+     * @param DateTime|int|string|null $value
+     * @param string|null $dateFormat  null, 'none', 'short', 'medium', 'long', 'full' or pattern
+     * @param string|null $timeFormat  null, 'none', 'short', 'medium', 'long', 'full' or pattern
+     * @param string $calendar    'gregorian' or 'traditional'
+     * @return string|null
      */
-    protected function formatLocal($value, $dateFormat, $timeFormat, $calendar = 'gregorian')
-    {
+    protected function formatLocal(
+        $value,
+        ?string $dateFormat,
+        ?string $timeFormat,
+        string $calendar = 'gregorian'
+    ): ?string {
         if (!isset($value)) {
             return null;
         }
@@ -202,42 +204,42 @@ protected function formatLocal($value, $dateFormat, $timeFormat, $calendar = 'gr
     /**
      * Format the date value as a string based on the current locale
      *
-     * @param \DateTime|int|string $date
-     * @param string               $format    null, 'short', 'medium', 'long', 'full' or pattern
-     * @param string               $calendar  'gregorian' or 'traditional'
-     * @return string
+     * @param DateTime|int|string|null $date
+     * @param string|null $format    null, 'short', 'medium', 'long', 'full' or pattern
+     * @param string $calendar  'gregorian' or 'traditional'
+     * @return string|null
      */
-    public function localDate($date, $format = null, $calendar = 'gregorian')
+    public function localDate($date, ?string $format = null, string $calendar = 'gregorian'): ?string
     {
-        return $this->formatLocal($date, $format, false, $calendar);
+        return $this->formatLocal($date, $format, 'none', $calendar);
     }
 
     /**
      * Format the time value as a string based on the current locale
      *
-     * @param \DateTime|int|string $date
-     * @param string               $format    'short', 'medium', 'long', 'full' or pattern
-     * @param string               $calendar  'gregorian' or 'traditional'
-     * @return string
+     * @param DateTime|int|string|null $date
+     * @param string $format    'short', 'medium', 'long', 'full' or pattern
+     * @param string $calendar  'gregorian' or 'traditional'
+     * @return string|null
      */
-    public function localTime($date, $format = 'short', $calendar = 'gregorian')
+    public function localTime($date, string $format = 'short', string $calendar = 'gregorian'): ?string
     {
-        return $this->formatLocal($date, false, $format, $calendar);
+        return $this->formatLocal($date, 'none', $format, $calendar);
     }
 
     /**
      * Format the date/time value as a string based on the current locale
      *
-     * @param \DateTime|int|string $date
-     * @param string               $format    date format, pattern or ['date'=>format, 'time'=>format)
-     * @param string               $calendar  'gregorian' or 'traditional'
+     * @param DateTime|int|string|null $date
+     * @param string|array|\stdClass|null $format    date format, pattern or ['date'=>format, 'time'=>format)
+     * @param string $calendar  'gregorian' or 'traditional'
      * @return string
      */
-    public function localDateTime($date, $format = null, $calendar = 'gregorian')
+    public function localDateTime($date, $format = null, string $calendar = 'gregorian'): ?string
     {
         if (is_array($format) || $format instanceof \stdClass || !isset($format)) {
-            $formatDate = isset($format['date']) ? $format['date'] : null;
-            $formatTime = isset($format['time']) ? $format['time'] : 'short';
+            $formatDate = $format['date'] ?? null;
+            $formatTime = $format['time'] ?? 'short';
         } else {
             $formatDate = $format;
             $formatTime = false;
@@ -251,9 +253,10 @@ public function localDateTime($date, $format = null, $calendar = 'gregorian')
      * Split duration into seconds, minutes, hours, days, weeks and years.
      *
      * @param int $seconds
+     * @param int $max
      * @return array
      */
-    protected function splitDuration($seconds, $max)
+    protected function splitDuration(int $seconds, int $max): array
     {
         if ($max < 1 || $seconds < 60) {
             return [$seconds];
@@ -294,13 +297,16 @@ protected function splitDuration($seconds, $max)
      *
      * Use null to skip a unit.
      *
-     * @param int    $value     Time in seconds
-     * @param array  $units     Time units (seconds, minutes, hours, days, weeks, years)
+     * @param int|null $value     Time in seconds
+     * @param array $units     Time units (seconds, minutes, hours, days, weeks, years)
      * @param string $separator
      * @return string
      */
-    public function duration($value, $units = ['s', 'm', 'h', 'd', 'w', 'y'], $separator = ' ')
-    {
+    public function duration(
+        ?int $value,
+        array $units = ['s', 'm', 'h', 'd', 'w', 'y'],
+        string $separator = ' '
+    ): ?string {
         if (!isset($value)) {
             return null;
         }
@@ -321,10 +327,10 @@ public function duration($value, $units = ['s', 'm', 'h', 'd', 'w', 'y'], $separ
     /**
      * Get the age (in years) based on a date.
      *
-     * @param \DateTime|string $value
-     * @return int
+     * @param DateTime|string|null $value
+     * @return int|null
      */
-    public function age($value)
+    public function age($value): ?int
     {
         if (!isset($value)) {
             return null;
@@ -332,6 +338,6 @@ public function age($value)
 
         $date = $this->valueToDateTime($value);
 
-        return $date->diff(new \DateTime())->format('%y');
+        return (int)$date->diff(new DateTime())->format('%y');
     }
 }
diff --git a/app/vendor/jasny/twig-extensions/src/PcreExtension.php b/app/vendor/jasny/twig-extensions/src/PcreExtension.php
index 5bdc2911f..3832b9348 100644
--- a/app/vendor/jasny/twig-extensions/src/PcreExtension.php
+++ b/app/vendor/jasny/twig-extensions/src/PcreExtension.php
@@ -25,10 +25,8 @@ public function __construct()
 
     /**
      * Return extension name
-     *
-     * @return string
      */
-    public function getName()
+    public function getName(): string
     {
         return 'jasny/pcre';
     }
@@ -36,7 +34,7 @@ public function getName()
     /**
      * {@inheritdoc}
      */
-    public function getFilters()
+    public function getFilters(): array
     {
         return [
             new TwigFilter('preg_quote', [$this, 'quote']),
@@ -54,28 +52,26 @@ public function getFilters()
     /**
      * Check that the regex doesn't use the eval modifier
      *
-     * @param string $pattern
-     * @throws \LogicException
+     * @throws RuntimeError
      */
-    protected function assertNoEval($pattern)
+    protected function assertNoEval(string ...$pattern): void
     {
-        $pos = strrpos($pattern, $pattern[0]);
-        $modifiers = substr($pattern, $pos + 1);
+        $patterns = $pattern;
+
+        foreach ($patterns as $pattern) {
+            $pos       = strrpos($pattern, $pattern[0]);
+            $modifiers = substr($pattern, $pos + 1);
 
-        if (strpos($modifiers, 'e') !== false) {
-            throw new RuntimeError("Using the eval modifier for regular expressions is not allowed");
+            if (strpos($modifiers, 'e') !== false) {
+                throw new RuntimeError("Using the eval modifier for regular expressions is not allowed");
+            }
         }
     }
 
-
     /**
      * Quote regular expression characters.
-     *
-     * @param string $value
-     * @param string $delimiter
-     * @return string
      */
-    public function quote($value, $delimiter = '/')
+    public function quote(?string $value, string $delimiter = '/'): ?string
     {
         if (!isset($value)) {
             return null;
@@ -85,63 +81,72 @@ public function quote($value, $delimiter = '/')
     }
 
     /**
-     * Perform a regular expression match.
+     * Wrapper for preg_match that throws an exception on error.
      *
-     * @param string $value
-     * @param string $pattern
-     * @return boolean
+     * @throws RuntimeError
+     */
+    private function pregMatch(string $pattern, string $value, &$matches = []): int
+    {
+        $ret = preg_match($pattern, $value, $matches);
+
+        if ($ret === false) {
+            throw new RuntimeError("Error in regular expression: $pattern");
+        }
+
+        return $ret;
+    }
+
+    /**
+     * Perform a regular expression match.
      */
-    public function match($value, $pattern)
+    public function match(?string $value, string $pattern): bool
     {
         if (!isset($value)) {
-            return null;
+            return false;
         }
 
-        return preg_match($pattern, $value);
+        return $this->pregMatch($pattern, $value) > 0;
     }
 
     /**
      * Perform a regular expression match and return a matched group.
-     *
-     * @param string $value
-     * @param string $pattern
-     * @return string
      */
-    public function get($value, $pattern, $group = 0)
+    public function get(?string $value, string $pattern, int $group = 0): ?string
     {
         if (!isset($value)) {
             return null;
         }
 
-        return preg_match($pattern, $value, $matches) && isset($matches[$group]) ? $matches[$group] : null;
+        return $this->pregMatch($pattern, $value, $matches) > 0 && isset($matches[$group]) ? $matches[$group] : null;
     }
 
     /**
      * Perform a regular expression match and return the group for all matches.
-     *
-     * @param string $value
-     * @param string $pattern
-     * @return array
      */
-    public function getAll($value, $pattern, $group = 0)
+    public function getAll(?string $value, string $pattern, int $group = 0): ?array
     {
         if (!isset($value)) {
             return null;
         }
 
-        return preg_match_all($pattern, $value, $matches, PREG_PATTERN_ORDER) && isset($matches[$group])
-            ? $matches[$group] : [];
+        $ret = preg_match_all($pattern, $value, $matches, PREG_PATTERN_ORDER);
+
+        if ($ret === false) {
+            throw new RuntimeError("Error in regular expression: $pattern");
+        }
+
+        return $ret > 0 && isset($matches[$group]) ? $matches[$group] : [];
     }
 
     /**
      * Perform a regular expression match and return an array of entries that match the pattern
      *
-     * @param array  $values
+     * @param array|null $values
      * @param string $pattern
      * @param string $flags    Optional 'invert' to return entries that do not match the given pattern.
      * @return array
      */
-    public function grep($values, $pattern, $flags = '')
+    public function grep(?array $values, string $pattern, string $flags = ''): ?array
     {
         if (!isset($values)) {
             return null;
@@ -151,62 +156,84 @@ public function grep($values, $pattern, $flags = '')
             $flags = $flags === 'invert' ? PREG_GREP_INVERT : 0;
         }
 
-        return preg_grep($pattern, $values, $flags);
+        $ret = preg_grep($pattern, $values, $flags);
+
+        if ($ret === false) {
+            throw new RuntimeError("Error in regular expression: $pattern");
+        }
+
+        return $ret;
     }
 
     /**
      * Perform a regular expression search and replace.
      *
-     * @param string $value
-     * @param string $pattern
-     * @param string $replacement
-     * @param int    $limit
-     * @return string
+     * @param string|array|null $value
+     * @param string|array $pattern
+     * @param string|array $replacement
+     * @param int $limit
+     * @return string|array|null
+     * @throws RuntimeError
      */
-    public function replace($value, $pattern, $replacement = '', $limit = -1)
+    public function replace($value, $pattern, $replacement = '', int $limit = -1)
     {
-        $this->assertNoEval($pattern);
+        $this->assertNoEval(...(array)$pattern);
 
         if (!isset($value)) {
             return null;
         }
 
-        return preg_replace($pattern, $replacement, $value, $limit);
+        $ret = preg_replace($pattern, $replacement, $value, $limit);
+
+        if ($ret === null) {
+            throw new RuntimeError("Error in regular expression: $pattern");
+        }
+
+        return $ret;
     }
 
     /**
      * Perform a regular expression search and replace, returning only matched subjects.
      *
-     * @param string $value
-     * @param string $pattern
-     * @param string $replacement
-     * @param int    $limit
-     * @return string
+     * @param string|array|null $value
+     * @param string|array $pattern
+     * @param string|array $replacement
+     * @param int $limit
+     * @return string|array|null
+     * @throws RuntimeError
      */
-    public function filter($value, $pattern, $replacement = '', $limit = -1)
+    public function filter($value, $pattern, $replacement = '', int $limit = -1)
     {
-        $this->assertNoEval($pattern);
+        $this->assertNoEval(...(array)$pattern);
 
         if (!isset($value)) {
             return null;
         }
 
-        return preg_filter($pattern, $replacement, $value, $limit);
+        $ret = preg_filter($pattern, $replacement, $value, $limit);
+
+        if ($ret === null) {
+            throw new RuntimeError("Error in regular expression: $pattern");
+        }
+
+        return $ret;
     }
 
     /**
      * Split text into an array using a regular expression.
-     *
-     * @param string $value
-     * @param string $pattern
-     * @return array
      */
-    public function split($value, $pattern)
+    public function split(?string $value, string $pattern): array
     {
         if (!isset($value)) {
-            return null;
+            return [];
+        }
+
+        $ret = preg_split($pattern, $value);
+
+        if ($ret === false) {
+            throw new RuntimeError("Error in regular expression: $pattern");
         }
 
-        return preg_split($pattern, $value);
+        return $ret;
     }
 }
diff --git a/app/vendor/jasny/twig-extensions/src/TextExtension.php b/app/vendor/jasny/twig-extensions/src/TextExtension.php
index 35bfbd220..947b846e2 100644
--- a/app/vendor/jasny/twig-extensions/src/TextExtension.php
+++ b/app/vendor/jasny/twig-extensions/src/TextExtension.php
@@ -36,11 +36,8 @@ public function getFilters()
 
     /**
      * Add paragraph and line breaks to text.
-     *
-     * @param string $value
-     * @return string
      */
-    public function paragraph($value)
+    public function paragraph(?string $value): ?string
     {
         if (!isset($value)) {
             return null;
@@ -53,11 +50,11 @@ public function paragraph($value)
     /**
      * Get a single line
      *
-     * @param string $value
+     * @param string|null $value
      * @param int    $line   Line number (starts at 1)
-     * @return string
+     * @return string|null
      */
-    public function line($value, $line = 1)
+    public function line(?string $value, int $line = 1): ?string
     {
         if (!isset($value)) {
             return null;
@@ -65,18 +62,13 @@ public function line($value, $line = 1)
 
         $lines = explode("\n", $value);
 
-        return isset($lines[$line - 1]) ? $lines[$line - 1] : null;
+        return $lines[$line - 1] ?? null;
     }
 
     /**
-     * Cut of text on a pagebreak.
-     *
-     * @param string $value
-     * @param string $replace
-     * @param string $break
-     * @return string
+     * Cut of text on a page break.
      */
-    public function less($value, $replace = '...', $break = '')
+    public function less(?string $value, string $replace = '...', string $break = ''): ?string
     {
         if (!isset($value)) {
             return null;
@@ -87,14 +79,9 @@ public function less($value, $replace = '...', $break = '')
     }
 
     /**
-     * Cut of text if it's to long.
-     *
-     * @param string $value
-     * @param int    $length
-     * @param string $replace
-     * @return string
+     * Cut of text if it's too long.
      */
-    public function truncate($value, $length, $replace = '...')
+    public function truncate(?string $value, int $length, string $replace = '...'): ?string
     {
         if (!isset($value)) {
             return null;
@@ -113,7 +100,7 @@ public function truncate($value, $length, $replace = '...')
      * @param string $mode
      * @return string
      */
-    protected function linkifyHttp($protocol, $text, array &$links, $attr, $mode)
+    protected function linkifyHttp(string $protocol, string $text, array &$links, string $attr, string $mode): string
     {
         $regexp = $mode != 'all'
             ? '~(?:(https?)://([^\s<>]+)|(?]+?\.[^\s<>]+))(?]+?@[^\s<>]+?\.[^\s<>]+)(?]+?@[^\s<>]+?\.[^\s<>]+)(?' . $match[1] . '')
@@ -159,7 +146,7 @@ protected function linkifyMail($text, array &$links, $attr)
      * @param string $mode
      * @return string
      */
-    protected function linkifyOther($protocol, $text, array &$links, $attr, $mode)
+    protected function linkifyOther(string $protocol, string $text, array &$links, string $attr, string $mode): string
     {
         if (strpos($protocol, ':') === false) {
             $protocol .= in_array($protocol, ['ftp', 'tftp', 'ssh', 'scp']) ? '://' : ':';
@@ -178,14 +165,18 @@ protected function linkifyOther($protocol, $text, array &$links, $attr, $mode)
     /**
      * Turn all URLs in clickable links.
      *
-     * @param string $value
-     * @param array  $protocols   'http'/'https', 'mail' and also 'ftp', 'scp', 'tel', etc
+     * @param string|null $value
+     * @param array|string $protocols 'http'/'https', 'mail' and also 'ftp', 'scp', 'tel', etc
      * @param array  $attributes  HTML attributes for the link
      * @param string $mode        normal or all
      * @return string
      */
-    public function linkify($value, $protocols = ['http', 'mail'], array $attributes = [], $mode = 'normal')
-    {
+    public function linkify(
+        ?string $value,
+        $protocols = ['http', 'mail'],
+        array $attributes = [],
+        string $mode = 'normal'
+    ): ?string {
         if (!isset($value)) {
             return null;
         }
diff --git a/app/vendor/jasny/twig-extensions/tests/ArrayExtensionTest.php b/app/vendor/jasny/twig-extensions/tests/ArrayExtensionTest.php
index bc43bf304..28aee8c45 100644
--- a/app/vendor/jasny/twig-extensions/tests/ArrayExtensionTest.php
+++ b/app/vendor/jasny/twig-extensions/tests/ArrayExtensionTest.php
@@ -1,9 +1,9 @@
 markAsSkipped("Unable to set locale to 'en_EN'");
-        }
-
+        \Locale::setDefault("en_US");
         $this->assertRender($en, $template);
     }
 
@@ -67,18 +64,14 @@ public function testLocalDateTimeEn($en, $nl, $template)
      * @param string $nl
      * @param string $template
      */
-    public function testLocalDateTimeNL($en, $nl, $template)
+    public function testLocalDateTimeNL($en, $nl, $template): void
     {
-        if (!\Locale::setDefault("nl_NL")) {
-            return $this->markAsSkipped("Unable to set locale to 'nl_NL'");
-        }
-
+        \Locale::setDefault("nl_NL");
         $this->assertRender($nl, $template);
-
     }
 
 
-    public function durationProvider()
+    public function durationProvider(): array
     {
         return [
             ['31s', "{{ 31|duration }}"],
@@ -111,7 +104,7 @@ public function testDuration($expect, $template)
     }
 
 
-    public function ageProvider()
+    public function ageProvider(): array
     {
         $time = time() - (((32 * 365) + 100) * 24 * 3600);
         $date = date('Y-m-d', $time);
@@ -134,7 +127,7 @@ public function testAge($expect, $template)
     }
 
 
-    public function filterProvider()
+    public static function filterProvider(): array
     {
         return [
             ['localdate'],
@@ -147,11 +140,10 @@ public function filterProvider()
 
     /**
      * @dataProvider filterProvider
-     *
-     * @param string $filter
      */
-    public function testWithNull($filter)
+    public function testWithNull(string $filter, $arg = null)
     {
-        $this->assertRender('-', '{{ null|' . $filter . '("//")|default("-") }}');
+        $call = $filter . ($arg ? '(' . json_encode($arg) . ')' : '');
+        $this->assertRender('-', '{{ null|' . $call  . '|default("-") }}');
     }
 }
diff --git a/app/vendor/jasny/twig-extensions/tests/PcreExtensionTest.php b/app/vendor/jasny/twig-extensions/tests/PcreExtensionTest.php
index 92a5c0a75..ecaa27f28 100644
--- a/app/vendor/jasny/twig-extensions/tests/PcreExtensionTest.php
+++ b/app/vendor/jasny/twig-extensions/tests/PcreExtensionTest.php
@@ -1,9 +1,9 @@
 assertRender(
+            '0000AAAA',
+            "{{ '1234ABCD'|preg_replace(['/\\\\d/','/[A-Z]/'],['0', 'A']) }}"
+        );
+    }
+
     public function testReplaceAssertNoEval()
     {
         $this->expectException(TwigRuntimeError::class);
diff --git a/app/vendor/jasny/twig-extensions/tests/TextExtensionTest.php b/app/vendor/jasny/twig-extensions/tests/TextExtensionTest.php
index 6c72c345d..50fdcb08d 100644
--- a/app/vendor/jasny/twig-extensions/tests/TextExtensionTest.php
+++ b/app/vendor/jasny/twig-extensions/tests/TextExtensionTest.php
@@ -1,9 +1,9 @@
  ['paragraph', '/'],
+            'line' => ['line', 1],
+            'less' => ['less'],
+            'truncate' => ['truncate', 10],
+            'linkify' => ['linkify']
         ];
     }
     
     /**
      * @dataProvider filterProvider
-     * 
-     * @param string $filter
      */
-    public function testWithNull($filter)
+    public function testWithNull(string $filter, $arg = null)
     {
-        $this->assertRender('-', '{{ null|' . $filter . '("//")|default("-") }}');
-    }    
+        $call = $filter . ($arg ? '(' . json_encode($arg) . ')' : '');
+        $this->assertRender('-', '{{ null|' . $call  . '|default("-") }}');
+    }
 }
diff --git a/app/vendor/jasny/twig-extensions/tests/support/TestHelper.php b/app/vendor/jasny/twig-extensions/tests/support/TestHelper.php
index 66214b532..41317d98a 100644
--- a/app/vendor/jasny/twig-extensions/tests/support/TestHelper.php
+++ b/app/vendor/jasny/twig-extensions/tests/support/TestHelper.php
@@ -1,8 +1,9 @@
 in([__DIR__ . '/src', __DIR__ . '/tests']);
+
+/* Based on ^2.1 of php-cs-fixer */
+$config
+    ->setRules([
+        // default
+        '@PSR2' => true,
+        '@Symfony' => true,
+        // additionally
+        'array_syntax' => ['syntax' => 'short'],
+        'binary_operator_spaces' => false,
+        'concat_space' => ['spacing' => 'one'],
+        'increment_style' => false,
+        'no_superfluous_phpdoc_tags' => false,
+        'no_useless_else' => true,
+        'no_useless_return' => true,
+        'ordered_imports' => true,
+        'phpdoc_no_package' => false,
+        'phpdoc_order' => true,
+        'phpdoc_summary' => false,
+        'phpdoc_types_order' => ['null_adjustment' => 'none', 'sort_algorithm' => 'none'],
+        'simplified_null_return' => false,
+        'single_line_throw' => false,
+        'trailing_comma_in_multiline' => false,
+        'yoda_style' => false,
+    ])
+    ->setFinder($finder)
+;
+
+return $config;
diff --git a/app/vendor/justinrainbow/json-schema/CHANGELOG.md b/app/vendor/justinrainbow/json-schema/CHANGELOG.md
new file mode 100644
index 000000000..83e1582d2
--- /dev/null
+++ b/app/vendor/justinrainbow/json-schema/CHANGELOG.md
@@ -0,0 +1,161 @@
+# CHANGELOG
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [Unreleased]
+
+## [6.4.2] - 2025-06-03
+### Fixed
+- Fix objects are non-unique despite key order ([#819](https://github.com/jsonrainbow/json-schema/pull/819))
+- Id's not being resolved and id property affects sibling ref which it should not do ([#828](https://github.com/jsonrainbow/json-schema/pull/828)) 
+
+### Changed
+- Added extra breaking change to UPDATE-6.0.md regarding BaseConstraint::addError signature change ([#823](https://github.com/jsonrainbow/json-schema/pull/823))
+- Update constraint class to PHP 7.2 language level ([#824](https://github.com/jsonrainbow/json-schema/pull/824))
+- Update base constraint class to PHP 7.2 language level ([#826](https://github.com/jsonrainbow/json-schema/pull/826))
+
+### Added
+- Introduce 32 bits CI workflow on latest php version ([#825](https://github.com/jsonrainbow/json-schema/pull/825))
+
+## [6.4.1] - 2025-04-04
+### Fixed
+- Fix support for 32bits PHP ([#817](https://github.com/jsonrainbow/json-schema/pull/817))
+
+## [6.4.0] - 2025-04-01
+### Added
+- Run PHPStan using the lowest and highest php version ([#811](https://github.com/jsonrainbow/json-schema/pull/811))
+### Fixed
+- Use parallel-lint and cs2pr for improved feedback on linting errors ([#812](https://github.com/jsonrainbow/json-schema/pull/812))
+- Array with number values with mathematical equality are considered valid ([#813](https://github.com/jsonrainbow/json-schema/pull/813))
+### Changed
+- Correct PHPStan findings in validator ([#808](https://github.com/jsonrainbow/json-schema/pull/808))
+- Add cs2pr handling for php-cs-fixer; avoid doing composer install ([#814](https://github.com/jsonrainbow/json-schema/pull/814))
+- prepare PHP 8.5 in CI ([#815](https://github.com/jsonrainbow/json-schema/pull/815))
+
+## [6.3.1] - 2025-03-18
+### Fixed
+- ensure numeric issues in const are correctly evaluated ([#805](https://github.com/jsonrainbow/json-schema/pull/805))
+- fix 6.3.0 regression with comparison of null values during validation ([#806](https://github.com/jsonrainbow/json-schema/issues/806))
+
+## [6.3.0] - 2025-03-14
+### Fixed
+- only check minProperties or maxProperties on objects ([#802](https://github.com/jsonrainbow/json-schema/pull/802))
+- replace filter_var for uri and uri-reference to userland code to be RFC 3986 compliant ([#800](https://github.com/jsonrainbow/json-schema/pull/800))
+- avoid duplicate workflow runs ([#804](https://github.com/jsonrainbow/json-schema/pull/804))
+
+## Changed
+- replace icecave/parity with custom deep comparator ([#803](https://github.com/jsonrainbow/json-schema/pull/803))
+ 
+## [6.2.1] - 2025-03-06
+### Fixed
+- allow items: true to pass validation ([#801](https://github.com/jsonrainbow/json-schema/pull/801))
+
+### Changed
+- Include actual count in collection constraint errors ([#797](https://github.com/jsonrainbow/json-schema/pull/797))
+
+## [6.2.0] - 2025-02-26
+### Added
+- Welcome first time contributors ([#782](https://github.com/jsonrainbow/json-schema/pull/782))
+
+### Fixed
+- Add required permissions for welcome action ([#789](https://github.com/jsonrainbow/json-schema/pull/789))
+- Upgrade php cs fixer to latest ([#783](https://github.com/jsonrainbow/json-schema/pull/783))
+- Create deep copy before checking each sub schema in oneOf ([#791](https://github.com/jsonrainbow/json-schema/pull/791))
+- Create deep copy before checking each sub schema in anyOf ([#792](https://github.com/jsonrainbow/json-schema/pull/792))
+- Correctly set the schema ID when passing it as assoc array ([#794](https://github.com/jsonrainbow/json-schema/pull/794))
+- Create deep copy before checking each sub schema in oneOf when only check_mode_apply_defaults is set ([#795](https://github.com/jsonrainbow/json-schema/pull/795))
+- Additional property casted into int when actually is numeric string ([#784](https://github.com/jsonrainbow/json-schema/pull/784))
+
+### Changed
+- Used PHPStan's int-mask-of type where applicable ([#779](https://github.com/jsonrainbow/json-schema/pull/779))
+- Fixed some PHPStan errors ([#781](https://github.com/jsonrainbow/json-schema/pull/781))
+- Cleanup redundant checks ([#796](https://github.com/jsonrainbow/json-schema/pull/796))
+
+## [6.1.0] - 2025-02-04
+### Added
+- Add return types in the test suite ([#748](https://github.com/jsonrainbow/json-schema/pull/748))
+- Add test case for validating array of strings with objects ([#704](https://github.com/jsonrainbow/json-schema/pull/704))
+- Add contributing information, contributor recognition and security information ([#771](https://github.com/jsonrainbow/json-schema/pull/771)) 
+
+### Fixed
+- Correct misconfigured mocks in JsonSchema\Tests\Uri\UriRetrieverTest ([#741](https://github.com/jsonrainbow/json-schema/pull/741))
+- Fix pugx badges in README ([#742](https://github.com/jsonrainbow/json-schema/pull/742))
+- Add missing property in UriResolverTest ([#743](https://github.com/jsonrainbow/json-schema/pull/743))
+- Correct casing of paths used in tests ([#745](https://github.com/jsonrainbow/json-schema/pull/745))
+- Resolve deprecations of optional parameter ([#752](https://github.com/jsonrainbow/json-schema/pull/752))
+- Fix wrong combined paths when traversing upward, fixes #557 ([#652](https://github.com/jsonrainbow/json-schema/pull/652))
+- Correct PHPStan baseline ([#764](https://github.com/jsonrainbow/json-schema/pull/764))
+- Correct spacing issue in `README.md` ([#763](https://github.com/jsonrainbow/json-schema/pull/763))
+- Format attribute: do not validate data instances that aren't the instance type to validate ([#773](https://github.com/jsonrainbow/json-schema/pull/773))
+
+### Changed
+- Bump to minimum PHP 7.2 ([#746](https://github.com/jsonrainbow/json-schema/pull/746))
+- Replace traditional syntax array with short syntax array ([#747](https://github.com/jsonrainbow/json-schema/pull/747))
+- Increase phpstan level to 8 with baseline to swallow existing errors ([#673](https://github.com/jsonrainbow/json-schema/pull/673))
+- Add ext-json to composer.json to ensure JSON extension available  ([#759](https://github.com/jsonrainbow/json-schema/pull/759))
+- Add visibility modifiers to class constants ([#757](https://github.com/jsonrainbow/json-schema/pull/757))
+- Include PHP 8.4 in workflow ([#765](https://github.com/jsonrainbow/json-schema/pull/765))
+- Add `strict_types=1` to all classes in ./src ([#758](https://github.com/jsonrainbow/json-schema/pull/758))
+- Raise minimum level of marc-mabe/php-enum ([#766](https://github.com/jsonrainbow/json-schema/pull/766))
+- Cleanup test from @param annotations ([#768](https://github.com/jsonrainbow/json-schema/pull/768))
+- Remove obsolete PHP 7.1 version check ([#772](https://github.com/jsonrainbow/json-schema/pull/772))
+
+## [6.0.0] - 2024-07-30
+### Added
+- Add URI translation, package:// URI scheme & bundle spec schemas ([#362](https://github.com/jsonrainbow/json-schema/pull/362))
+- Add quiet option ([#382](https://github.com/jsonrainbow/json-schema/pull/382))
+- Add option to disable validation of "format" constraint ([#383](https://github.com/jsonrainbow/json-schema/pull/383))
+- Add more unit tests ([#366](https://github.com/jsonrainbow/json-schema/pull/366))
+- Reset errors prior to validation ([#386](https://github.com/jsonrainbow/json-schema/pull/386))
+- Allow the schema to be an associative array ([#389](https://github.com/jsonrainbow/json-schema/pull/389))
+- Enable FILTER_FLAG_EMAIL_UNICODE for email format if present ([#398](https://github.com/jsonrainbow/json-schema/pull/398))
+- Add enum wrapper ([#375](https://github.com/jsonrainbow/json-schema/pull/375))
+- Add option to validate the schema ([#357](https://github.com/jsonrainbow/json-schema/pull/357))
+- Add support for "const" ([#507](https://github.com/jsonrainbow/json-schema/pull/507))
+- Added note about supported Draft versions ([#620](https://github.com/jsonrainbow/json-schema/pull/620))
+- Add linting GH action
+### Changed
+- Centralize errors ([#364](https://github.com/jsonrainbow/json-schema/pull/364))
+- Revert "An email is a string, not much else." ([#373](https://github.com/jsonrainbow/json-schema/pull/373))
+- Improvements to type coercion ([#384](https://github.com/jsonrainbow/json-schema/pull/384))
+- Don't add a file:// prefix to URI that already have a scheme ([#455](https://github.com/jsonrainbow/json-schema/pull/455))
+- Enhancement: Normalize` composer.json` ([#505](https://github.com/jsonrainbow/json-schema/pull/505))
+- Correct echo `sprintf` for `printf` ([#634](https://github.com/jsonrainbow/json-schema/pull/634))
+- Streamline validation of Regex ([#650](https://github.com/jsonrainbow/json-schema/pull/650))
+- Streamline validation of patternProperties Regex ([#653](https://github.com/jsonrainbow/json-schema/pull/653))
+- Switch to GH Actions ([#670](https://github.com/jsonrainbow/json-schema/pull/670))
+- Updated PHPStan
+- Remove unwanted whitespace ([#700](https://github.com/jsonrainbow/json-schema/pull/700))
+- Bump to v4 versions of GitHub actions ([#722](https://github.com/jsonrainbow/json-schema/pull/722))
+- Update references to jsonrainbow ([#725](https://github.com/jsonrainbow/json-schema/pull/725))
+### Deprecated
+- Mark check() and coerce() as deprecated ([#476](https://github.com/jsonrainbow/json-schema/pull/476))
+### Removed
+- Remove stale files from #357 (obviated by #362) ([#400](https://github.com/jsonrainbow/json-schema/pull/400))
+- Remove unnecessary fallbacks when args accept null
+- Removed unused variable in UndefinedConstraint ([#698](https://github.com/jsonrainbow/json-schema/pull/698))
+- Remove dead block of code ([#710](https://github.com/jsonrainbow/json-schema/pull/710))
+### Fixed
+- Add use line for InvalidArgumentException ([#370](https://github.com/jsonrainbow/json-schema/pull/370))
+- Add use line for InvalidArgumentException & adjust scope ([#372](https://github.com/jsonrainbow/json-schema/pull/372))
+- Add provided schema under a dummy / internal URI (fixes #376) ([#378](https://github.com/jsonrainbow/json-schema/pull/378))
+- Don't throw exceptions until after checking anyOf / oneOf ([#394](https://github.com/jsonrainbow/json-schema/pull/394))
+- Fix infinite recursion on some schemas when setting defaults (#359) ([#365](https://github.com/jsonrainbow/json-schema/pull/365))
+- Fix autoload to work properly with composer dependencies ([#401](https://github.com/jsonrainbow/json-schema/pull/401))
+- Ignore $ref siblings & abort on infinite-loop references ([#437](https://github.com/jsonrainbow/json-schema/pull/437))
+- Don't cast multipleOf to be an integer for the error message ([#471](https://github.com/jsonrainbow/json-schema/pull/471))
+- Strict Enum/Const Object Checking ([#518](https://github.com/jsonrainbow/json-schema/pull/518))
+- Return original value when no cast ([#535](https://github.com/jsonrainbow/json-schema/pull/535))
+- Allow `marc-mabe/php-enum` v2.x and v3.x. ([#464](https://github.com/jsonrainbow/json-schema/pull/464))
+- Deprecated warning message on composer install command ([#614](https://github.com/jsonrainbow/json-schema/pull/614))
+- Allow `marc-mabe/php-enum` v4.x ([#629](https://github.com/jsonrainbow/json-schema/pull/629))
+- Fixed method convertJsonPointerIntoPropertyPath in wrong class ([#655](https://github.com/jsonrainbow/json-schema/pull/655))
+- Fix type validation failing for "any" and false-y type wording ([#686](https://github.com/jsonrainbow/json-schema/pull/686))
+- Correct code style
+- Fix: Clean up `.gitattributes` ([#687](https://github.com/jsonrainbow/json-schema/pull/687))
+- Fix: Order `friendsofphp/php-cs-fixer` rules ([#688](https://github.com/jsonrainbow/json-schema/pull/688))
+- HTTP to HTTPS redirection breaks remote reference resolution ([#709](https://github.com/jsonrainbow/json-schema/pull/709))
+- Corrected several typos and code style issues
diff --git a/app/vendor/justinrainbow/json-schema/CONTRIBUTING.md b/app/vendor/justinrainbow/json-schema/CONTRIBUTING.md
new file mode 100644
index 000000000..0ca886d8b
--- /dev/null
+++ b/app/vendor/justinrainbow/json-schema/CONTRIBUTING.md
@@ -0,0 +1,96 @@
+# Contributing to JSON Schema
+
+First off, thanks for taking the time to contribute! ❤️
+
+All types of contributions are encouraged and valued. See the [Table of Contents](#table-of-contents) for different ways to help and details about how this project handles them. Please make sure to read the relevant section before making your contribution. It will make it a lot easier for us maintainers and smooth out the experience for all involved. The community looks forward to your contributions. 🎉
+
+> And if you like the project, but just don't have time to contribute, that's fine. There are other easy ways to support the project and show your appreciation, which we would also be very happy about:
+> - Star the project
+> - Tweet about it
+> - Refer this project in your project's readme
+> - Mention the project at local meetups and tell your friends/colleagues
+
+## Table of Contents
+
+- [I Have a Question](#i-have-a-question)
+- [I Want To Contribute](#i-want-to-contribute)
+- [Reporting Bugs](#reporting-bugs)
+- [Suggesting Enhancements](#suggesting-enhancements)
+
+## I Have a Question
+
+> If you want to ask a question, we assume that you have read the available [Documentation](https://github.com/jsonrainbow/json-schema/wiki).
+
+Before you ask a question, it is best to search for existing [Issues](https://github.com/jsonrainbow/json-schema/issues) that might help you. In case you have found a suitable issue and still need clarification, you can write your question in this issue. It is also advisable to search the internet for answers first.
+
+If you then still feel the need to ask a question and need clarification, we recommend the following:
+
+- Open an [Issue](https://github.com/jsonrainbow/json-schema/issues/new).
+- Provide as much context as you can about what you're running into.
+- Provide project and PHP version, depending on what seems relevant.
+
+We will then take care of the issue as soon as possible.
+
+## I Want To Contribute
+
+> ### Legal Notice
+> When contributing to this project, you must agree that you have authored 100% of the content, that you have the necessary rights to the content and that the content you contribute may be provided under the project licence.
+
+## Reporting Bugs
+
+### Before Submitting a Bug Report
+
+A good bug report shouldn't leave others needing to chase you up for more information. Therefore, we ask you to investigate carefully, collect information and describe the issue in detail in your report. Please complete the following steps in advance to help us fix any potential bug as fast as possible.
+
+- Make sure that you are using the latest version.
+- Determine if your bug is really a bug and not an error on your side e.g. using incompatible environment components/versions (Make sure that you have read the [documentation](https://github.com/jsonrainbow/json-schema/wiki). If you are looking for support, you might want to check [this section](#i-have-a-question)).
+- To see if other users have experienced (and potentially already solved) the same issue you are having, check if there is not already a bug report existing for your bug or error in the [bug tracker](https://github.com/jsonrainbow/json-schema/issues?q=label%3Abug).
+- Collect information about the bug:
+  - Stack trace (Traceback)
+  - OS, Platform and Version (Windows, Linux, macOS, x86, ARM)
+  - Version of the interpreter, compiler, SDK, runtime environment, package manager, depending on what seems relevant.
+  - Possibly your input and the output
+- Can you reliably reproduce the issue? And can you also reproduce it with older versions?
+
+### How Do I Submit a Good Bug Report?
+
+> You must never report security related issues, vulnerabilities or bugs including sensitive information to the issue tracker, or elsewhere in public. Instead, sensitive bugs must be reported at https://github.com/jsonrainbow/json-schema/security
+
+GitHub issues is used to track bugs and errors. If you run into an issue with the project:
+
+- Open an [Issue](https://github.com/jsonrainbow/json-schema/issues/new).
+- Explain the behavior you would expect and the actual behavior.
+- Please provide as much context as possible and describe the *reproduction steps* that someone else can follow to recreate the issue on their own. This usually includes your code. For good bug reports you should isolate the problem and create a reduced test case.
+- Provide the information you collected in the previous section.
+
+Once it's filed:
+
+- The project team will label the issue accordingly.
+- A team member will try to reproduce the issue with your provided steps. If there are no reproduction steps or no obvious way to reproduce the issue, the team will ask you for those steps and mark the issue as `needs-repro`. Bugs with the `needs-repro` tag will not be addressed until they are reproduced.
+- If the team is able to reproduce the issue, it will be marked `needs-fix`, as well as possibly other tags (such as `critical`), and the issue will be left to be [implemented by someone](#your-first-code-contribution).
+
+### Suggesting Enhancements
+
+This section guides you through submitting an enhancement suggestion for JSON Schema, **including completely new features and minor improvements to existing functionality**. Following these guidelines will help maintainers and the community to understand your suggestion and find related suggestions.
+
+#### Before Submitting an Enhancement
+
+- Make sure that you are using the latest version.
+- Read the [documentation](https://github.com/jsonrainbow/json-schema/wiki) carefully and find out if the functionality is already covered, maybe by an individual configuration.
+- Perform a [search](https://github.com/jsonrainbow/json-schema/issues) to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
+- Find out whether your idea fits with the scope and aims of the project. It's up to you to make a strong case to convince the project's developers of the merits of this feature. Keep in mind that we want features that will be useful to the majority of our users and not just a small subset. If you're just targeting a minority of users, consider writing an add-on/plugin library.
+
+#### How Do I Submit a Good Enhancement Suggestion?
+
+Enhancement suggestions are tracked as [GitHub issues](https://github.com/jsonrainbow/json-schema/issues).
+
+- Use a **clear and descriptive title** for the issue to identify the suggestion.
+- Provide a **step-by-step description of the suggested enhancement** in as many details as possible.
+- **Describe the current behavior** and **explain which behavior you expected to see instead** and why. At this point you can also tell which alternatives do not work for you.
+- You may want to **include screenshots or screen recordings** which help you demonstrate the steps or point out the part which the suggestion is related to. 
+- **Explain why this enhancement would be useful** to most JSON Schema users. You may also want to point out the other projects that solved it better and which could serve as inspiration.
+
+
+
+## Attribution
+This guide is based on the [contributing.md](https://contributing.md/generator)!
\ No newline at end of file
diff --git a/app/vendor/justinrainbow/json-schema/README.md b/app/vendor/justinrainbow/json-schema/README.md
index 8df14db79..95e6482a4 100644
--- a/app/vendor/justinrainbow/json-schema/README.md
+++ b/app/vendor/justinrainbow/json-schema/README.md
@@ -1,10 +1,10 @@
 # JSON Schema for PHP
 
-[![Build Status](https://travis-ci.org/justinrainbow/json-schema.svg?branch=master)](https://travis-ci.org/justinrainbow/json-schema)
-[![Latest Stable Version](https://poser.pugx.org/justinrainbow/json-schema/v/stable.png)](https://packagist.org/packages/justinrainbow/json-schema)
-[![Total Downloads](https://poser.pugx.org/justinrainbow/json-schema/downloads.png)](https://packagist.org/packages/justinrainbow/json-schema)
+[![Build Status](https://github.com/jsonrainbow/json-schema/actions/workflows/continuous-integration.yml/badge.svg)](https://github.com/jsonrainbow/json-schema/actions)
+[![Latest Stable Version](https://poser.pugx.org/justinrainbow/json-schema/v/stable)](https://packagist.org/packages/justinrainbow/json-schema)
+[![Total Downloads](https://poser.pugx.org/justinrainbow/json-schema/downloads)](https://packagist.org/packages/justinrainbow/json-schema/stats)
 
-A PHP Implementation for validating `JSON` Structures against a given `Schema`.
+A PHP Implementation for validating `JSON` Structures against a given `Schema` with support for `Schemas` of Draft-3 or Draft-4. Features of newer Drafts might not be supported. See [Table of All Versions of Everything](https://json-schema.org/specification-links.html#table-of-all-versions-of-everything) to get an overview of all existing Drafts.
 
 See [json-schema](http://json-schema.org/) for more details.
 
@@ -13,7 +13,7 @@ See [json-schema](http://json-schema.org/) for more details.
 ### Library
 
 ```bash
-git clone https://github.com/justinrainbow/json-schema.git
+git clone https://github.com/jsonrainbow/json-schema.git
 ```
 
 ### Composer
@@ -26,6 +26,12 @@ composer require justinrainbow/json-schema
 
 ## Usage
 
+For a complete reference see [Understanding JSON Schema](https://json-schema.org/understanding-json-schema/).
+
+__Note:__ features of Drafts newer than Draft-4 might not be supported!
+
+### Basic usage
+
 ```php
 isValid()) {
 } else {
     echo "JSON does not validate. Violations:\n";
     foreach ($validator->getErrors() as $error) {
-        echo sprintf("[%s] %s\n", $error['property'], $error['message']);
+        printf("[%s] %s\n", $error['property'], $error['message']);
     }
 }
 ```
@@ -65,7 +71,7 @@ $request = (object)[
 
 $validator->validate(
     $request, (object) [
-    "type"=>"object",
+        "type"=>"object",
         "properties"=>(object)[
             "processRefund"=>(object)[
                 "type"=>"boolean"
@@ -167,7 +173,7 @@ $schemaStorage = new SchemaStorage();
 $schemaStorage->addSchema('file://mySchema', $jsonSchemaObject);
 
 // Provide $schemaStorage to the Validator so that references can be resolved during validation
-$jsonValidator = new Validator( new Factory($schemaStorage));
+$jsonValidator = new Validator(new Factory($schemaStorage));
 
 // JSON must be decoded before it can be validated
 $jsonToValidateObject = json_decode('{"data":123}');
@@ -186,14 +192,19 @@ third argument to `Validator::validate()`, or can be provided as the third argum
 | `Constraint::CHECK_MODE_NORMAL` | Validate in 'normal' mode - this is the default |
 | `Constraint::CHECK_MODE_TYPE_CAST` | Enable fuzzy type checking for associative arrays and objects |
 | `Constraint::CHECK_MODE_COERCE_TYPES` | Convert data types to match the schema where possible |
+| `Constraint::CHECK_MODE_EARLY_COERCE` | Apply type coercion as soon as possible |
 | `Constraint::CHECK_MODE_APPLY_DEFAULTS` | Apply default values from the schema if not set |
 | `Constraint::CHECK_MODE_ONLY_REQUIRED_DEFAULTS` | When applying defaults, only set values that are required |
 | `Constraint::CHECK_MODE_EXCEPTIONS` | Throw an exception immediately if validation fails |
 | `Constraint::CHECK_MODE_DISABLE_FORMAT` | Do not validate "format" constraints |
 | `Constraint::CHECK_MODE_VALIDATE_SCHEMA` | Validate the schema as well as the provided document |
 
-Please note that using `Constraint::CHECK_MODE_COERCE_TYPES` or `Constraint::CHECK_MODE_APPLY_DEFAULTS`
-will modify your original data.
+Please note that using `CHECK_MODE_COERCE_TYPES` or `CHECK_MODE_APPLY_DEFAULTS` will modify your
+original data.
+
+`CHECK_MODE_EARLY_COERCE` has no effect unless used in combination with `CHECK_MODE_COERCE_TYPES`. If
+enabled, the validator will use (and coerce) the first compatible type it encounters, even if the
+schema defines another type that matches directly and does not require coercion.
 
 ## Running the tests
 
@@ -204,3 +215,10 @@ composer testOnly TestClass::testMethod  # run specific unit test method
 composer style-check                     # check code style for errors
 composer style-fix                       # automatically fix code style errors
 ```
+
+# Contributors  ✨
+Thanks go to these wonderful people, without their effort this project wasn't possible.
+
+
+  
+
\ No newline at end of file
diff --git a/app/vendor/justinrainbow/json-schema/SECURITY.md b/app/vendor/justinrainbow/json-schema/SECURITY.md
new file mode 100644
index 000000000..06f966ddd
--- /dev/null
+++ b/app/vendor/justinrainbow/json-schema/SECURITY.md
@@ -0,0 +1,13 @@
+# Security Policy
+
+## Supported Versions
+
+| Version | Supported          |
+| ------- | ------------------ |
+| 6.x.x   | :white_check_mark: |
+| 5.x.x   | :white_check_mark: |
+| < 5.0   | :x:                |
+
+## Reporting a Vulnerability
+
+JSON Schema uses the GitHub feature to safely report vulnerabilities, please report them using https://github.com/jsonrainbow/json-schema/security 
diff --git a/app/vendor/justinrainbow/json-schema/UPGRADE-6.0.md b/app/vendor/justinrainbow/json-schema/UPGRADE-6.0.md
new file mode 100644
index 000000000..f861ee179
--- /dev/null
+++ b/app/vendor/justinrainbow/json-schema/UPGRADE-6.0.md
@@ -0,0 +1,45 @@
+UPGRADE FROM 5.3 to 6.0
+=======================
+
+## Introduction
+
+We are excited to release version 6.0 of our open-source package, featuring major improvements and important updates. This release includes several breaking changes from version 5.3 aimed at enhancing performance, security, and flexibility.
+
+Please review the following breaking changes carefully and update your implementations to ensure compatibility with version 6.0. This guide provides key modifications and instructions for a smooth transition.
+
+Thank you for your support and contributions to the project.
+
+## Errors
+* `constraint` key is no longer the constraint name but contains more information in order to translate violations.
+
+    *Before*
+    ```php
+    foreach ($validator->getErrors() as $error) {
+        echo $error['constraint']; // required
+    }
+    ```
+
+    *After*
+    ```php
+    foreach ($validator->getErrors() as $error) {
+        echo $error['constraint']['name']; // required
+    }
+    ```
+
+## BaseConstraint::addError signature changed
+
+* The signature for the `BaseConstraint::AddError` method has changed.
+
+  The `$message` parameter has been removed and replaced by the `ConstraintError` parameter. 
+  The `ConstraintError` object encapsulates the error message along with additional information about the constraint violation.
+
+    *Before*
+    ```php
+    public function addError(?JsonPointer $path, $message, $constraint = '', ?array $more = null)
+    ```
+
+    *After*
+    ```php
+    public function addError(ConstraintError $constraint, ?JsonPointer $path = null, array $more = []): void
+    ```
+
diff --git a/app/vendor/justinrainbow/json-schema/bin/validate-json b/app/vendor/justinrainbow/json-schema/bin/validate-json
index d2102fe94..83f0e2a86 100755
--- a/app/vendor/justinrainbow/json-schema/bin/validate-json
+++ b/app/vendor/justinrainbow/json-schema/bin/validate-json
@@ -6,35 +6,22 @@
  * @author Christian Weiske 
  */
 
-/**
- * Dead simple autoloader
- *
- * @param string $className Name of class to load
- *
- * @return void
- */
-spl_autoload_register(function ($className)
-{
-    $className = ltrim($className, '\\');
-    $fileName  = '';
-    if ($lastNsPos = strrpos($className, '\\')) {
-        $namespace = substr($className, 0, $lastNsPos);
-        $className = substr($className, $lastNsPos + 1);
-        $fileName  = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
-    }
-    $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
-    if (stream_resolve_include_path($fileName)) {
-        require_once $fileName;
-    }
-});
-
 // support running this tool from git checkout
-if (is_dir(__DIR__ . '/../src/JsonSchema')) {
-    set_include_path(__DIR__ . '/../src' . PATH_SEPARATOR . get_include_path());
+$projectDirectory = dirname(__DIR__);
+if (is_dir($projectDirectory . DIRECTORY_SEPARATOR . 'vendor')) {
+    set_include_path($projectDirectory . PATH_SEPARATOR . get_include_path());
+}
+
+// autoload composer classes
+$composerAutoload = stream_resolve_include_path('vendor/autoload.php');
+if (!$composerAutoload) {
+    echo("Cannot load json-schema library\n");
+    exit(1);
 }
+require($composerAutoload);
 
-$arOptions = array();
-$arArgs = array();
+$arOptions = [];
+$arArgs = [];
 array_shift($argv);//script itself
 foreach ($argv as $arg) {
     if ($arg[0] == '-') {
@@ -73,13 +60,11 @@ if (count($arArgs) == 1) {
 
 /**
  * Show the json parse error that happened last
- *
- * @return void
  */
-function showJsonError()
+function showJsonError(): void
 {
     $constants = get_defined_constants(true);
-    $json_errors = array();
+    $json_errors = [];
     foreach ($constants['json'] as $name => $value) {
         if (!strncmp($name, 'JSON_ERROR_', 11)) {
             $json_errors[$value] = $name;
@@ -114,11 +99,11 @@ function getUrlFromPath($path)
 function parseHeaderValue($headerValue)
 {
     if (strpos($headerValue, ';') === false) {
-        return array('_value' => $headerValue);
+        return ['_value' => $headerValue];
     }
 
     $parts = explode(';', $headerValue);
-    $arData = array('_value' => array_shift($parts));
+    $arData = ['_value' => array_shift($parts)];
     foreach ($parts as $part) {
         list($name, $value) = explode('=', $part);
         $arData[$name] = trim($value, ' "\'');
@@ -141,15 +126,15 @@ function output($str) {
 $urlData = getUrlFromPath($pathData);
 
 $context = stream_context_create(
-    array(
-        'http' => array(
-            'header'        => array(
+    [
+        'http' => [
+            'header'        => [
                 'Accept: */*',
                 'Connection: Close'
-            ),
+            ],
             'max_redirects' => 5
-        )
-    )
+        ]
+    ]
 );
 $dataString = file_get_contents($pathData, false, $context);
 if ($dataString == '') {
@@ -230,7 +215,7 @@ if (isset($arOptions['--dump-schema'])) {
 
 try {
     $validator = new JsonSchema\Validator();
-    $validator->check($data, $schema);
+    $validator->validate($data, $schema);
 
     if ($validator->isValid()) {
         if(isset($arOptions['--verbose'])) {
diff --git a/app/vendor/justinrainbow/json-schema/composer.json b/app/vendor/justinrainbow/json-schema/composer.json
index fcacd40c3..8229d6356 100644
--- a/app/vendor/justinrainbow/json-schema/composer.json
+++ b/app/vendor/justinrainbow/json-schema/composer.json
@@ -6,7 +6,7 @@
         "json",
         "schema"
     ],
-    "homepage": "https://github.com/justinrainbow/json-schema",
+    "homepage": "https://github.com/jsonrainbow/json-schema",
     "license": "MIT",
     "authors": [
         {
@@ -27,16 +27,21 @@
         }
     ],
     "require": {
-        "php": ">=5.3.3"
+        "php": "^7.2 || ^8.0",
+        "ext-json": "*",
+        "marc-mabe/php-enum":"^4.0"
     },
     "require-dev": {
-        "friendsofphp/php-cs-fixer": "~2.2.20||~2.15.1",
+        "friendsofphp/php-cs-fixer": "3.3.0",
         "json-schema/json-schema-test-suite": "1.2.0",
-        "phpunit/phpunit": "^4.8.35"
+        "phpunit/phpunit": "^8.5",
+        "phpspec/prophecy": "^1.19",
+        "phpstan/phpstan": "^1.12",
+        "marc-mabe/php-enum-phpstan": "^2.0"
     },
     "extra": {
         "branch-alias": {
-            "dev-master": "5.0.x-dev"
+            "dev-master": "6.x-dev"
         }
     },
     "autoload": {
@@ -71,6 +76,8 @@
         "style-check": "php-cs-fixer fix --dry-run --verbose --diff",
         "style-fix": "php-cs-fixer fix --verbose",
         "test": "phpunit",
-        "testOnly": "phpunit --colors --filter"
+        "testOnly": "phpunit --colors --filter",
+        "phpstan": "@php phpstan",
+        "phpstan-generate-baseline": "@php phpstan --generate-baseline"
     }
 }
diff --git a/app/vendor/justinrainbow/json-schema/src/JsonSchema/ConstraintError.php b/app/vendor/justinrainbow/json-schema/src/JsonSchema/ConstraintError.php
new file mode 100644
index 000000000..c17cfeff1
--- /dev/null
+++ b/app/vendor/justinrainbow/json-schema/src/JsonSchema/ConstraintError.php
@@ -0,0 +1,117 @@
+getValue();
+        static $messages = [
+            self::ADDITIONAL_ITEMS => 'The item %s[%s] is not defined and the definition does not allow additional items',
+            self::ADDITIONAL_PROPERTIES => 'The property %s is not defined and the definition does not allow additional properties',
+            self::ALL_OF => 'Failed to match all schemas',
+            self::ANY_OF => 'Failed to match at least one schema',
+            self::DEPENDENCIES => '%s depends on %s, which is missing',
+            self::DISALLOW => 'Disallowed value was matched',
+            self::DIVISIBLE_BY => 'Is not divisible by %d',
+            self::ENUM => 'Does not have a value in the enumeration %s',
+            self::CONSTANT => 'Does not have a value equal to %s',
+            self::EXCLUSIVE_MINIMUM => 'Must have a minimum value greater than %d',
+            self::EXCLUSIVE_MAXIMUM => 'Must have a maximum value less than %d',
+            self::FORMAT_COLOR => 'Invalid color',
+            self::FORMAT_DATE => 'Invalid date %s, expected format YYYY-MM-DD',
+            self::FORMAT_DATE_TIME => 'Invalid date-time %s, expected format YYYY-MM-DDThh:mm:ssZ or YYYY-MM-DDThh:mm:ss+hh:mm',
+            self::FORMAT_DATE_UTC => 'Invalid time %s, expected integer of milliseconds since Epoch',
+            self::FORMAT_EMAIL => 'Invalid email',
+            self::FORMAT_HOSTNAME => 'Invalid hostname',
+            self::FORMAT_IP => 'Invalid IP address',
+            self::FORMAT_PHONE => 'Invalid phone number',
+            self::FORMAT_REGEX=> 'Invalid regex format %s',
+            self::FORMAT_STYLE => 'Invalid style',
+            self::FORMAT_TIME => 'Invalid time %s, expected format hh:mm:ss',
+            self::FORMAT_URL => 'Invalid URL format',
+            self::FORMAT_URL_REF => 'Invalid URL reference format',
+            self::LENGTH_MAX => 'Must be at most %d characters long',
+            self::INVALID_SCHEMA => 'Schema is not valid',
+            self::LENGTH_MIN => 'Must be at least %d characters long',
+            self::MAX_ITEMS => 'There must be a maximum of %d items in the array, %d found',
+            self::MAXIMUM => 'Must have a maximum value less than or equal to %d',
+            self::MIN_ITEMS => 'There must be a minimum of %d items in the array, %d found',
+            self::MINIMUM => 'Must have a minimum value greater than or equal to %d',
+            self::MISSING_MAXIMUM => 'Use of exclusiveMaximum requires presence of maximum',
+            self::MISSING_MINIMUM => 'Use of exclusiveMinimum requires presence of minimum',
+            /*self::MISSING_ERROR => 'Used for tests; this error is deliberately commented out',*/
+            self::MULTIPLE_OF => 'Must be a multiple of %s',
+            self::NOT => 'Matched a schema which it should not',
+            self::ONE_OF => 'Failed to match exactly one schema',
+            self::REQUIRED => 'The property %s is required',
+            self::REQUIRES => 'The presence of the property %s requires that %s also be present',
+            self::PATTERN => 'Does not match the regex pattern %s',
+            self::PREGEX_INVALID => 'The pattern %s is invalid',
+            self::PROPERTIES_MIN => 'Must contain a minimum of %d properties',
+            self::PROPERTIES_MAX => 'Must contain no more than %d properties',
+            self::TYPE => '%s value found, but %s is required',
+            self::UNIQUE_ITEMS => 'There are no duplicates allowed in the array'
+        ];
+
+        if (!isset($messages[$name])) {
+            throw new InvalidArgumentException('Missing error message for ' . $name);
+        }
+
+        return $messages[$name];
+    }
+}
diff --git a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/BaseConstraint.php b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/BaseConstraint.php
index 63968213e..b1b34c32d 100644
--- a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/BaseConstraint.php
+++ b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/BaseConstraint.php
@@ -1,14 +1,11 @@
 
      */
     protected $errorMask = Validator::ERROR_NONE;
 
@@ -35,42 +33,46 @@ class BaseConstraint
      */
     protected $factory;
 
-    /**
-     * @param Factory $factory
-     */
-    public function __construct(Factory $factory = null)
+    public function __construct(?Factory $factory = null)
     {
         $this->factory = $factory ?: new Factory();
     }
 
-    public function addError(JsonPointer $path = null, $message, $constraint = '', array $more = null)
+    public function addError(ConstraintError $constraint, ?JsonPointer $path = null, array $more = []): void
     {
-        $error = array(
+        $message = $constraint->getMessage();
+        $name = $constraint->getValue();
+        $error = [
             'property' => $this->convertJsonPointerIntoPropertyPath($path ?: new JsonPointer('')),
-            'pointer' => ltrim(strval($path ?: new JsonPointer('')), '#'),
-            'message' => $message,
-            'constraint' => $constraint,
+            'pointer' => ltrim((string) ($path ?: new JsonPointer('')), '#'),
+            'message' => ucfirst(vsprintf($message, array_map(static function ($val) {
+                if (is_scalar($val)) {
+                    return is_bool($val) ? var_export($val, true) : $val;
+                }
+
+                return json_encode($val);
+            }, array_values($more)))),
+            'constraint' => [
+                'name' => $name,
+                'params' => $more
+            ],
             'context' => $this->factory->getErrorContext(),
-        );
+        ];
 
         if ($this->factory->getConfig(Constraint::CHECK_MODE_EXCEPTIONS)) {
             throw new ValidationException(sprintf('Error validating %s: %s', $error['pointer'], $error['message']));
         }
 
-        if (is_array($more) && count($more) > 0) {
-            $error += $more;
-        }
-
         $this->errors[] = $error;
         $this->errorMask |= $error['context'];
     }
 
-    public function addErrors(array $errors)
+    public function addErrors(array $errors): void
     {
         if ($errors) {
             $this->errors = array_merge($this->errors, $errors);
             $errorMask = &$this->errorMask;
-            array_walk($errors, function ($error) use (&$errorMask) {
+            array_walk($errors, static function ($error) use (&$errorMask) {
                 if (isset($error['context'])) {
                     $errorMask |= $error['context'];
                 }
@@ -78,20 +80,24 @@ public function addErrors(array $errors)
         }
     }
 
-    public function getErrors($errorContext = Validator::ERROR_ALL)
+    /**
+     * @phpstan-param int-mask-of $errorContext
+     */
+    public function getErrors(int $errorContext = Validator::ERROR_ALL): array
     {
         if ($errorContext === Validator::ERROR_ALL) {
             return $this->errors;
         }
 
-        return array_filter($this->errors, function ($error) use ($errorContext) {
-            if ($errorContext & $error['context']) {
-                return true;
-            }
+        return array_filter($this->errors, static function ($error) use ($errorContext) {
+            return (bool) ($errorContext & $error['context']);
         });
     }
 
-    public function numErrors($errorContext = Validator::ERROR_ALL)
+    /**
+     * @phpstan-param int-mask-of $errorContext
+     */
+    public function numErrors(int $errorContext = Validator::ERROR_ALL): int
     {
         if ($errorContext === Validator::ERROR_ALL) {
             return count($this->errors);
@@ -100,42 +106,38 @@ public function numErrors($errorContext = Validator::ERROR_ALL)
         return count($this->getErrors($errorContext));
     }
 
-    public function isValid()
+    public function isValid(): bool
     {
         return !$this->getErrors();
     }
 
     /**
-     * Clears any reported errors.  Should be used between
+     * Clears any reported errors. Should be used between
      * multiple validation checks.
      */
-    public function reset()
+    public function reset(): void
     {
-        $this->errors = array();
+        $this->errors = [];
         $this->errorMask = Validator::ERROR_NONE;
     }
 
     /**
      * Get the error mask
      *
-     * @return int
+     * @phpstan-return int-mask-of
      */
-    public function getErrorMask()
+    public function getErrorMask(): int
     {
         return $this->errorMask;
     }
 
     /**
      * Recursively cast an associative array to an object
-     *
-     * @param array $array
-     *
-     * @return object
      */
-    public static function arrayToObjectRecursive($array)
+    public static function arrayToObjectRecursive(array $array): object
     {
         $json = json_encode($array);
-        if (json_last_error() !== \JSON_ERROR_NONE) {
+        if (json_last_error() !== JSON_ERROR_NONE) {
             $message = 'Unable to encode schema array as JSON';
             if (function_exists('json_last_error_msg')) {
                 $message .= ': ' . json_last_error_msg();
@@ -143,6 +145,26 @@ public static function arrayToObjectRecursive($array)
             throw new InvalidArgumentException($message);
         }
 
-        return (object) json_decode($json);
+        return (object) json_decode($json, false);
+    }
+
+    /**
+     * Transform a JSON pattern into a PCRE regex
+     */
+    public static function jsonPatternToPhpRegex(string $pattern): string
+    {
+        return '~' . str_replace('~', '\\~', $pattern) . '~u';
+    }
+
+    protected function convertJsonPointerIntoPropertyPath(JsonPointer $pointer): string
+    {
+        $result = array_map(
+            static function ($path) {
+                return sprintf(is_numeric($path) ? '[%d]' : '.%s', $path);
+            },
+            $pointer->getPropertyPaths()
+        );
+
+        return trim(implode('', $result), '.');
     }
 }
diff --git a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/CollectionConstraint.php b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/CollectionConstraint.php
index d1384b884..e42a6fb8d 100644
--- a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/CollectionConstraint.php
+++ b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/CollectionConstraint.php
@@ -1,5 +1,7 @@
 minItems) && count($value) < $schema->minItems) {
-            $this->addError($path, 'There must be a minimum of ' . $schema->minItems . ' items in the array', 'minItems', array('minItems' => $schema->minItems));
+            $this->addError(ConstraintError::MIN_ITEMS(), $path, ['minItems' => $schema->minItems, 'found' => count($value)]);
         }
 
         // Verify maxItems
         if (isset($schema->maxItems) && count($value) > $schema->maxItems) {
-            $this->addError($path, 'There must be a maximum of ' . $schema->maxItems . ' items in the array', 'maxItems', array('maxItems' => $schema->maxItems));
+            $this->addError(ConstraintError::MAX_ITEMS(), $path, ['maxItems' => $schema->maxItems, 'found' => count($value)]);
         }
 
         // Verify uniqueItems
         if (isset($schema->uniqueItems) && $schema->uniqueItems) {
-            $unique = $value;
-            if (is_array($value) && count($value)) {
-                $unique = array_map(function ($e) {
-                    return var_export($e, true);
-                }, $value);
-            }
-            if (count(array_unique($unique)) != count($value)) {
-                $this->addError($path, 'There are no duplicates allowed in the array', 'uniqueItems');
+            $count = count($value);
+            for ($x = 0; $x < $count - 1; $x++) {
+                for ($y = $x + 1; $y < $count; $y++) {
+                    if (DeepComparer::isEqual($value[$x], $value[$y])) {
+                        $this->addError(ConstraintError::UNIQUE_ITEMS(), $path);
+                        break 2;
+                    }
+                }
             }
         }
 
-        // Verify items
-        if (isset($schema->items)) {
-            $this->validateItems($value, $schema, $path, $i);
-        }
+        $this->validateItems($value, $schema, $path, $i);
     }
 
     /**
      * Validates the items
      *
-     * @param array            $value
-     * @param \stdClass        $schema
-     * @param JsonPointer|null $path
-     * @param string           $i
+     * @param array     $value
+     * @param \stdClass $schema
+     * @param string    $i
      */
-    protected function validateItems(&$value, $schema = null, JsonPointer $path = null, $i = null)
+    protected function validateItems(&$value, $schema = null, ?JsonPointer $path = null, $i = null): void
     {
+        if (\is_null($schema) || !isset($schema->items)) {
+            return;
+        }
+
+        if ($schema->items === true) {
+            return;
+        }
+
         if (is_object($schema->items)) {
             // just one type definition for the whole array
             foreach ($value as $k => &$v) {
@@ -98,7 +106,14 @@ protected function validateItems(&$value, $schema = null, JsonPointer $path = nu
                             $this->checkUndefined($v, $schema->additionalItems, $path, $k);
                         } else {
                             $this->addError(
-                                $path, 'The item ' . $i . '[' . $k . '] is not defined and the definition does not allow additional items', 'additionalItems', array('additionalItems' => $schema->additionalItems));
+                                ConstraintError::ADDITIONAL_ITEMS(),
+                                $path,
+                                [
+                                    'item' => $i,
+                                    'property' => $k,
+                                    'additionalItems' => $schema->additionalItems
+                                ]
+                            );
                         }
                     } else {
                         // Should be valid against an empty schema
diff --git a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/ConstConstraint.php b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/ConstConstraint.php
new file mode 100644
index 000000000..b9bb1f48d
--- /dev/null
+++ b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/ConstConstraint.php
@@ -0,0 +1,51 @@
+
+ */
+class ConstConstraint extends Constraint
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function check(&$element, $schema = null, ?JsonPointer $path = null, $i = null): void
+    {
+        // Only validate const if the attribute exists
+        if ($element instanceof UndefinedConstraint && (!isset($schema->required) || !$schema->required)) {
+            return;
+        }
+        $const = $schema->const;
+
+        $type = gettype($element);
+        $constType = gettype($const);
+
+        if ($this->factory->getConfig(self::CHECK_MODE_TYPE_CAST) && $type === 'array' && $constType === 'object') {
+            if (DeepComparer::isEqual((object) $element, $const)) {
+                return;
+            }
+        }
+
+        if (DeepComparer::isEqual($element, $const)) {
+            return;
+        }
+
+        $this->addError(ConstraintError::CONSTANT(), $path, ['const' => $schema->const]);
+    }
+}
diff --git a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/Constraint.php b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/Constraint.php
index c61b89ad2..8e818f0aa 100644
--- a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/Constraint.php
+++ b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/Constraint.php
@@ -1,71 +1,57 @@
 
- * @author Bruno Prieto Reis 
- */
 abstract class Constraint extends BaseConstraint implements ConstraintInterface
 {
+    /** @var string */
     protected $inlineSchemaProperty = '$schema';
 
-    const CHECK_MODE_NONE =             0x00000000;
-    const CHECK_MODE_NORMAL =           0x00000001;
-    const CHECK_MODE_TYPE_CAST =        0x00000002;
-    const CHECK_MODE_COERCE_TYPES =     0x00000004;
-    const CHECK_MODE_APPLY_DEFAULTS =   0x00000008;
-    const CHECK_MODE_EXCEPTIONS =       0x00000010;
-    const CHECK_MODE_DISABLE_FORMAT =   0x00000020;
-    const CHECK_MODE_ONLY_REQUIRED_DEFAULTS   = 0x00000080;
-    const CHECK_MODE_VALIDATE_SCHEMA =  0x00000100;
+    public const CHECK_MODE_NONE =             0x00000000;
+    public const CHECK_MODE_NORMAL =           0x00000001;
+    public const CHECK_MODE_TYPE_CAST =        0x00000002;
+    public const CHECK_MODE_COERCE_TYPES =     0x00000004;
+    public const CHECK_MODE_APPLY_DEFAULTS =   0x00000008;
+    public const CHECK_MODE_EXCEPTIONS =       0x00000010;
+    public const CHECK_MODE_DISABLE_FORMAT =   0x00000020;
+    public const CHECK_MODE_EARLY_COERCE =     0x00000040;
+    public const CHECK_MODE_ONLY_REQUIRED_DEFAULTS   = 0x00000080;
+    public const CHECK_MODE_VALIDATE_SCHEMA =  0x00000100;
 
     /**
      * Bubble down the path
      *
      * @param JsonPointer|null $path Current path
      * @param mixed            $i    What to append to the path
-     *
-     * @return JsonPointer;
      */
-    protected function incrementPath(JsonPointer $path = null, $i)
+    protected function incrementPath(?JsonPointer $path, $i): JsonPointer
     {
-        $path = $path ?: new JsonPointer('');
+        $path = $path ?? new JsonPointer('');
 
         if ($i === null || $i === '') {
             return $path;
         }
 
-        $path = $path->withPropertyPaths(
+        return $path->withPropertyPaths(
             array_merge(
                 $path->getPropertyPaths(),
-                array($i)
+                [$i]
             )
         );
-
-        return $path;
     }
 
     /**
      * Validates an array
      *
-     * @param mixed            $value
-     * @param mixed            $schema
-     * @param JsonPointer|null $path
-     * @param mixed            $i
+     * @param mixed $value
+     * @param mixed $schema
+     * @param mixed $i
      */
-    protected function checkArray(&$value, $schema = null, JsonPointer $path = null, $i = null)
+    protected function checkArray(&$value, $schema = null, ?JsonPointer $path = null, $i = null): void
     {
         $validator = $this->factory->createInstanceFor('collection');
         $validator->check($value, $schema, $path, $i);
@@ -76,16 +62,23 @@ protected function checkArray(&$value, $schema = null, JsonPointer $path = null,
     /**
      * Validates an object
      *
-     * @param mixed            $value
-     * @param mixed            $schema
-     * @param JsonPointer|null $path
-     * @param mixed            $properties
-     * @param mixed            $additionalProperties
-     * @param mixed            $patternProperties
+     * @param mixed         $value
+     * @param mixed         $schema
+     * @param mixed         $properties
+     * @param mixed         $additionalProperties
+     * @param mixed         $patternProperties
+     * @param array $appliedDefaults
      */
-    protected function checkObject(&$value, $schema = null, JsonPointer $path = null, $properties = null,
-        $additionalProperties = null, $patternProperties = null, $appliedDefaults = array())
-    {
+    protected function checkObject(
+        &$value,
+        $schema = null,
+        ?JsonPointer $path = null,
+        $properties = null,
+        $additionalProperties = null,
+        $patternProperties = null,
+        array $appliedDefaults = []
+    ): void {
+        /** @var ObjectConstraint $validator */
         $validator = $this->factory->createInstanceFor('object');
         $validator->check($value, $schema, $path, $properties, $additionalProperties, $patternProperties, $appliedDefaults);
 
@@ -93,14 +86,13 @@ protected function checkObject(&$value, $schema = null, JsonPointer $path = null
     }
 
     /**
-     * Validates the type of a property
+     * Validates the type of the value
      *
-     * @param mixed            $value
-     * @param mixed            $schema
-     * @param JsonPointer|null $path
-     * @param mixed            $i
+     * @param mixed $value
+     * @param mixed $schema
+     * @param mixed $i
      */
-    protected function checkType(&$value, $schema = null, JsonPointer $path = null, $i = null)
+    protected function checkType(&$value, $schema = null, ?JsonPointer $path = null, $i = null): void
     {
         $validator = $this->factory->createInstanceFor('type');
         $validator->check($value, $schema, $path, $i);
@@ -111,13 +103,13 @@ protected function checkType(&$value, $schema = null, JsonPointer $path = null,
     /**
      * Checks a undefined element
      *
-     * @param mixed            $value
-     * @param mixed            $schema
-     * @param JsonPointer|null $path
-     * @param mixed            $i
+     * @param mixed $value
+     * @param mixed $schema
+     * @param mixed $i
      */
-    protected function checkUndefined(&$value, $schema = null, JsonPointer $path = null, $i = null, $fromDefault = false)
+    protected function checkUndefined(&$value, $schema = null, ?JsonPointer $path = null, $i = null, bool $fromDefault = false): void
     {
+        /** @var UndefinedConstraint $validator */
         $validator = $this->factory->createInstanceFor('undefined');
 
         $validator->check($value, $this->factory->getSchemaStorage()->resolveRefSchema($schema), $path, $i, $fromDefault);
@@ -128,12 +120,11 @@ protected function checkUndefined(&$value, $schema = null, JsonPointer $path = n
     /**
      * Checks a string element
      *
-     * @param mixed            $value
-     * @param mixed            $schema
-     * @param JsonPointer|null $path
-     * @param mixed            $i
+     * @param mixed $value
+     * @param mixed $schema
+     * @param mixed $i
      */
-    protected function checkString($value, $schema = null, JsonPointer $path = null, $i = null)
+    protected function checkString($value, $schema = null, ?JsonPointer $path = null, $i = null): void
     {
         $validator = $this->factory->createInstanceFor('string');
         $validator->check($value, $schema, $path, $i);
@@ -144,12 +135,11 @@ protected function checkString($value, $schema = null, JsonPointer $path = null,
     /**
      * Checks a number element
      *
-     * @param mixed       $value
-     * @param mixed       $schema
-     * @param JsonPointer $path
-     * @param mixed       $i
+     * @param mixed $value
+     * @param mixed $schema
+     * @param mixed $i
      */
-    protected function checkNumber($value, $schema = null, JsonPointer $path = null, $i = null)
+    protected function checkNumber($value, $schema = null, ?JsonPointer $path = null, $i = null): void
     {
         $validator = $this->factory->createInstanceFor('number');
         $validator->check($value, $schema, $path, $i);
@@ -160,12 +150,11 @@ protected function checkNumber($value, $schema = null, JsonPointer $path = null,
     /**
      * Checks a enum element
      *
-     * @param mixed            $value
-     * @param mixed            $schema
-     * @param JsonPointer|null $path
-     * @param mixed            $i
+     * @param mixed $value
+     * @param mixed $schema
+     * @param mixed $i
      */
-    protected function checkEnum($value, $schema = null, JsonPointer $path = null, $i = null)
+    protected function checkEnum($value, $schema = null, ?JsonPointer $path = null, $i = null): void
     {
         $validator = $this->factory->createInstanceFor('enum');
         $validator->check($value, $schema, $path, $i);
@@ -174,45 +163,40 @@ protected function checkEnum($value, $schema = null, JsonPointer $path = null, $
     }
 
     /**
-     * Checks format of an element
+     * Checks a const element
      *
-     * @param mixed            $value
-     * @param mixed            $schema
-     * @param JsonPointer|null $path
-     * @param mixed            $i
+     * @param mixed $value
+     * @param mixed $schema
+     * @param mixed $i
      */
-    protected function checkFormat($value, $schema = null, JsonPointer $path = null, $i = null)
+    protected function checkConst($value, $schema = null, ?JsonPointer $path = null, $i = null): void
     {
-        $validator = $this->factory->createInstanceFor('format');
+        $validator = $this->factory->createInstanceFor('const');
         $validator->check($value, $schema, $path, $i);
 
         $this->addErrors($validator->getErrors());
     }
 
     /**
-     * Get the type check based on the set check mode.
+     * Checks format of an element
      *
-     * @return TypeCheck\TypeCheckInterface
+     * @param mixed $value
+     * @param mixed $schema
+     * @param mixed $i
      */
-    protected function getTypeCheck()
+    protected function checkFormat($value, $schema = null, ?JsonPointer $path = null, $i = null): void
     {
-        return $this->factory->getTypeCheck();
+        $validator = $this->factory->createInstanceFor('format');
+        $validator->check($value, $schema, $path, $i);
+
+        $this->addErrors($validator->getErrors());
     }
 
     /**
-     * @param JsonPointer $pointer
-     *
-     * @return string property path
+     * Get the type check based on the set check mode.
      */
-    protected function convertJsonPointerIntoPropertyPath(JsonPointer $pointer)
+    protected function getTypeCheck(): TypeCheck\TypeCheckInterface
     {
-        $result = array_map(
-            function ($path) {
-                return sprintf(is_numeric($path) ? '[%d]' : '.%s', $path);
-            },
-            $pointer->getPropertyPaths()
-        );
-
-        return trim(implode('', $result), '.');
+        return $this->factory->getTypeCheck();
     }
 }
diff --git a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/ConstraintInterface.php b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/ConstraintInterface.php
index 442268e68..9e43ecb56 100644
--- a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/ConstraintInterface.php
+++ b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/ConstraintInterface.php
@@ -1,5 +1,7 @@
 required) || !$schema->required)) {
@@ -32,23 +36,24 @@ public function check(&$element, $schema = null, JsonPointer $path = null, $i =
 
         foreach ($schema->enum as $enum) {
             $enumType = gettype($enum);
-            if ($this->factory->getConfig(self::CHECK_MODE_TYPE_CAST) && $type == 'array' && $enumType == 'object') {
-                if ((object) $element == $enum) {
-                    return;
-                }
+
+            if ($enumType === 'object'
+                && $type === 'array'
+                && $this->factory->getConfig(self::CHECK_MODE_TYPE_CAST)
+                && DeepComparer::isEqual((object) $element, $enum)
+            ) {
+                return;
+            }
+
+            if (($type === $enumType) && DeepComparer::isEqual($element, $enum)) {
+                return;
             }
 
-            if ($type === gettype($enum)) {
-                if ($type == 'object') {
-                    if ($element == $enum) {
-                        return;
-                    }
-                } elseif ($element === $enum) {
-                    return;
-                }
+            if (is_numeric($element) && is_numeric($enum) && DeepComparer::isEqual((float) $element, (float) $enum)) {
+                return;
             }
         }
 
-        $this->addError($path, 'Does not have a value in the enumeration ' . json_encode($schema->enum), 'enum', array('enum' => $schema->enum));
+        $this->addError(ConstraintError::ENUM(), $path, ['enum' => $schema->enum]);
     }
 }
diff --git a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/Factory.php b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/Factory.php
index 4e771c19c..b9220b9d8 100644
--- a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/Factory.php
+++ b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/Factory.php
@@ -1,5 +1,7 @@
 
      */
     private $checkMode = Constraint::CHECK_MODE_NORMAL;
 
     /**
-     * @var TypeCheck\TypeCheckInterface[]
+     * @var array
+     * @phpstan-var array, TypeCheck\TypeCheckInterface>
      */
-    private $typeCheck = array();
+    private $typeCheck = [];
 
     /**
      * @var int Validation context
@@ -49,7 +53,7 @@ class Factory
     /**
      * @var array
      */
-    protected $constraintMap = array(
+    protected $constraintMap = [
         'array' => 'JsonSchema\Constraints\CollectionConstraint',
         'collection' => 'JsonSchema\Constraints\CollectionConstraint',
         'object' => 'JsonSchema\Constraints\ObjectConstraint',
@@ -58,25 +62,24 @@ class Factory
         'string' => 'JsonSchema\Constraints\StringConstraint',
         'number' => 'JsonSchema\Constraints\NumberConstraint',
         'enum' => 'JsonSchema\Constraints\EnumConstraint',
+        'const' => 'JsonSchema\Constraints\ConstConstraint',
         'format' => 'JsonSchema\Constraints\FormatConstraint',
         'schema' => 'JsonSchema\Constraints\SchemaConstraint',
         'validator' => 'JsonSchema\Validator'
-    );
+    ];
 
     /**
      * @var array
      */
-    private $instanceCache = array();
+    private $instanceCache = [];
 
     /**
-     * @param SchemaStorage         $schemaStorage
-     * @param UriRetrieverInterface $uriRetriever
-     * @param int                   $checkMode
+     * @phpstan-param int-mask-of $checkMode
      */
     public function __construct(
-        SchemaStorageInterface $schemaStorage = null,
-        UriRetrieverInterface $uriRetriever = null,
-        $checkMode = Constraint::CHECK_MODE_NORMAL
+        ?SchemaStorageInterface $schemaStorage = null,
+        ?UriRetrieverInterface $uriRetriever = null,
+        int $checkMode = Constraint::CHECK_MODE_NORMAL
     ) {
         // set provided config options
         $this->setConfig($checkMode);
@@ -89,8 +92,9 @@ public function __construct(
      * Set config values
      *
      * @param int $checkMode Set checkMode options - does not preserve existing flags
+     * @phpstan-param int-mask-of $checkMode
      */
-    public function setConfig($checkMode = Constraint::CHECK_MODE_NORMAL)
+    public function setConfig(int $checkMode = Constraint::CHECK_MODE_NORMAL): void
     {
         $this->checkMode = $checkMode;
     }
@@ -98,9 +102,9 @@ public function setConfig($checkMode = Constraint::CHECK_MODE_NORMAL)
     /**
      * Enable checkMode flags
      *
-     * @param int $options
+     * @phpstan-param int-mask-of $options
      */
-    public function addConfig($options)
+    public function addConfig(int $options): void
     {
         $this->checkMode |= $options;
     }
@@ -108,9 +112,9 @@ public function addConfig($options)
     /**
      * Disable checkMode flags
      *
-     * @param int $options
+     * @phpstan-param int-mask-of $options
      */
-    public function removeConfig($options)
+    public function removeConfig(int $options): void
     {
         $this->checkMode &= ~$options;
     }
@@ -118,11 +122,12 @@ public function removeConfig($options)
     /**
      * Get checkMode option
      *
-     * @param int $options Options to get, if null then return entire bitmask
+     * @param int|null $options Options to get, if null then return entire bitmask
+     * @phpstan-param int-mask-of|null $options Options to get, if null then return entire bitmask
      *
-     * @return int
+     * @phpstan-return int-mask-of
      */
-    public function getConfig($options = null)
+    public function getConfig(?int $options = null): int
     {
         if ($options === null) {
             return $this->checkMode;
@@ -131,20 +136,17 @@ public function getConfig($options = null)
         return $this->checkMode & $options;
     }
 
-    /**
-     * @return UriRetrieverInterface
-     */
-    public function getUriRetriever()
+    public function getUriRetriever(): UriRetrieverInterface
     {
         return $this->uriRetriever;
     }
 
-    public function getSchemaStorage()
+    public function getSchemaStorage(): SchemaStorageInterface
     {
         return $this->schemaStorage;
     }
 
-    public function getTypeCheck()
+    public function getTypeCheck(): TypeCheck\TypeCheckInterface
     {
         if (!isset($this->typeCheck[$this->checkMode])) {
             $this->typeCheck[$this->checkMode] = ($this->checkMode & Constraint::CHECK_MODE_TYPE_CAST)
@@ -155,13 +157,7 @@ public function getTypeCheck()
         return $this->typeCheck[$this->checkMode];
     }
 
-    /**
-     * @param string $name
-     * @param string $class
-     *
-     * @return Factory
-     */
-    public function setConstraintClass($name, $class)
+    public function setConstraintClass(string $name, string $class): Factory
     {
         // Ensure class exists
         if (!class_exists($class)) {
@@ -183,7 +179,8 @@ public function setConstraintClass($name, $class)
      *
      * @throws InvalidArgumentException if is not possible create the constraint instance
      *
-     * @return ConstraintInterface|ObjectConstraint
+     * @return ConstraintInterface&BaseConstraint
+     * @phpstan-return ConstraintInterface&BaseConstraint
      */
     public function createInstanceFor($constraintName)
     {
@@ -201,9 +198,9 @@ public function createInstanceFor($constraintName)
     /**
      * Get the error context
      *
-     * @return string
+     * @phpstan-return Validator::ERROR_DOCUMENT_VALIDATION|Validator::ERROR_SCHEMA_VALIDATION
      */
-    public function getErrorContext()
+    public function getErrorContext(): int
     {
         return $this->errorContext;
     }
@@ -211,9 +208,9 @@ public function getErrorContext()
     /**
      * Set the error context
      *
-     * @param string $validationContext
+     * @phpstan-param Validator::ERROR_DOCUMENT_VALIDATION|Validator::ERROR_SCHEMA_VALIDATION $errorContext
      */
-    public function setErrorContext($errorContext)
+    public function setErrorContext(int $errorContext): void
     {
         $this->errorContext = $errorContext;
     }
diff --git a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/FormatConstraint.php b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/FormatConstraint.php
index 578cdb14d..9ed4df9dc 100644
--- a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/FormatConstraint.php
+++ b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/FormatConstraint.php
@@ -1,5 +1,7 @@
 format) || $this->factory->getConfig(self::CHECK_MODE_DISABLE_FORMAT)) {
             return;
@@ -32,113 +37,107 @@ public function check(&$element, $schema = null, JsonPointer $path = null, $i =
 
         switch ($schema->format) {
             case 'date':
-                if (!$date = $this->validateDateTime($element, 'Y-m-d')) {
-                    $this->addError($path, sprintf('Invalid date %s, expected format YYYY-MM-DD', json_encode($element)), 'format', array('format' => $schema->format));
+                if (is_string($element) && !$date = $this->validateDateTime($element, 'Y-m-d')) {
+                    $this->addError(ConstraintError::FORMAT_DATE(), $path, [
+                            'date' => $element,
+                            'format' => $schema->format
+                        ]
+                    );
                 }
                 break;
 
             case 'time':
-                if (!$this->validateDateTime($element, 'H:i:s')) {
-                    $this->addError($path, sprintf('Invalid time %s, expected format hh:mm:ss', json_encode($element)), 'format', array('format' => $schema->format));
+                if (is_string($element) && !$this->validateDateTime($element, 'H:i:s')) {
+                    $this->addError(ConstraintError::FORMAT_TIME(), $path, [
+                            'time' => json_encode($element),
+                            'format' => $schema->format,
+                        ]
+                    );
                 }
                 break;
 
             case 'date-time':
-                if (null === Rfc3339::createFromString($element)) {
-                    $this->addError($path, sprintf('Invalid date-time %s, expected format YYYY-MM-DDThh:mm:ssZ or YYYY-MM-DDThh:mm:ss+hh:mm', json_encode($element)), 'format', array('format' => $schema->format));
+                if (is_string($element) && null === Rfc3339::createFromString($element)) {
+                    $this->addError(ConstraintError::FORMAT_DATE_TIME(), $path, [
+                            'dateTime' => json_encode($element),
+                            'format' => $schema->format
+                        ]
+                    );
                 }
                 break;
 
             case 'utc-millisec':
                 if (!$this->validateDateTime($element, 'U')) {
-                    $this->addError($path, sprintf('Invalid time %s, expected integer of milliseconds since Epoch', json_encode($element)), 'format', array('format' => $schema->format));
+                    $this->addError(ConstraintError::FORMAT_DATE_UTC(), $path, [
+                        'value' => $element,
+                        'format' => $schema->format]);
                 }
                 break;
 
             case 'regex':
                 if (!$this->validateRegex($element)) {
-                    $this->addError($path, 'Invalid regex format ' . $element, 'format', array('format' => $schema->format));
+                    $this->addError(ConstraintError::FORMAT_REGEX(), $path, [
+                            'value' => $element,
+                            'format' => $schema->format
+                        ]
+                    );
                 }
                 break;
 
             case 'color':
                 if (!$this->validateColor($element)) {
-                    $this->addError($path, 'Invalid color', 'format', array('format' => $schema->format));
+                    $this->addError(ConstraintError::FORMAT_COLOR(), $path, ['format' => $schema->format]);
                 }
                 break;
 
             case 'style':
                 if (!$this->validateStyle($element)) {
-                    $this->addError($path, 'Invalid style', 'format', array('format' => $schema->format));
+                    $this->addError(ConstraintError::FORMAT_STYLE(), $path, ['format' => $schema->format]);
                 }
                 break;
 
             case 'phone':
                 if (!$this->validatePhone($element)) {
-                    $this->addError($path, 'Invalid phone number', 'format', array('format' => $schema->format));
+                    $this->addError(ConstraintError::FORMAT_PHONE(), $path, ['format' => $schema->format]);
                 }
                 break;
 
             case 'uri':
-                if (null === filter_var($element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE)) {
-                    $this->addError($path, 'Invalid URL format', 'format', array('format' => $schema->format));
+                if (is_string($element) && !UriValidator::isValid($element)) {
+                    $this->addError(ConstraintError::FORMAT_URL(), $path, ['format' => $schema->format]);
                 }
                 break;
 
             case 'uriref':
             case 'uri-reference':
-                if (null === filter_var($element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE)) {
-                    // FILTER_VALIDATE_URL does not conform to RFC-3986, and cannot handle relative URLs, but
-                    // the json-schema spec uses RFC-3986, so need a bit of hackery to properly validate them.
-                    // See https://tools.ietf.org/html/rfc3986#section-4.2 for additional information.
-                    if (substr($element, 0, 2) === '//') { // network-path reference
-                        $validURL = filter_var('scheme:' . $element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE);
-                    } elseif (substr($element, 0, 1) === '/') { // absolute-path reference
-                        $validURL = filter_var('scheme://host' . $element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE);
-                    } elseif (strlen($element)) { // relative-path reference
-                        $pathParts = explode('/', $element, 2);
-                        if (strpos($pathParts[0], ':') !== false) {
-                            $validURL = null;
-                        } else {
-                            $validURL = filter_var('scheme://host/' . $element, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE);
-                        }
-                    } else {
-                        $validURL = null;
-                    }
-                    if ($validURL === null) {
-                        $this->addError($path, 'Invalid URL format', 'format', array('format' => $schema->format));
-                    }
+                if (is_string($element) && !(UriValidator::isValid($element) || RelativeReferenceValidator::isValid($element))) {
+                    $this->addError(ConstraintError::FORMAT_URL(), $path, ['format' => $schema->format]);
                 }
                 break;
 
             case 'email':
-                $filterFlags = FILTER_NULL_ON_FAILURE;
-                if (defined('FILTER_FLAG_EMAIL_UNICODE')) {
-                    // Only available from PHP >= 7.1.0, so ignore it for coverage checks
-                    $filterFlags |= constant('FILTER_FLAG_EMAIL_UNICODE'); // @codeCoverageIgnore
-                }
-                if (null === filter_var($element, FILTER_VALIDATE_EMAIL, $filterFlags)) {
-                    $this->addError($path, 'Invalid email', 'format', array('format' => $schema->format));
+                if (is_string($element) && null === filter_var($element, FILTER_VALIDATE_EMAIL, FILTER_NULL_ON_FAILURE | FILTER_FLAG_EMAIL_UNICODE)) {
+                    $this->addError(ConstraintError::FORMAT_EMAIL(), $path, ['format' => $schema->format]);
                 }
                 break;
 
             case 'ip-address':
             case 'ipv4':
-                if (null === filter_var($element, FILTER_VALIDATE_IP, FILTER_NULL_ON_FAILURE | FILTER_FLAG_IPV4)) {
-                    $this->addError($path, 'Invalid IP address', 'format', array('format' => $schema->format));
+                if (is_string($element) && null === filter_var($element, FILTER_VALIDATE_IP, FILTER_NULL_ON_FAILURE | FILTER_FLAG_IPV4)) {
+                    $this->addError(ConstraintError::FORMAT_IP(), $path, ['format' => $schema->format]);
                 }
                 break;
 
             case 'ipv6':
-                if (null === filter_var($element, FILTER_VALIDATE_IP, FILTER_NULL_ON_FAILURE | FILTER_FLAG_IPV6)) {
-                    $this->addError($path, 'Invalid IP address', 'format', array('format' => $schema->format));
+                if (is_string($element) && null === filter_var($element, FILTER_VALIDATE_IP, FILTER_NULL_ON_FAILURE | FILTER_FLAG_IPV6)) {
+                    $this->addError(ConstraintError::FORMAT_IP(), $path, ['format' => $schema->format]);
                 }
                 break;
 
             case 'host-name':
             case 'hostname':
                 if (!$this->validateHostname($element)) {
-                    $this->addError($path, 'Invalid hostname', 'format', array('format' => $schema->format));
+                    $this->addError(ConstraintError::FORMAT_HOSTNAME(), $path, ['format' => $schema->format]);
                 }
                 break;
 
@@ -155,7 +154,7 @@ public function check(&$element, $schema = null, JsonPointer $path = null, $i =
 
     protected function validateDateTime($datetime, $format)
     {
-        $dt = \DateTime::createFromFormat($format, $datetime);
+        $dt = \DateTime::createFromFormat($format, (string) $datetime);
 
         if (!$dt) {
             return false;
@@ -165,27 +164,27 @@ protected function validateDateTime($datetime, $format)
             return true;
         }
 
-        // handles the case where a non-6 digit microsecond datetime is passed
-        // which will fail the above string comparison because the passed
-        // $datetime may be '2000-05-01T12:12:12.123Z' but format() will return
-        // '2000-05-01T12:12:12.123000Z'
-        if ((strpos('u', $format) !== -1) && (preg_match('/\.\d+Z$/', $datetime))) {
-            return true;
-        }
-
         return false;
     }
 
     protected function validateRegex($regex)
     {
-        return false !== @preg_match('/' . $regex . '/u', '');
+        if (!is_string($regex)) {
+            return true;
+        }
+
+        return false !== @preg_match(self::jsonPatternToPhpRegex($regex), '');
     }
 
     protected function validateColor($color)
     {
-        if (in_array(strtolower($color), array('aqua', 'black', 'blue', 'fuchsia',
+        if (!is_string($color)) {
+            return true;
+        }
+
+        if (in_array(strtolower($color), ['aqua', 'black', 'blue', 'fuchsia',
             'gray', 'green', 'lime', 'maroon', 'navy', 'olive', 'orange', 'purple',
-            'red', 'silver', 'teal', 'white', 'yellow'))) {
+            'red', 'silver', 'teal', 'white', 'yellow'])) {
             return true;
         }
 
@@ -207,6 +206,10 @@ protected function validatePhone($phone)
 
     protected function validateHostname($host)
     {
+        if (!is_string($host)) {
+            return true;
+        }
+
         $hostnameRegex = '/^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/i';
 
         return preg_match($hostnameRegex, $host);
diff --git a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/NumberConstraint.php b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/NumberConstraint.php
index d4c31a469..e1b2ffc3a 100644
--- a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/NumberConstraint.php
+++ b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/NumberConstraint.php
@@ -1,5 +1,7 @@
 exclusiveMinimum)) {
             if (isset($schema->minimum)) {
                 if ($schema->exclusiveMinimum && $element <= $schema->minimum) {
-                    $this->addError($path, 'Must have a minimum value of ' . $schema->minimum, 'exclusiveMinimum', array('minimum' => $schema->minimum));
+                    $this->addError(ConstraintError::EXCLUSIVE_MINIMUM(), $path, ['minimum' => $schema->minimum]);
                 } elseif ($element < $schema->minimum) {
-                    $this->addError($path, 'Must have a minimum value of ' . $schema->minimum, 'minimum', array('minimum' => $schema->minimum));
+                    $this->addError(ConstraintError::MINIMUM(), $path, ['minimum' => $schema->minimum]);
                 }
             } else {
-                $this->addError($path, 'Use of exclusiveMinimum requires presence of minimum', 'missingMinimum');
+                $this->addError(ConstraintError::MISSING_MINIMUM(), $path);
             }
         } elseif (isset($schema->minimum) && $element < $schema->minimum) {
-            $this->addError($path, 'Must have a minimum value of ' . $schema->minimum, 'minimum', array('minimum' => $schema->minimum));
+            $this->addError(ConstraintError::MINIMUM(), $path, ['minimum' => $schema->minimum]);
         }
 
         // Verify maximum
         if (isset($schema->exclusiveMaximum)) {
             if (isset($schema->maximum)) {
                 if ($schema->exclusiveMaximum && $element >= $schema->maximum) {
-                    $this->addError($path, 'Must have a maximum value of ' . $schema->maximum, 'exclusiveMaximum', array('maximum' => $schema->maximum));
+                    $this->addError(ConstraintError::EXCLUSIVE_MAXIMUM(), $path, ['maximum' => $schema->maximum]);
                 } elseif ($element > $schema->maximum) {
-                    $this->addError($path, 'Must have a maximum value of ' . $schema->maximum, 'maximum', array('maximum' => $schema->maximum));
+                    $this->addError(ConstraintError::MAXIMUM(), $path, ['maximum' => $schema->maximum]);
                 }
             } else {
-                $this->addError($path, 'Use of exclusiveMaximum requires presence of maximum', 'missingMaximum');
+                $this->addError(ConstraintError::MISSING_MAXIMUM(), $path);
             }
         } elseif (isset($schema->maximum) && $element > $schema->maximum) {
-            $this->addError($path, 'Must have a maximum value of ' . $schema->maximum, 'maximum', array('maximum' => $schema->maximum));
+            $this->addError(ConstraintError::MAXIMUM(), $path, ['maximum' => $schema->maximum]);
         }
 
         // Verify divisibleBy - Draft v3
         if (isset($schema->divisibleBy) && $this->fmod($element, $schema->divisibleBy) != 0) {
-            $this->addError($path, 'Is not divisible by ' . $schema->divisibleBy, 'divisibleBy', array('divisibleBy' => $schema->divisibleBy));
+            $this->addError(ConstraintError::DIVISIBLE_BY(), $path, ['divisibleBy' => $schema->divisibleBy]);
         }
 
         // Verify multipleOf - Draft v4
         if (isset($schema->multipleOf) && $this->fmod($element, $schema->multipleOf) != 0) {
-            $this->addError($path, 'Must be a multiple of ' . $schema->multipleOf, 'multipleOf', array('multipleOf' => $schema->multipleOf));
+            $this->addError(ConstraintError::MULTIPLE_OF(), $path, ['multipleOf' => $schema->multipleOf]);
         }
 
         $this->checkFormat($element, $schema, $path, $i);
diff --git a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/ObjectConstraint.php b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/ObjectConstraint.php
index 0010d2941..c2c614a90 100644
--- a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/ObjectConstraint.php
+++ b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/ObjectConstraint.php
@@ -1,42 +1,40 @@
 
- * @author Bruno Prieto Reis 
- */
 class ObjectConstraint extends Constraint
 {
     /**
-     * @var array List of properties to which a default value has been applied
+     * @var list List of properties to which a default value has been applied
      */
-    protected $appliedDefaults = array();
+    protected $appliedDefaults = [];
 
     /**
      * {@inheritdoc}
+     *
+     * @param list $appliedDefaults
      */
-    public function check(&$element, $schema = null, JsonPointer $path = null, $properties = null,
-        $additionalProp = null, $patternProperties = null, $appliedDefaults = array())
-    {
+    public function check(
+        &$element,
+        $schema = null,
+        ?JsonPointer $path = null,
+        $properties = null,
+        $additionalProp = null,
+        $patternProperties = null,
+        $appliedDefaults = []
+    ): void {
         if ($element instanceof UndefinedConstraint) {
             return;
         }
 
         $this->appliedDefaults = $appliedDefaults;
 
-        $matches = array();
+        $matches = [];
         if ($patternProperties) {
             // validate the element pattern properties
             $matches = $this->validatePatternProperties($element, $path, $patternProperties);
@@ -51,26 +49,19 @@ public function check(&$element, $schema = null, JsonPointer $path = null, $prop
         $this->validateElement($element, $matches, $schema, $path, $properties, $additionalProp);
     }
 
-    public function validatePatternProperties($element, JsonPointer $path = null, $patternProperties)
+    public function validatePatternProperties($element, ?JsonPointer $path, $patternProperties)
     {
-        $try = array('/', '#', '+', '~', '%');
-        $matches = array();
+        $matches = [];
         foreach ($patternProperties as $pregex => $schema) {
-            $delimiter = '/';
-            // Choose delimiter. Necessary for patterns like ^/ , otherwise you get error
-            foreach ($try as $delimiter) {
-                if (strpos($pregex, $delimiter) === false) { // safe to use
-                    break;
-                }
-            }
+            $fullRegex = self::jsonPatternToPhpRegex($pregex);
 
             // Validate the pattern before using it to test for matches
-            if (@preg_match($delimiter . $pregex . $delimiter . 'u', '') === false) {
-                $this->addError($path, 'The pattern "' . $pregex . '" is invalid', 'pregex', array('pregex' => $pregex));
+            if (@preg_match($fullRegex, '') === false) {
+                $this->addError(ConstraintError::PREGEX_INVALID(), $path, ['pregex' => $pregex]);
                 continue;
             }
             foreach ($element as $i => $value) {
-                if (preg_match($delimiter . $pregex . $delimiter . 'u', $i)) {
+                if (preg_match($fullRegex, $i)) {
                     $matches[] = $i;
                     $this->checkUndefined($value, $schema ?: new \stdClass(), $path, $i, in_array($i, $this->appliedDefaults));
                 }
@@ -90,7 +81,7 @@ public function validatePatternProperties($element, JsonPointer $path = null, $p
      * @param \StdClass        $properties     Properties
      * @param mixed            $additionalProp Additional properties
      */
-    public function validateElement($element, $matches, $schema = null, JsonPointer $path = null,
+    public function validateElement($element, $matches, $schema = null, ?JsonPointer $path = null,
         $properties = null, $additionalProp = null)
     {
         $this->validateMinMaxConstraint($element, $schema, $path);
@@ -100,7 +91,7 @@ public function validateElement($element, $matches, $schema = null, JsonPointer
 
             // no additional properties allowed
             if (!in_array($i, $matches) && $additionalProp === false && $this->inlineSchemaProperty !== $i && !$definition) {
-                $this->addError($path, 'The property ' . $i . ' is not defined and the definition does not allow additional properties', 'additionalProp');
+                $this->addError(ConstraintError::ADDITIONAL_PROPERTIES(), $path, ['property' => $i]);
             }
 
             // additional properties defined
@@ -115,7 +106,10 @@ public function validateElement($element, $matches, $schema = null, JsonPointer
             // property requires presence of another
             $require = $this->getProperty($definition, 'requires');
             if ($require && !$this->getProperty($element, $require)) {
-                $this->addError($path, 'The presence of the property ' . $i . ' requires that ' . $require . ' also be present', 'requires');
+                $this->addError(ConstraintError::REQUIRES(), $path, [
+                    'property' => $i,
+                    'requiredProperty' => $require
+                ]);
             }
 
             $property = $this->getProperty($element, $i, $this->factory->createInstanceFor('undefined'));
@@ -132,7 +126,7 @@ public function validateElement($element, $matches, $schema = null, JsonPointer
      * @param \stdClass        $properties Property definitions
      * @param JsonPointer|null $path       Path?
      */
-    public function validateProperties(&$element, $properties = null, JsonPointer $path = null)
+    public function validateProperties(&$element, $properties = null, ?JsonPointer $path = null)
     {
         $undefinedConstraint = $this->factory->createInstanceFor('undefined');
 
@@ -160,7 +154,7 @@ protected function &getProperty(&$element, $property, $fallback = null)
     {
         if (is_array($element) && (isset($element[$property]) || array_key_exists($property, $element)) /*$this->checkMode == self::CHECK_MODE_TYPE_CAST*/) {
             return $element[$property];
-        } elseif (is_object($element) && property_exists($element, $property)) {
+        } elseif (is_object($element) && property_exists($element, (string) $property)) {
             return $element->$property;
         }
 
@@ -174,18 +168,22 @@ protected function &getProperty(&$element, $property, $fallback = null)
      * @param \stdClass        $objectDefinition ObjectConstraint definition
      * @param JsonPointer|null $path             Path to test?
      */
-    protected function validateMinMaxConstraint($element, $objectDefinition, JsonPointer $path = null)
+    protected function validateMinMaxConstraint($element, $objectDefinition, ?JsonPointer $path = null)
     {
+        if (!$this->getTypeCheck()::isObject($element)) {
+            return;
+        }
+
         // Verify minimum number of properties
-        if (isset($objectDefinition->minProperties) && !is_object($objectDefinition->minProperties)) {
-            if ($this->getTypeCheck()->propertyCount($element) < $objectDefinition->minProperties) {
-                $this->addError($path, 'Must contain a minimum of ' . $objectDefinition->minProperties . ' properties', 'minProperties', array('minProperties' => $objectDefinition->minProperties));
+        if (isset($objectDefinition->minProperties) && is_int($objectDefinition->minProperties)) {
+            if ($this->getTypeCheck()->propertyCount($element) < max(0, $objectDefinition->minProperties)) {
+                $this->addError(ConstraintError::PROPERTIES_MIN(), $path, ['minProperties' => $objectDefinition->minProperties]);
             }
         }
         // Verify maximum number of properties
-        if (isset($objectDefinition->maxProperties) && !is_object($objectDefinition->maxProperties)) {
-            if ($this->getTypeCheck()->propertyCount($element) > $objectDefinition->maxProperties) {
-                $this->addError($path, 'Must contain no more than ' . $objectDefinition->maxProperties . ' properties', 'maxProperties', array('maxProperties' => $objectDefinition->maxProperties));
+        if (isset($objectDefinition->maxProperties) && is_int($objectDefinition->maxProperties)) {
+            if ($this->getTypeCheck()->propertyCount($element) > max(0, $objectDefinition->maxProperties)) {
+                $this->addError(ConstraintError::PROPERTIES_MAX(), $path, ['maxProperties' => $objectDefinition->maxProperties]);
             }
         }
     }
diff --git a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/SchemaConstraint.php b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/SchemaConstraint.php
index db665ad38..7852e8518 100644
--- a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/SchemaConstraint.php
+++ b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/SchemaConstraint.php
@@ -1,5 +1,7 @@
 numErrors() > $initialErrorCount) {
-                $this->addError($path, 'Schema is not valid', 'schema');
+                $this->addError(ConstraintError::INVALID_SCHEMA(), $path);
             }
 
             // restore the initial config
diff --git a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/StringConstraint.php b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/StringConstraint.php
index c66af1ed6..7b811614a 100644
--- a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/StringConstraint.php
+++ b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/StringConstraint.php
@@ -1,5 +1,7 @@
 maxLength) && $this->strlen($element) > $schema->maxLength) {
-            $this->addError($path, 'Must be at most ' . $schema->maxLength . ' characters long', 'maxLength', array(
+            $this->addError(ConstraintError::LENGTH_MAX(), $path, [
                 'maxLength' => $schema->maxLength,
-            ));
+            ]);
         }
 
         //verify minLength
         if (isset($schema->minLength) && $this->strlen($element) < $schema->minLength) {
-            $this->addError($path, 'Must be at least ' . $schema->minLength . ' characters long', 'minLength', array(
+            $this->addError(ConstraintError::LENGTH_MIN(), $path, [
                 'minLength' => $schema->minLength,
-            ));
+            ]);
         }
 
         // Verify a regex pattern
-        if (isset($schema->pattern) && !preg_match('#' . str_replace('#', '\\#', $schema->pattern) . '#u', $element)) {
-            $this->addError($path, 'Does not match the regex pattern ' . $schema->pattern, 'pattern', array(
+        if (isset($schema->pattern) && !preg_match(self::jsonPatternToPhpRegex($schema->pattern), $element)) {
+            $this->addError(ConstraintError::PATTERN(), $path, [
                 'pattern' => $schema->pattern,
-            ));
+            ]);
         }
 
         $this->checkFormat($element, $schema, $path, $i);
diff --git a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/TypeCheck/LooseTypeCheck.php b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/TypeCheck/LooseTypeCheck.php
index 984288539..8f9f349b7 100644
--- a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/TypeCheck/LooseTypeCheck.php
+++ b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/TypeCheck/LooseTypeCheck.php
@@ -1,5 +1,7 @@
  'an integer',
         'number'  => 'a number',
         'boolean' => 'a boolean',
@@ -34,25 +37,33 @@ class TypeConstraint extends Constraint
         'null'    => 'a null',
         'any'     => null, // validation of 'any' is always true so is not needed in message wording
         0         => null, // validation of a false-y value is always true, so not needed as well
-    );
+    ];
 
     /**
      * {@inheritdoc}
      */
-    public function check(&$value = null, $schema = null, JsonPointer $path = null, $i = null)
+    public function check(&$value = null, $schema = null, ?JsonPointer $path = null, $i = null): void
     {
         $type = isset($schema->type) ? $schema->type : null;
         $isValid = false;
-        $wording = array();
+        $coerce = $this->factory->getConfig(self::CHECK_MODE_COERCE_TYPES);
+        $earlyCoerce = $this->factory->getConfig(self::CHECK_MODE_EARLY_COERCE);
+        $wording = [];
 
         if (is_array($type)) {
-            $this->validateTypesArray($value, $type, $wording, $isValid, $path);
+            $this->validateTypesArray($value, $type, $wording, $isValid, $path, $coerce && $earlyCoerce);
+            if (!$isValid && $coerce && !$earlyCoerce) {
+                $this->validateTypesArray($value, $type, $wording, $isValid, $path, true);
+            }
         } elseif (is_object($type)) {
             $this->checkUndefined($value, $type, $path);
 
             return;
         } else {
-            $isValid = $this->validateType($value, $type);
+            $isValid = $this->validateType($value, $type, $coerce && $earlyCoerce);
+            if (!$isValid && $coerce && !$earlyCoerce) {
+                $isValid = $this->validateType($value, $type, true);
+            }
         }
 
         if ($isValid === false) {
@@ -60,8 +71,10 @@ public function check(&$value = null, $schema = null, JsonPointer $path = null,
                 $this->validateTypeNameWording($type);
                 $wording[] = self::$wording[$type];
             }
-            $this->addError($path, ucwords(gettype($value)) . ' value found, but ' .
-                $this->implodeWith($wording, ', ', 'or') . ' is required', 'type');
+            $this->addError(ConstraintError::TYPE(), $path, [
+                    'found' => gettype($value),
+                    'expected' => $this->implodeWith($wording, ', ', 'or')
+            ]);
         }
     }
 
@@ -70,15 +83,21 @@ public function check(&$value = null, $schema = null, JsonPointer $path = null,
      * of $isValid to true, if at least one $type mateches the type of $value or the value
      * passed as $isValid is already true.
      *
-     * @param mixed $value             Value to validate
-     * @param array $type              TypeConstraints to check agains
-     * @param array $validTypesWording An array of wordings of the valid types of the array $type
-     * @param bool  $isValid           The current validation value
-     * @param $path
+     * @param mixed        $value             Value to validate
+     * @param array        $type              TypeConstraints to check against
+     * @param array        $validTypesWording An array of wordings of the valid types of the array $type
+     * @param bool         $isValid           The current validation value
+     * @param ?JsonPointer $path
+     * @param bool         $coerce
      */
-    protected function validateTypesArray(&$value, array $type, &$validTypesWording, &$isValid, $path)
+    protected function validateTypesArray(&$value, array $type, &$validTypesWording, &$isValid, $path, $coerce = false)
     {
         foreach ($type as $tp) {
+            // already valid, so no need to waste cycles looping over everything
+            if ($isValid) {
+                return;
+            }
+
             // $tp can be an object, if it's a schema instead of a simple type, validate it
             // with a new type constraint
             if (is_object($tp)) {
@@ -95,7 +114,7 @@ protected function validateTypesArray(&$value, array $type, &$validTypesWording,
                 $this->validateTypeNameWording($tp);
                 $validTypesWording[] = self::$wording[$tp];
                 if (!$isValid) {
-                    $isValid = $this->validateType($value, $tp);
+                    $isValid = $this->validateType($value, $tp, $coerce);
                 }
             }
         }
@@ -119,7 +138,7 @@ protected function implodeWith(array $elements, $delimiter = ', ', $listEnd = fa
         }
         $lastElement  = array_slice($elements, -1);
         $firsElements = join($delimiter, array_slice($elements, 0, -1));
-        $implodedElements = array_merge(array($firsElements), $lastElement);
+        $implodedElements = array_merge([$firsElements], $lastElement);
 
         return join(" $listEnd ", $implodedElements);
     }
@@ -154,7 +173,7 @@ protected function validateTypeNameWording($type)
      *
      * @return bool
      */
-    protected function validateType(&$value, $type)
+    protected function validateType(&$value, $type, $coerce = false)
     {
         //mostly the case for inline schema
         if (!$type) {
@@ -170,11 +189,13 @@ protected function validateType(&$value, $type)
         }
 
         if ('array' === $type) {
+            if ($coerce) {
+                $value = $this->toArray($value);
+            }
+
             return $this->getTypeCheck()->isArray($value);
         }
 
-        $coerce = $this->factory->getConfig(Constraint::CHECK_MODE_COERCE_TYPES);
-
         if ('integer' === $type) {
             if ($coerce) {
                 $value = $this->toInteger($value);
@@ -200,14 +221,18 @@ protected function validateType(&$value, $type)
         }
 
         if ('string' === $type) {
-            return is_string($value);
-        }
+            if ($coerce) {
+                $value = $this->toString($value);
+            }
 
-        if ('email' === $type) {
             return is_string($value);
         }
 
         if ('null' === $type) {
+            if ($coerce) {
+                $value = $this->toNull($value);
+            }
+
             return is_null($value);
         }
 
@@ -217,25 +242,27 @@ protected function validateType(&$value, $type)
     /**
      * Converts a value to boolean. For example, "true" becomes true.
      *
-     * @param $value The value to convert to boolean
+     * @param mixed $value The value to convert to boolean
      *
      * @return bool|mixed
      */
     protected function toBoolean($value)
     {
-        if ($value === 'true') {
+        if ($value === 1 || $value === 'true') {
             return true;
         }
-
-        if ($value === 'false') {
+        if (is_null($value) || $value === 0 || $value === 'false') {
             return false;
         }
+        if ($this->getTypeCheck()->isArray($value) && count($value) === 1) {
+            return $this->toBoolean(reset($value));
+        }
 
         return $value;
     }
 
     /**
-     * Converts a numeric string to a number. For example, "4" becomes 4.
+     * Converts a value to a number. For example, "4.5" becomes 4.5.
      *
      * @param mixed $value the value to convert to a number
      *
@@ -246,14 +273,91 @@ protected function toNumber($value)
         if (is_numeric($value)) {
             return $value + 0; // cast to number
         }
+        if (is_bool($value) || is_null($value)) {
+            return (int) $value;
+        }
+        if ($this->getTypeCheck()->isArray($value) && count($value) === 1) {
+            return $this->toNumber(reset($value));
+        }
 
         return $value;
     }
 
+    /**
+     * Converts a value to an integer. For example, "4" becomes 4.
+     *
+     * @param mixed $value
+     *
+     * @return int|mixed
+     */
     protected function toInteger($value)
     {
-        if (is_numeric($value) && (int) $value == $value) {
-            return (int) $value; // cast to number
+        $numberValue = $this->toNumber($value);
+        if (is_numeric($numberValue) && (int) $numberValue == $numberValue) {
+            return (int) $numberValue; // cast to number
+        }
+
+        return $value;
+    }
+
+    /**
+     * Converts a value to an array containing that value. For example, [4] becomes 4.
+     *
+     * @param mixed $value
+     *
+     * @return array|mixed
+     */
+    protected function toArray($value)
+    {
+        if (is_scalar($value) || is_null($value)) {
+            return [$value];
+        }
+
+        return $value;
+    }
+
+    /**
+     * Convert a value to a string representation of that value. For example, null becomes "".
+     *
+     * @param mixed $value
+     *
+     * @return string|mixed
+     */
+    protected function toString($value)
+    {
+        if (is_numeric($value)) {
+            return "$value";
+        }
+        if ($value === true) {
+            return 'true';
+        }
+        if ($value === false) {
+            return 'false';
+        }
+        if (is_null($value)) {
+            return '';
+        }
+        if ($this->getTypeCheck()->isArray($value) && count($value) === 1) {
+            return $this->toString(reset($value));
+        }
+
+        return $value;
+    }
+
+    /**
+     * Convert a value to a null. For example, 0 becomes null.
+     *
+     * @param mixed $value
+     *
+     * @return null|mixed
+     */
+    protected function toNull($value)
+    {
+        if ($value === 0 || $value === false || $value === '') {
+            return null;
+        }
+        if ($this->getTypeCheck()->isArray($value) && count($value) === 1) {
+            return $this->toNull(reset($value));
         }
 
         return $value;
diff --git a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/UndefinedConstraint.php b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/UndefinedConstraint.php
index 1e984a3db..1ea0a7bc1 100644
--- a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/UndefinedConstraint.php
+++ b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Constraints/UndefinedConstraint.php
@@ -1,43 +1,34 @@
 
- * @author Bruno Prieto Reis 
- */
 #[\AllowDynamicProperties]
 class UndefinedConstraint extends Constraint
 {
     /**
-     * @var array List of properties to which a default value has been applied
+     * @var list List of properties to which a default value has been applied
      */
-    protected $appliedDefaults = array();
+    protected $appliedDefaults = [];
 
     /**
      * {@inheritdoc}
-     */
-    public function check(&$value, $schema = null, JsonPointer $path = null, $i = null, $fromDefault = false)
+     * */
+    public function check(&$value, $schema = null, ?JsonPointer $path = null, $i = null, bool $fromDefault = false): void
     {
         if (is_null($schema) || !is_object($schema)) {
             return;
         }
 
-        $path = $this->incrementPath($path ?: new JsonPointer(''), $i);
+        $path = $this->incrementPath($path, $i);
         if ($fromDefault) {
             $path->setFromDefault();
         }
@@ -68,9 +59,10 @@ public function validateTypes(&$value, $schema, JsonPointer $path, $i = null)
         }
 
         // check object
-        if (LooseTypeCheck::isObject($value)) { // object processing should always be run on assoc arrays,
-                                                // so use LooseTypeCheck here even if CHECK_MODE_TYPE_CAST
-                                                // is not set (i.e. don't use $this->getTypeCheck() here).
+        if (LooseTypeCheck::isObject($value)) {
+            // object processing should always be run on assoc arrays,
+            // so use LooseTypeCheck here even if CHECK_MODE_TYPE_CAST
+            // is not set (i.e. don't use $this->getTypeCheck() here).
             $this->checkObject(
                 $value,
                 $schema,
@@ -96,6 +88,11 @@ public function validateTypes(&$value, $schema, JsonPointer $path, $i = null)
         if (isset($schema->enum)) {
             $this->checkEnum($value, $schema, $path, $i);
         }
+
+        // check const
+        if (isset($schema->const)) {
+            $this->checkConst($value, $schema, $path, $i);
+        }
     }
 
     /**
@@ -134,9 +131,10 @@ protected function validateCommonProperties(&$value, $schema, JsonPointer $path,
                 foreach ($schema->required as $required) {
                     if (!$this->getTypeCheck()->propertyExists($value, $required)) {
                         $this->addError(
-                            $this->incrementPath($path ?: new JsonPointer(''), $required),
-                            'The property ' . $required . ' is required',
-                            'required'
+                            ConstraintError::REQUIRED(),
+                            $this->incrementPath($path, $required), [
+                                'property' => $required
+                            ]
                         );
                     }
                 }
@@ -145,11 +143,7 @@ protected function validateCommonProperties(&$value, $schema, JsonPointer $path,
                 if ($schema->required && $value instanceof self) {
                     $propertyPaths = $path->getPropertyPaths();
                     $propertyName = end($propertyPaths);
-                    $this->addError(
-                        $path,
-                        'The property ' . $propertyName . ' is required',
-                        'required'
-                    );
+                    $this->addError(ConstraintError::REQUIRED(), $path, ['property' => $propertyName]);
                 }
             } else {
                 // if the value is both undefined and not required, skip remaining checks
@@ -175,7 +169,7 @@ protected function validateCommonProperties(&$value, $schema, JsonPointer $path,
 
             // if no new errors were raised it must be a disallowed value
             if (count($this->getErrors()) == count($initErrors)) {
-                $this->addError($path, 'Disallowed value was matched', 'disallow');
+                $this->addError(ConstraintError::DISALLOW(), $path);
             } else {
                 $this->errors = $initErrors;
             }
@@ -187,7 +181,7 @@ protected function validateCommonProperties(&$value, $schema, JsonPointer $path,
 
             // if no new errors were raised then the instance validated against the "not" schema
             if (count($this->getErrors()) == count($initErrors)) {
-                $this->addError($path, 'Matched a schema which it should not', 'not');
+                $this->addError(ConstraintError::NOT(), $path);
             } else {
                 $this->errors = $initErrors;
             }
@@ -238,7 +232,7 @@ private function shouldApplyDefaultValue($requiredOnly, $schema, $name = null, $
      * @param mixed       $schema
      * @param JsonPointer $path
      */
-    protected function applyDefaultValues(&$value, $schema, $path)
+    protected function applyDefaultValues(&$value, $schema, $path): void
     {
         // only apply defaults if feature is enabled
         if (!$this->factory->getConfig(self::CHECK_MODE_APPLY_DEFAULTS)) {
@@ -246,7 +240,7 @@ protected function applyDefaultValues(&$value, $schema, $path)
         }
 
         // apply defaults if appropriate
-        $requiredOnly = $this->factory->getConfig(self::CHECK_MODE_ONLY_REQUIRED_DEFAULTS);
+        $requiredOnly = (bool) $this->factory->getConfig(self::CHECK_MODE_ONLY_REQUIRED_DEFAULTS);
         if (isset($schema->properties) && LooseTypeCheck::isObject($value)) {
             // $value is an object or assoc array, and properties are defined - treat as an object
             foreach ($schema->properties as $currentProperty => $propertyDefinition) {
@@ -266,7 +260,7 @@ protected function applyDefaultValues(&$value, $schema, $path)
                 }
             }
         } elseif (isset($schema->items) && LooseTypeCheck::isArray($value)) {
-            $items = array();
+            $items = [];
             if (LooseTypeCheck::isArray($schema->items)) {
                 $items = $schema->items;
             } elseif (isset($schema->minItems) && count($value) < $schema->minItems) {
@@ -320,19 +314,22 @@ protected function validateOfProperties(&$value, $schema, JsonPointer $path, $i
                 $isValid = $isValid && (count($this->getErrors()) == count($initErrors));
             }
             if (!$isValid) {
-                $this->addError($path, 'Failed to match all schemas', 'allOf');
+                $this->addError(ConstraintError::ALL_OF(), $path);
             }
         }
 
         if (isset($schema->anyOf)) {
             $isValid = false;
             $startErrors = $this->getErrors();
-            $caughtException = null;
+            $coerceOrDefaults = $this->factory->getConfig(self::CHECK_MODE_COERCE_TYPES | self::CHECK_MODE_APPLY_DEFAULTS);
+
             foreach ($schema->anyOf as $anyOf) {
                 $initErrors = $this->getErrors();
                 try {
-                    $this->checkUndefined($value, $anyOf, $path, $i);
-                    if ($isValid = (count($this->getErrors()) == count($initErrors))) {
+                    $anyOfValue = $coerceOrDefaults ? DeepCopy::copyOf($value) : $value;
+                    $this->checkUndefined($anyOfValue, $anyOf, $path, $i);
+                    if ($isValid = (count($this->getErrors()) === count($initErrors))) {
+                        $value = $anyOfValue;
                         break;
                     }
                 } catch (ValidationException $e) {
@@ -340,22 +337,26 @@ protected function validateOfProperties(&$value, $schema, JsonPointer $path, $i
                 }
             }
             if (!$isValid) {
-                $this->addError($path, 'Failed to match at least one schema', 'anyOf');
+                $this->addError(ConstraintError::ANY_OF(), $path);
             } else {
                 $this->errors = $startErrors;
             }
         }
 
         if (isset($schema->oneOf)) {
-            $allErrors = array();
-            $matchedSchemas = 0;
+            $allErrors = [];
+            $matchedSchemas = [];
             $startErrors = $this->getErrors();
+            $coerceOrDefaults = $this->factory->getConfig(self::CHECK_MODE_COERCE_TYPES | self::CHECK_MODE_APPLY_DEFAULTS);
+
             foreach ($schema->oneOf as $oneOf) {
                 try {
-                    $this->errors = array();
-                    $this->checkUndefined($value, $oneOf, $path, $i);
-                    if (count($this->getErrors()) == 0) {
-                        $matchedSchemas++;
+                    $this->errors = [];
+
+                    $oneOfValue = $coerceOrDefaults ? DeepCopy::copyOf($value) : $value;
+                    $this->checkUndefined($oneOfValue, $oneOf, $path, $i);
+                    if (count($this->getErrors()) === 0) {
+                        $matchedSchemas[] = ['schema' => $oneOf, 'value' => $oneOfValue];
                     }
                     $allErrors = array_merge($allErrors, array_values($this->getErrors()));
                 } catch (ValidationException $e) {
@@ -363,11 +364,12 @@ protected function validateOfProperties(&$value, $schema, JsonPointer $path, $i
                     // other schema options in the OneOf field.
                 }
             }
-            if ($matchedSchemas !== 1) {
+            if (count($matchedSchemas) !== 1) {
                 $this->addErrors(array_merge($allErrors, $startErrors));
-                $this->addError($path, 'Failed to match exactly one schema', 'oneOf');
+                $this->addError(ConstraintError::ONE_OF(), $path);
             } else {
                 $this->errors = $startErrors;
+                $value = $matchedSchemas[0]['value'];
             }
         }
     }
@@ -387,13 +389,19 @@ protected function validateDependencies($value, $dependencies, JsonPointer $path
                 if (is_string($dependency)) {
                     // Draft 3 string is allowed - e.g. "dependencies": {"bar": "foo"}
                     if (!$this->getTypeCheck()->propertyExists($value, $dependency)) {
-                        $this->addError($path, "$key depends on $dependency and $dependency is missing", 'dependencies');
+                        $this->addError(ConstraintError::DEPENDENCIES(), $path, [
+                            'key' => $key,
+                            'dependency' => $dependency
+                        ]);
                     }
                 } elseif (is_array($dependency)) {
                     // Draft 4 must be an array - e.g. "dependencies": {"bar": ["foo"]}
                     foreach ($dependency as $d) {
                         if (!$this->getTypeCheck()->propertyExists($value, $d)) {
-                            $this->addError($path, "$key depends on $d and $d is missing", 'dependencies');
+                            $this->addError(ConstraintError::DEPENDENCIES(), $path, [
+                                'key' => $key,
+                                'dependency' => $dependency
+                            ]);
                         }
                     }
                 } elseif (is_object($dependency)) {
diff --git a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Entity/JsonPointer.php b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Entity/JsonPointer.php
index fcaf5b8d7..e674fa6f8 100644
--- a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Entity/JsonPointer.php
+++ b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Entity/JsonPointer.php
@@ -1,5 +1,7 @@
 decodePath($path);
             if (is_string($path) && '' !== $path) {
@@ -71,7 +73,7 @@ private function decodePropertyPaths($propertyPathString)
     private function encodePropertyPaths()
     {
         return array_map(
-            array($this, 'encodePath'),
+            [$this, 'encodePath'],
             $this->getPropertyPaths()
         );
     }
@@ -83,7 +85,7 @@ private function encodePropertyPaths()
      */
     private function decodePath($path)
     {
-        return strtr($path, array('~1' => '/', '~0' => '~', '%25' => '%'));
+        return strtr($path, ['~1' => '/', '~0' => '~', '%25' => '%']);
     }
 
     /**
@@ -93,7 +95,7 @@ private function decodePath($path)
      */
     private function encodePath($path)
     {
-        return strtr($path, array('/' => '~1', '~' => '~0', '%' => '%25'));
+        return strtr($path, ['/' => '~1', '~' => '~0', '%' => '%25']);
     }
 
     /**
@@ -120,7 +122,7 @@ public function getPropertyPaths()
     public function withPropertyPaths(array $propertyPaths)
     {
         $new = clone $this;
-        $new->propertyPaths = $propertyPaths;
+        $new->propertyPaths = array_map(function ($p): string { return (string) $p; }, $propertyPaths);
 
         return $new;
     }
@@ -144,7 +146,7 @@ public function __toString()
     /**
      * Mark the value at this path as being set from a schema default
      */
-    public function setFromDefault()
+    public function setFromDefault(): void
     {
         $this->fromDefault = true;
     }
diff --git a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Enum.php b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Enum.php
new file mode 100644
index 000000000..ef8cb2856
--- /dev/null
+++ b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Enum.php
@@ -0,0 +1,9 @@
+initialize();
@@ -49,7 +52,7 @@ public function current()
     /**
      * {@inheritdoc}
      */
-    public function next()
+    public function next(): void
     {
         $this->initialize();
         $this->position++;
@@ -58,7 +61,7 @@ public function next()
     /**
      * {@inheritdoc}
      */
-    public function key()
+    public function key(): int
     {
         $this->initialize();
 
@@ -68,7 +71,7 @@ public function key()
     /**
      * {@inheritdoc}
      */
-    public function valid()
+    public function valid(): bool
     {
         $this->initialize();
 
@@ -78,7 +81,7 @@ public function valid()
     /**
      * {@inheritdoc}
      */
-    public function rewind()
+    public function rewind(): void
     {
         $this->initialize();
         $this->position = 0;
@@ -87,7 +90,7 @@ public function rewind()
     /**
      * {@inheritdoc}
      */
-    public function count()
+    public function count(): int
     {
         $this->initialize();
 
@@ -112,7 +115,7 @@ private function initialize()
      */
     private function buildDataFromObject($object)
     {
-        $result = array();
+        $result = [];
 
         $stack = new \SplStack();
         $stack->push($object);
@@ -141,7 +144,7 @@ private function buildDataFromObject($object)
     private function getDataFromItem($item)
     {
         if (!is_object($item) && !is_array($item)) {
-            return array();
+            return [];
         }
 
         return is_object($item) ? get_object_vars($item) : $item;
diff --git a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Rfc3339.php b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Rfc3339.php
index adca581a4..3524f681f 100644
--- a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Rfc3339.php
+++ b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Rfc3339.php
@@ -1,10 +1,12 @@
 uriRetriever = $uriRetriever ?: new UriRetriever();
         $this->uriResolver = $uriResolver ?: new UriResolver();
@@ -43,7 +45,7 @@ public function getUriResolver()
     /**
      * {@inheritdoc}
      */
-    public function addSchema($id, $schema = null)
+    public function addSchema(string $id, $schema = null): void
     {
         if (is_null($schema) && $id !== self::INTERNAL_PROVIDED_SCHEMA_URI) {
             // if the schema was user-provided to Validator and is still null, then assume this is
@@ -60,14 +62,16 @@ public function addSchema($id, $schema = null)
         // workaround for bug in draft-03 & draft-04 meta-schemas (id & $ref defined with incorrect format)
         // see https://github.com/json-schema-org/JSON-Schema-Test-Suite/issues/177#issuecomment-293051367
         if (is_object($schema) && property_exists($schema, 'id')) {
-            if ($schema->id == 'http://json-schema.org/draft-04/schema#') {
+            if ($schema->id === 'http://json-schema.org/draft-04/schema#') {
                 $schema->properties->id->format = 'uri-reference';
-            } elseif ($schema->id == 'http://json-schema.org/draft-03/schema#') {
+            } elseif ($schema->id === 'http://json-schema.org/draft-03/schema#') {
                 $schema->properties->id->format = 'uri-reference';
                 $schema->properties->{'$ref'}->format = 'uri-reference';
             }
         }
 
+        $this->scanForSubschemas($schema, $id);
+
         // resolve references
         $this->expandRefs($schema, $id);
 
@@ -77,39 +81,44 @@ public function addSchema($id, $schema = null)
     /**
      * Recursively resolve all references against the provided base
      *
-     * @param mixed  $schema
-     * @param string $base
+     * @param mixed $schema
      */
-    private function expandRefs(&$schema, $base = null)
+    private function expandRefs(&$schema, ?string $parentId = null): void
     {
         if (!is_object($schema)) {
             if (is_array($schema)) {
                 foreach ($schema as &$member) {
-                    $this->expandRefs($member, $base);
+                    $this->expandRefs($member, $parentId);
                 }
             }
 
             return;
         }
 
-        if (property_exists($schema, 'id') && is_string($schema->id) && $base != $schema->id) {
-            $base = $this->uriResolver->resolve($schema->id, $base);
-        }
-
         if (property_exists($schema, '$ref') && is_string($schema->{'$ref'})) {
-            $refPointer = new JsonPointer($this->uriResolver->resolve($schema->{'$ref'}, $base));
+            $refPointer = new JsonPointer($this->uriResolver->resolve($schema->{'$ref'}, $parentId));
             $schema->{'$ref'} = (string) $refPointer;
         }
 
-        foreach ($schema as &$member) {
-            $this->expandRefs($member, $base);
+        foreach ($schema as $propertyName => &$member) {
+            if (in_array($propertyName, ['enum', 'const'])) {
+                // Enum and const don't allow $ref as a keyword, see https://github.com/json-schema-org/JSON-Schema-Test-Suite/pull/445
+                continue;
+            }
+
+            $childId = $parentId;
+            if (property_exists($schema, 'id') && is_string($schema->id) && $childId !== $schema->id) {
+                $childId = $this->uriResolver->resolve($schema->id, $childId);
+            }
+
+            $this->expandRefs($member, $childId);
         }
     }
 
     /**
      * {@inheritdoc}
      */
-    public function getSchema($id)
+    public function getSchema(string $id)
     {
         if (!array_key_exists($id, $this->schemas)) {
             $this->addSchema($id);
@@ -121,7 +130,7 @@ public function getSchema($id)
     /**
      * {@inheritdoc}
      */
-    public function resolveRef($ref)
+    public function resolveRef(string $ref, $resolveStack = [])
     {
         $jsonPointer = new JsonPointer($ref);
 
@@ -138,9 +147,9 @@ public function resolveRef($ref)
         $refSchema = $this->getSchema($fileName);
         foreach ($jsonPointer->getPropertyPaths() as $path) {
             if (is_object($refSchema) && property_exists($refSchema, $path)) {
-                $refSchema = $this->resolveRefSchema($refSchema->{$path});
+                $refSchema = $this->resolveRefSchema($refSchema->{$path}, $resolveStack);
             } elseif (is_array($refSchema) && array_key_exists($path, $refSchema)) {
-                $refSchema = $this->resolveRefSchema($refSchema[$path]);
+                $refSchema = $this->resolveRefSchema($refSchema[$path], $resolveStack);
             } else {
                 throw new UnresolvableJsonPointerException(sprintf(
                     'File: %s is found, but could not resolve fragment: %s',
@@ -156,14 +165,48 @@ public function resolveRef($ref)
     /**
      * {@inheritdoc}
      */
-    public function resolveRefSchema($refSchema)
+    public function resolveRefSchema($refSchema, $resolveStack = [])
     {
         if (is_object($refSchema) && property_exists($refSchema, '$ref') && is_string($refSchema->{'$ref'})) {
-            $newSchema = $this->resolveRef($refSchema->{'$ref'});
-            $refSchema = (object) (get_object_vars($refSchema) + get_object_vars($newSchema));
-            unset($refSchema->{'$ref'});
+            if (in_array($refSchema, $resolveStack, true)) {
+                throw new UnresolvableJsonPointerException(sprintf(
+                    'Dereferencing a pointer to %s results in an infinite loop',
+                    $refSchema->{'$ref'}
+                ));
+            }
+            $resolveStack[] = $refSchema;
+
+            return $this->resolveRef($refSchema->{'$ref'}, $resolveStack);
         }
 
         return $refSchema;
     }
+
+    /**
+     * @param mixed $schema
+     */
+    private function scanForSubschemas($schema, string $parentId): void
+    {
+        if (!$schema instanceof \stdClass  && !is_array($schema)) {
+            return;
+        }
+
+        foreach ($schema as $propertyName => $potentialSubSchema) {
+            if (!is_object($potentialSubSchema)) {
+                continue;
+            }
+
+            if (property_exists($potentialSubSchema, 'id') && is_string($potentialSubSchema->id) && property_exists($potentialSubSchema, 'type')) {
+                // Enum and const don't allow id as a keyword, see https://github.com/json-schema-org/JSON-Schema-Test-Suite/pull/471
+                if (in_array($propertyName, ['enum', 'const'])) {
+                    continue;
+                }
+
+                // Found sub schema
+                $this->addSchema($this->uriResolver->resolve($potentialSubSchema->id, $parentId), $potentialSubSchema);
+            }
+
+            $this->scanForSubschemas($potentialSubSchema, $parentId);
+        }
+    }
 }
diff --git a/app/vendor/justinrainbow/json-schema/src/JsonSchema/SchemaStorageInterface.php b/app/vendor/justinrainbow/json-schema/src/JsonSchema/SchemaStorageInterface.php
index ddaf6633e..f625cdd28 100644
--- a/app/vendor/justinrainbow/json-schema/src/JsonSchema/SchemaStorageInterface.php
+++ b/app/vendor/justinrainbow/json-schema/src/JsonSchema/SchemaStorageInterface.php
@@ -1,5 +1,7 @@
  $left
+     * @param array $right
+     */
+    private static function isArrayEqual(array $left, array $right): bool
+    {
+        if (count($left) !== count($right)) {
+            return false;
+        }
+        foreach ($left as $key => $value) {
+            if (!array_key_exists($key, $right)) {
+                return false;
+            }
+
+            if (!self::isEqual($value, $right[$key])) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}
diff --git a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Tool/DeepCopy.php b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Tool/DeepCopy.php
new file mode 100644
index 000000000..8b09156fc
--- /dev/null
+++ b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Tool/DeepCopy.php
@@ -0,0 +1,38 @@
+ 65535)) {
+                return false;
+            }
+
+            // Validate path (reject illegal characters: < > { } | \ ^ `)
+            if (!empty($matches[6]) && preg_match('/[<>{}|\\\^`]/', $matches[6])) {
+                return false;
+            }
+
+            return true;
+        }
+
+        // If not hierarchical, check non-hierarchical URIs
+        if (preg_match($nonHierarchicalPattern, $uri, $matches) === 1) {
+            $scheme = strtolower($matches[1]); // Extract the scheme
+
+            // Special case: `mailto:` must contain a **valid email address**
+            if ($scheme === 'mailto') {
+                return preg_match($emailPattern, $matches[2]) === 1;
+            }
+
+            return true; // Valid non-hierarchical URI
+        }
+
+        return false;
+    }
+}
diff --git a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/AbstractRetriever.php b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/AbstractRetriever.php
index 9ab24b95f..f4ae718aa 100644
--- a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/AbstractRetriever.php
+++ b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/AbstractRetriever.php
@@ -1,4 +1,7 @@
 contentType = self::getContentTypeMatchInHeader($header)) {
                 return true;
             }
diff --git a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/PredefinedArray.php b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/PredefinedArray.php
index a663d3417..116930022 100644
--- a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/PredefinedArray.php
+++ b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Uri/Retrievers/PredefinedArray.php
@@ -1,5 +1,7 @@
  $match[2],
                 'authority' => $match[4],
                 'path'      => $match[5]
-            );
+            ];
         }
         if (7 < count($match)) {
             $components['query'] = $match[7];
@@ -125,25 +127,37 @@ public function resolve($uri, $baseUri = null)
     public static function combineRelativePathWithBasePath($relativePath, $basePath)
     {
         $relativePath = self::normalizePath($relativePath);
-        if ($relativePath == '') {
+        if (!$relativePath) {
             return $basePath;
         }
-        if ($relativePath[0] == '/') {
+        if ($relativePath[0] === '/') {
             return $relativePath;
         }
-
-        $basePathSegments = explode('/', $basePath);
-
-        preg_match('|^/?(\.\./(?:\./)*)*|', $relativePath, $match);
-        $numLevelUp = strlen($match[0]) /3 + 1;
-        if ($numLevelUp >= count($basePathSegments)) {
+        if (!$basePath) {
             throw new UriResolverException(sprintf("Unable to resolve URI '%s' from base '%s'", $relativePath, $basePath));
         }
 
-        $basePathSegments = array_slice($basePathSegments, 0, -$numLevelUp);
-        $path = preg_replace('|^/?(\.\./(\./)*)*|', '', $relativePath);
+        $dirname = $basePath[strlen($basePath) - 1] === '/' ? $basePath : dirname($basePath);
+        $combined = rtrim($dirname, '/') . '/' . ltrim($relativePath, '/');
+        $combinedSegments = explode('/', $combined);
+        $collapsedSegments = [];
+        while ($combinedSegments) {
+            $segment = array_shift($combinedSegments);
+            if ($segment === '..') {
+                if (count($collapsedSegments) <= 1) {
+                    // Do not remove the top level (domain)
+                    // This is not ideal - the domain should not be part of the path here. parse() and generate()
+                    // should handle the "domain" separately, like the schema.
+                    // Then the if-condition here would be `if (!$collapsedSegments) {`.
+                    throw new UriResolverException(sprintf("Unable to resolve URI '%s' from base '%s'", $relativePath, $basePath));
+                }
+                array_pop($collapsedSegments);
+            } else {
+                $collapsedSegments[] = $segment;
+            }
+        }
 
-        return implode('/', $basePathSegments) . '/' . $path;
+        return implode('/', $collapsedSegments);
     }
 
     /**
diff --git a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Uri/UriRetriever.php b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Uri/UriRetriever.php
index 41147a2a0..4094cccc3 100644
--- a/app/vendor/justinrainbow/json-schema/src/JsonSchema/Uri/UriRetriever.php
+++ b/app/vendor/justinrainbow/json-schema/src/JsonSchema/Uri/UriRetriever.php
@@ -1,5 +1,7 @@
  'package://dist/schema/json-schema-draft-$1.json'
-    );
+    ];
 
     /**
      * @var array A list of endpoints for media type check exclusion
      */
-    protected $allowedInvalidContentTypeEndpoints = array(
+    protected $allowedInvalidContentTypeEndpoints = [
         'http://json-schema.org/',
         'https://json-schema.org/'
-    );
+    ];
 
     /**
      * @var null|UriRetrieverInterface
@@ -50,7 +52,7 @@ class UriRetriever implements BaseUriRetrieverInterface
      *
      * @see loadSchema
      */
-    private $schemaCache = array();
+    private $schemaCache = [];
 
     /**
      * Adds an endpoint to the media type validation exclusion list
@@ -79,12 +81,12 @@ public function confirmMediaType($uriRetriever, $uri)
             return;
         }
 
-        if (in_array($contentType, array(Validator::SCHEMA_MEDIA_TYPE, 'application/json'))) {
+        if (in_array($contentType, [Validator::SCHEMA_MEDIA_TYPE, 'application/json'])) {
             return;
         }
 
         foreach ($this->allowedInvalidContentTypeEndpoints as $endpoint) {
-            if (strpos($uri, $endpoint) === 0) {
+            if (!\is_null($uri) && strpos($uri, $endpoint) === 0) {
                 return true;
             }
         }
@@ -243,13 +245,13 @@ public function parse($uri)
     {
         preg_match('|^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?|', $uri, $match);
 
-        $components = array();
+        $components = [];
         if (5 < count($match)) {
-            $components =  array(
+            $components =  [
                 'scheme'    => $match[2],
                 'authority' => $match[4],
                 'path'      => $match[5]
-            );
+            ];
         }
 
         if (7 < count($match)) {
diff --git a/app/vendor/justinrainbow/json-schema/src/JsonSchema/UriResolverInterface.php b/app/vendor/justinrainbow/json-schema/src/JsonSchema/UriResolverInterface.php
index 4eb50c03c..e80e2be73 100644
--- a/app/vendor/justinrainbow/json-schema/src/JsonSchema/UriResolverInterface.php
+++ b/app/vendor/justinrainbow/json-schema/src/JsonSchema/UriResolverInterface.php
@@ -1,5 +1,7 @@
  $checkMode
+     * @phpstan-return int-mask-of
      */
-    public function validate(&$value, $schema = null, $checkMode = null)
+    public function validate(&$value, $schema = null, ?int $checkMode = null): int
     {
-        // make sure $schema is an object
-        if (is_array($schema)) {
-            $schema = self::arrayToObjectRecursive($schema);
-        }
+        // reset errors prior to validation
+        $this->reset();
 
         // set checkMode
         $initialCheckMode = $this->factory->getConfig();
@@ -50,10 +57,9 @@ public function validate(&$value, $schema = null, $checkMode = null)
         }
 
         // add provided schema to SchemaStorage with internal URI to allow internal $ref resolution
-        if (is_object($schema) && property_exists($schema, 'id')) {
-            $schemaURI = $schema->id;
-        } else {
-            $schemaURI = SchemaStorage::INTERNAL_PROVIDED_SCHEMA_URI;
+        $schemaURI = SchemaStorage::INTERNAL_PROVIDED_SCHEMA_URI;
+        if (LooseTypeCheck::propertyExists($schema, 'id')) {
+            $schemaURI = LooseTypeCheck::propertyGet($schema, 'id');
         }
         $this->factory->getSchemaStorage()->addSchema($schemaURI, $schema);
 
@@ -72,16 +78,30 @@ public function validate(&$value, $schema = null, $checkMode = null)
 
     /**
      * Alias to validate(), to maintain backwards-compatibility with the previous API
+     *
+     * @deprecated since 6.0.0, use Validator::validate() instead, to be removed in 7.0
+     *
+     * @param mixed $value
+     * @param mixed $schema
+     *
+     * @phpstan-return int-mask-of
      */
-    public function check($value, $schema)
+    public function check($value, $schema): int
     {
         return $this->validate($value, $schema);
     }
 
     /**
      * Alias to validate(), to maintain backwards-compatibility with the previous API
+     *
+     * @deprecated since 6.0.0, use Validator::validate() instead, to be removed in 7.0
+     *
+     * @param mixed $value
+     * @param mixed $schema
+     *
+     * @phpstan-return int-mask-of
      */
-    public function coerce(&$value, $schema)
+    public function coerce(&$value, $schema): int
     {
         return $this->validate($value, $schema, Constraint::CHECK_MODE_COERCE_TYPES);
     }
diff --git a/app/vendor/laminas/laminas-httphandlerrunner/composer.json b/app/vendor/laminas/laminas-httphandlerrunner/composer.json
index a729714ff..7b0b68a1b 100644
--- a/app/vendor/laminas/laminas-httphandlerrunner/composer.json
+++ b/app/vendor/laminas/laminas-httphandlerrunner/composer.json
@@ -39,11 +39,11 @@
         "psr/http-server-handler": "^1.0"
     },
     "require-dev": {
-        "laminas/laminas-coding-standard": "~3.0.0",
-        "laminas/laminas-diactoros": "^3.4.0",
-        "phpunit/phpunit": "^10.5.36",
-        "psalm/plugin-phpunit": "^0.19.0",
-        "vimeo/psalm": "^5.26.1"
+        "laminas/laminas-coding-standard": "~3.1.0",
+        "laminas/laminas-diactoros": "^3.6.0",
+        "phpunit/phpunit": "^10.5.46",
+        "psalm/plugin-phpunit": "^0.19.5",
+        "vimeo/psalm": "^6.10.3"
     },
     "autoload": {
         "psr-4": {
diff --git a/app/vendor/laminas/laminas-httphandlerrunner/src/ConfigProvider.php b/app/vendor/laminas/laminas-httphandlerrunner/src/ConfigProvider.php
index 27ea8a7a5..3005af852 100644
--- a/app/vendor/laminas/laminas-httphandlerrunner/src/ConfigProvider.php
+++ b/app/vendor/laminas/laminas-httphandlerrunner/src/ConfigProvider.php
@@ -4,6 +4,7 @@
 
 namespace Laminas\HttpHandlerRunner;
 
+/** @final */
 class ConfigProvider
 {
     public function __invoke(): array
diff --git a/app/vendor/laminas/laminas-httphandlerrunner/src/Emitter/EmitterStack.php b/app/vendor/laminas/laminas-httphandlerrunner/src/Emitter/EmitterStack.php
index 486f4084d..e9e7c7a1e 100644
--- a/app/vendor/laminas/laminas-httphandlerrunner/src/Emitter/EmitterStack.php
+++ b/app/vendor/laminas/laminas-httphandlerrunner/src/Emitter/EmitterStack.php
@@ -18,6 +18,7 @@
  * true value will short-circuit iteration.
  *
  * @template-extends SplStack
+ * @final
  */
 class EmitterStack extends SplStack implements EmitterInterface
 {
diff --git a/app/vendor/laminas/laminas-httphandlerrunner/src/Emitter/SapiEmitter.php b/app/vendor/laminas/laminas-httphandlerrunner/src/Emitter/SapiEmitter.php
index eb9f11acd..49f6e8409 100644
--- a/app/vendor/laminas/laminas-httphandlerrunner/src/Emitter/SapiEmitter.php
+++ b/app/vendor/laminas/laminas-httphandlerrunner/src/Emitter/SapiEmitter.php
@@ -6,6 +6,7 @@
 
 use Psr\Http\Message\ResponseInterface;
 
+/** @final */
 class SapiEmitter implements EmitterInterface
 {
     use SapiEmitterTrait;
diff --git a/app/vendor/laminas/laminas-httphandlerrunner/src/Emitter/SapiStreamEmitter.php b/app/vendor/laminas/laminas-httphandlerrunner/src/Emitter/SapiStreamEmitter.php
index f58708ffb..06fcdc49c 100644
--- a/app/vendor/laminas/laminas-httphandlerrunner/src/Emitter/SapiStreamEmitter.php
+++ b/app/vendor/laminas/laminas-httphandlerrunner/src/Emitter/SapiStreamEmitter.php
@@ -13,6 +13,7 @@
 
 /**
  * @psalm-type ParsedRangeType = array{0:string,1:int,2:int,3:'*'|int}
+ * @final
  */
 class SapiStreamEmitter implements EmitterInterface
 {
diff --git a/app/vendor/laminas/laminas-httphandlerrunner/src/Exception/EmitterException.php b/app/vendor/laminas/laminas-httphandlerrunner/src/Exception/EmitterException.php
index 79a2f277a..bff408dd1 100644
--- a/app/vendor/laminas/laminas-httphandlerrunner/src/Exception/EmitterException.php
+++ b/app/vendor/laminas/laminas-httphandlerrunner/src/Exception/EmitterException.php
@@ -8,6 +8,7 @@
 
 use function sprintf;
 
+/** @final */
 class EmitterException extends RuntimeException implements ExceptionInterface
 {
     public static function forHeadersSent(string $filename, int $line): self
diff --git a/app/vendor/laminas/laminas-httphandlerrunner/src/Exception/ExceptionInterface.php b/app/vendor/laminas/laminas-httphandlerrunner/src/Exception/ExceptionInterface.php
index 9987d8c41..fe2b158aa 100644
--- a/app/vendor/laminas/laminas-httphandlerrunner/src/Exception/ExceptionInterface.php
+++ b/app/vendor/laminas/laminas-httphandlerrunner/src/Exception/ExceptionInterface.php
@@ -4,9 +4,11 @@
 
 namespace Laminas\HttpHandlerRunner\Exception;
 
+use Throwable;
+
 /**
  * Marker interface for package exceptions.
  */
-interface ExceptionInterface
+interface ExceptionInterface extends Throwable
 {
 }
diff --git a/app/vendor/laminas/laminas-httphandlerrunner/src/Exception/InvalidEmitterException.php b/app/vendor/laminas/laminas-httphandlerrunner/src/Exception/InvalidEmitterException.php
index 7944c03c6..f03ef78b4 100644
--- a/app/vendor/laminas/laminas-httphandlerrunner/src/Exception/InvalidEmitterException.php
+++ b/app/vendor/laminas/laminas-httphandlerrunner/src/Exception/InvalidEmitterException.php
@@ -10,6 +10,7 @@
 use function get_debug_type;
 use function sprintf;
 
+/** @final */
 class InvalidEmitterException extends InvalidArgumentException implements ExceptionInterface
 {
     /**
diff --git a/app/vendor/laminas/laminas-httphandlerrunner/src/RequestHandlerRunner.php b/app/vendor/laminas/laminas-httphandlerrunner/src/RequestHandlerRunner.php
index 0c2e63cee..0656ed181 100644
--- a/app/vendor/laminas/laminas-httphandlerrunner/src/RequestHandlerRunner.php
+++ b/app/vendor/laminas/laminas-httphandlerrunner/src/RequestHandlerRunner.php
@@ -51,8 +51,8 @@ public function __construct(
         /**
          * A request handler to run as the application.
          */
-        private RequestHandlerInterface $handler,
-        private EmitterInterface $emitter,
+        private readonly RequestHandlerInterface $handler,
+        private readonly EmitterInterface $emitter,
         callable $serverRequestFactory,
         callable $serverRequestErrorResponseGenerator
     ) {
diff --git a/app/vendor/league/container/CHANGELOG.md b/app/vendor/league/container/CHANGELOG.md
index 2362089c2..1496300a0 100644
--- a/app/vendor/league/container/CHANGELOG.md
+++ b/app/vendor/league/container/CHANGELOG.md
@@ -2,6 +2,27 @@
 
 All Notable changes to `League\Container` will be documented in this file
 
+## 4.2.5
+
+### Fixed
+- Restored ability to perform recursive definition search. (@spider-mane)
+
+## 4.2.4
+
+### Fixed
+- Now properly handle string based fully qualified class names in with preceding slashes. (@M1ke)
+
+## 4.2.3
+
+### Fixed
+- Warnings for PHP 8.4 implicit nullable types (@andypost)
+
+## 4.2.1
+
+### Fixed
+- Remove an unnecessary conditional in ServiceProviderAggregate. (@SubhanSh)
+- Fixed an infinite loop in resolving definitions. (@arai-ta)
+
 ## 4.2.0
 
 ### Added
@@ -111,7 +132,7 @@ All Notable changes to `League\Container` will be documented in this file
 
 ### Added
 - Re-added the `share` proxy method that was mistakenly removed in previous major release.
-- Added ability to set Conatiner to "share" by default using `defaultToShared` method.
+- Added ability to set Container to "share" by default using `defaultToShared` method.
 - Added ability for `ReflectionContainer` to cache resolutions and pull from cache for following calls.
 
 ## 3.0.1
@@ -259,4 +280,4 @@ All Notable changes to `League\Container` will be documented in this file
 ## 1.0.0 - 2015-01-12
 
 ### Added
-- Migrated from [Orno\Di](https://github.com/orno/di).
+- Migrated from [Orno\Di](https://github.com/orno/di).
\ No newline at end of file
diff --git a/app/vendor/league/container/CONTRIBUTING.md b/app/vendor/league/container/CONTRIBUTING.md
index 0c45c52dd..d62f88db5 100644
--- a/app/vendor/league/container/CONTRIBUTING.md
+++ b/app/vendor/league/container/CONTRIBUTING.md
@@ -2,7 +2,7 @@
 
 Contributions are **welcome** and will be fully **credited**.
 
-We accept contributions via Pull Requests on [Github](https://github.com/thephpleague/container).
+We accept contributions via Pull Requests on [GitHub](https://github.com/thephpleague/container).
 
 ## Pull Requests
 
diff --git a/app/vendor/league/container/README.md b/app/vendor/league/container/README.md
index 48aa39361..69c786cb5 100644
--- a/app/vendor/league/container/README.md
+++ b/app/vendor/league/container/README.md
@@ -1,27 +1,28 @@
 # Container (Dependency Injection)
 
-[![Author](http://img.shields.io/badge/author-@philipobenito-blue.svg?style=flat-square)](https://twitter.com/philipobenito)
+[![Author](https://img.shields.io/badge/author-Phil%20Bennett-blue?style=flat-square)](https://github.com/philipobenito)
 [![Latest Version](https://img.shields.io/github/release/thephpleague/container.svg?style=flat-square)](https://github.com/thephpleague/container/releases)
 [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md)
-[![Build Status](https://img.shields.io/travis/thephpleague/container/master.svg?style=flat-square)](https://travis-ci.org/thephpleague/container)
+[![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/thephpleague/container/test.yml?style=flat-square)](https://github.com/thephpleague/container/actions/workflows/test.yml)
 [![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/thephpleague/container.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/container/code-structure)
 [![Quality Score](https://img.shields.io/scrutinizer/g/thephpleague/container.svg?style=flat-square)](https://scrutinizer-ci.com/g/thephpleague/container)
 [![Total Downloads](https://img.shields.io/packagist/dt/league/container.svg?style=flat-square)](https://packagist.org/packages/league/container)
 
-This package is compliant with [PSR-1], [PSR-2], [PSR-12], [PSR-4] and [PSR-11]. If you notice compliance oversights, please send a patch via pull request.
+This package is compliant with [PSR-1], [PSR-2], [PSR-12], [PSR-4], [PSR-11] and [PSR-12]. If you notice compliance oversights, please send a patch via pull request.
 
 [PSR-1]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md
 [PSR-2]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md
 [PSR-12]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-12-extended-coding-style-guide.md
 [PSR-4]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md
 [PSR-11]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-11-container.md
+[PSR-12]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-12-extended-coding-style-guide.md
 
 ## Install
 
 Via Composer
 
 ``` bash
-$ composer require league/container
+composer require league/container
 ```
 
 ## Requirements
@@ -31,6 +32,11 @@ The following versions of PHP are supported by this version.
 * PHP 7.2
 * PHP 7.3
 * PHP 7.4
+* PHP 8.0
+* PHP 8.1
+* PHP 8.2
+* PHP 8.3
+* PHP 8.4
 
 ## Documentation
 
diff --git a/app/vendor/league/container/src/Argument/LiteralArgument.php b/app/vendor/league/container/src/Argument/LiteralArgument.php
index c121d35fd..55adede70 100644
--- a/app/vendor/league/container/src/Argument/LiteralArgument.php
+++ b/app/vendor/league/container/src/Argument/LiteralArgument.php
@@ -24,7 +24,7 @@ class LiteralArgument implements LiteralArgumentInterface
      */
     protected $value;
 
-    public function __construct($value, string $type = null)
+    public function __construct($value, ?string $type = null)
     {
         if (
             null === $type
diff --git a/app/vendor/league/container/src/Container.php b/app/vendor/league/container/src/Container.php
index 259fdbbf1..195dba7c0 100644
--- a/app/vendor/league/container/src/Container.php
+++ b/app/vendor/league/container/src/Container.php
@@ -40,9 +40,9 @@ class Container implements DefinitionContainerInterface
     protected $delegates = [];
 
     public function __construct(
-        DefinitionAggregateInterface $definitions = null,
-        ServiceProviderAggregateInterface $providers = null,
-        InflectorAggregateInterface $inflectors = null
+        ?DefinitionAggregateInterface $definitions = null,
+        ?ServiceProviderAggregateInterface $providers = null,
+        ?InflectorAggregateInterface $inflectors = null
     ) {
         $this->definitions = $definitions ?? new DefinitionAggregate();
         $this->providers   = $providers   ?? new ServiceProviderAggregate();
@@ -106,11 +106,25 @@ public function addServiceProvider(ServiceProviderInterface $provider): Definiti
         return $this;
     }
 
+    /**
+     * @template RequestedType
+     *
+     * @param class-string|string $id
+     *
+     * @return RequestedType|mixed
+     */
     public function get($id)
     {
         return $this->resolve($id);
     }
 
+    /**
+     * @template RequestedType
+     *
+     * @param class-string|string $id
+     *
+     * @return RequestedType|mixed
+     */
     public function getNew($id)
     {
         return $this->resolve($id, true);
@@ -139,7 +153,7 @@ public function has($id): bool
         return false;
     }
 
-    public function inflector(string $type, callable $callback = null): InflectorInterface
+    public function inflector(string $type, ?callable $callback = null): InflectorInterface
     {
         return $this->inflectors->add($type, $callback);
     }
diff --git a/app/vendor/league/container/src/Definition/Definition.php b/app/vendor/league/container/src/Definition/Definition.php
index 8ff440d1f..0d4b2f21a 100644
--- a/app/vendor/league/container/src/Definition/Definition.php
+++ b/app/vendor/league/container/src/Definition/Definition.php
@@ -61,6 +61,8 @@ class Definition implements ArgumentResolverInterface, DefinitionInterface
      */
     public function __construct(string $id, $concrete = null)
     {
+        $id = static::normaliseAlias($id);
+
         $concrete = $concrete ?? $id;
         $this->alias    = $id;
         $this->concrete = $concrete;
@@ -79,6 +81,8 @@ public function hasTag(string $tag): bool
 
     public function setAlias(string $id): DefinitionInterface
     {
+        $id = static::normaliseAlias($id);
+
         $this->alias = $id;
         return $this;
     }
@@ -171,8 +175,12 @@ public function resolveNew()
             $concrete = $concrete->getValue();
         }
 
-        if (is_string($concrete) && class_exists($concrete)) {
-            $concrete = $this->resolveClass($concrete);
+        if (is_string($concrete)) {
+            if (class_exists($concrete)) {
+                $concrete = $this->resolveClass($concrete);
+            } elseif ($this->getAlias() === $concrete) {
+                return $concrete;
+            }
         }
 
         if (is_object($concrete)) {
@@ -222,4 +230,13 @@ protected function invokeMethods(object $instance): object
 
         return $instance;
     }
+
+    public static function normaliseAlias(string $alias): string
+    {
+        if (strpos($alias, '\\') === 0) {
+            return substr($alias, 1);
+        }
+
+        return $alias;
+    }
 }
diff --git a/app/vendor/league/container/src/Definition/DefinitionAggregate.php b/app/vendor/league/container/src/Definition/DefinitionAggregate.php
index cddb82f15..d3413545a 100644
--- a/app/vendor/league/container/src/Definition/DefinitionAggregate.php
+++ b/app/vendor/league/container/src/Definition/DefinitionAggregate.php
@@ -43,6 +43,8 @@ public function addShared(string $id, $definition): DefinitionInterface
 
     public function has(string $id): bool
     {
+        $id = Definition::normaliseAlias($id);
+
         foreach ($this->getIterator() as $definition) {
             if ($id === $definition->getAlias()) {
                 return true;
@@ -65,6 +67,8 @@ public function hasTag(string $tag): bool
 
     public function getDefinition(string $id): DefinitionInterface
     {
+        $id = Definition::normaliseAlias($id);
+
         foreach ($this->getIterator() as $definition) {
             if ($id === $definition->getAlias()) {
                 return $definition->setContainer($this->getContainer());
diff --git a/app/vendor/league/container/src/DefinitionContainerInterface.php b/app/vendor/league/container/src/DefinitionContainerInterface.php
index 7e7e57e36..d7d53381f 100644
--- a/app/vendor/league/container/src/DefinitionContainerInterface.php
+++ b/app/vendor/league/container/src/DefinitionContainerInterface.php
@@ -16,5 +16,5 @@ public function addServiceProvider(ServiceProviderInterface $provider): self;
     public function addShared(string $id, $concrete = null): DefinitionInterface;
     public function extend(string $id): DefinitionInterface;
     public function getNew($id);
-    public function inflector(string $type, callable $callback = null): InflectorInterface;
+    public function inflector(string $type, ?callable $callback = null): InflectorInterface;
 }
diff --git a/app/vendor/league/container/src/Inflector/Inflector.php b/app/vendor/league/container/src/Inflector/Inflector.php
index b8f067558..e0809cd25 100644
--- a/app/vendor/league/container/src/Inflector/Inflector.php
+++ b/app/vendor/league/container/src/Inflector/Inflector.php
@@ -33,7 +33,7 @@ class Inflector implements ArgumentResolverInterface, InflectorInterface
      */
     protected $properties = [];
 
-    public function __construct(string $type, callable $callback = null)
+    public function __construct(string $type, ?callable $callback = null)
     {
         $this->type = $type;
         $this->callback = $callback;
diff --git a/app/vendor/league/container/src/Inflector/InflectorAggregate.php b/app/vendor/league/container/src/Inflector/InflectorAggregate.php
index c7193322c..70922d497 100644
--- a/app/vendor/league/container/src/Inflector/InflectorAggregate.php
+++ b/app/vendor/league/container/src/Inflector/InflectorAggregate.php
@@ -16,7 +16,7 @@ class InflectorAggregate implements InflectorAggregateInterface
      */
     protected $inflectors = [];
 
-    public function add(string $type, callable $callback = null): Inflector
+    public function add(string $type, ?callable $callback = null): Inflector
     {
         $inflector = new Inflector($type, $callback);
         $this->inflectors[] = $inflector;
diff --git a/app/vendor/league/container/src/Inflector/InflectorAggregateInterface.php b/app/vendor/league/container/src/Inflector/InflectorAggregateInterface.php
index 474276b3a..c95ac1723 100644
--- a/app/vendor/league/container/src/Inflector/InflectorAggregateInterface.php
+++ b/app/vendor/league/container/src/Inflector/InflectorAggregateInterface.php
@@ -9,6 +9,6 @@
 
 interface InflectorAggregateInterface extends ContainerAwareInterface, IteratorAggregate
 {
-    public function add(string $type, callable $callback = null): Inflector;
+    public function add(string $type, ?callable $callback = null): Inflector;
     public function inflect(object $object);
 }
diff --git a/app/vendor/league/container/src/ServiceProvider/ServiceProviderAggregate.php b/app/vendor/league/container/src/ServiceProvider/ServiceProviderAggregate.php
index 3bc0861b7..a790b3f51 100644
--- a/app/vendor/league/container/src/ServiceProvider/ServiceProviderAggregate.php
+++ b/app/vendor/league/container/src/ServiceProvider/ServiceProviderAggregate.php
@@ -28,9 +28,7 @@ public function add(ServiceProviderInterface $provider): ServiceProviderAggregat
             return $this;
         }
 
-        if ($provider instanceof ContainerAwareInterface) {
-            $provider->setContainer($this->getContainer());
-        }
+        $provider->setContainer($this->getContainer());
 
         if ($provider instanceof BootableServiceProviderInterface) {
             $provider->boot();
diff --git a/app/vendor/marc-mabe/php-enum/LICENSE.txt b/app/vendor/marc-mabe/php-enum/LICENSE.txt
new file mode 100644
index 000000000..02bcecec7
--- /dev/null
+++ b/app/vendor/marc-mabe/php-enum/LICENSE.txt
@@ -0,0 +1,27 @@
+Copyright (c) 2020, Marc Bennewitz
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright notice,
+      this list of conditions and the following disclaimer.
+    
+    * Redistributions in binary form must reproduce the above copyright notice,
+      this list of conditions and the following disclaimer in the documentation
+      and/or other materials provided with the distribution.
+    
+    * Neither the name of the organisation nor the names of its contributors
+      may be used to endorse or promote products derived from this software
+      without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/app/vendor/marc-mabe/php-enum/README.md b/app/vendor/marc-mabe/php-enum/README.md
new file mode 100644
index 000000000..37ef675ef
--- /dev/null
+++ b/app/vendor/marc-mabe/php-enum/README.md
@@ -0,0 +1,479 @@
+# php-enum
+[![Build Status](https://github.com/marc-mabe/php-enum/workflows/Test/badge.svg?branch=master)](https://github.com/marc-mabe/php-enum/actions?query=workflow%3ATest%20branch%3Amaster)
+[![Code Coverage](https://codecov.io/github/marc-mabe/php-enum/coverage.svg?branch=master)](https://codecov.io/gh/marc-mabe/php-enum/branch/master/)
+[![License](https://poser.pugx.org/marc-mabe/php-enum/license)](https://github.com/marc-mabe/php-enum/blob/master/LICENSE.txt)
+[![Latest Stable](https://poser.pugx.org/marc-mabe/php-enum/v/stable.png)](https://packagist.org/packages/marc-mabe/php-enum)
+[![Total Downloads](https://poser.pugx.org/marc-mabe/php-enum/downloads.png)](https://packagist.org/packages/marc-mabe/php-enum)
+[![Monthly Downloads](https://poser.pugx.org/marc-mabe/php-enum/d/monthly)](https://packagist.org/packages/marc-mabe/php-enum)
+[![Dependents](https://poser.pugx.org/marc-mabe/php-enum/dependents)](https://packagist.org/packages/marc-mabe/php-enum/dependents?order_by=downloads)
+
+This is a native PHP implementation to add enumeration support to PHP.
+It's an abstract class that needs to be extended to use it.
+
+
+# What is an Enumeration?
+
+[Wikipedia](http://wikipedia.org/wiki/Enumerated_type)
+> In computer programming, an enumerated type (also called enumeration or enum)
+> is a data type consisting of a set of named values called elements, members
+> or enumerators of the type. The enumerator names are usually identifiers that
+> behave as constants in the language. A variable that has been declared as
+> having an enumerated type can be assigned any of the enumerators as a value.
+> In other words, an enumerated type has values that are different from each
+> other, and that can be compared and assigned, but which do not have any
+> particular concrete representation in the computer's memory; compilers and
+> interpreters can represent them arbitrarily.
+
+
+# Usage
+
+## Basics
+
+```php
+use MabeEnum\Enum;
+
+// define an own enumeration class
+class UserStatus extends Enum
+{
+    const INACTIVE = 'i';
+    const ACTIVE   = 'a';
+    const DELETED  = 'd';
+
+    // all scalar data types and arrays are supported as enumerator values
+    const NIL     = null;
+    const BOOLEAN = true;
+    const INT     = 1234;
+    const STR     = 'string';
+    const FLOAT   = 0.123;
+    const ARR     = ['this', 'is', ['an', 'array']];
+
+    // Enumerators will be generated from public constants only
+    public    const PUBLIC_CONST    = 'public constant';    // this will be an enumerator
+    protected const PROTECTED_CONST = 'protected constant'; // this will NOT be an enumerator
+    private   const PRIVATE_CONST   = 'private constant';   // this will NOT be an enumerator
+
+    // works since PHP-7.0 - see https://wiki.php.net/rfc/context_sensitive_lexer
+    const TRUE      = 'true';
+    const FALSE     = 'false';
+    const NULL      = 'null';
+    const PUBLIC    = 'public';
+    const PRIVATE   = 'private';
+    const PROTECTED = 'protected';
+    const FUNCTION  = 'function';
+    const TRAIT     = 'trait';
+    const INTERFACE = 'interface';
+
+    // Doesn't work - see https://wiki.php.net/rfc/class_name_scalars
+    // const CLASS = 'class';
+}
+
+// ways to instantiate an enumerator
+$status = UserStatus::get(UserStatus::ACTIVE); // by value or instance
+$status = UserStatus::ACTIVE();                // by name as callable
+$status = UserStatus::byValue('a');            // by value
+$status = UserStatus::byName('ACTIVE');        // by name
+$status = UserStatus::byOrdinal(1);            // by ordinal number
+
+// basic methods of an instantiated enumerator
+$status->getValue();   // returns the selected constant value
+$status->getName();    // returns the selected constant name
+$status->getOrdinal(); // returns the ordinal number of the selected constant
+
+// basic methods to list defined enumerators
+UserStatus::getEnumerators();  // returns a list of enumerator instances
+UserStatus::getValues();       // returns a list of enumerator values
+UserStatus::getNames();        // returns a list of enumerator names
+UserStatus::getOrdinals();     // returns a list of ordinal numbers
+UserStatus::getConstants();    // returns an associative array of enumerator names to enumerator values
+
+// same enumerators (of the same enumeration class) holds the same instance
+UserStatus::get(UserStatus::ACTIVE) === UserStatus::ACTIVE()
+UserStatus::get(UserStatus::DELETED) != UserStatus::INACTIVE()
+
+// simplified way to compare two enumerators
+$status = UserStatus::ACTIVE();
+$status->is(UserStatus::ACTIVE);     // true
+$status->is(UserStatus::ACTIVE());   // true
+$status->is(UserStatus::DELETED);    // false
+$status->is(UserStatus::DELETED());  // false
+```
+
+## Type-Hint
+
+```php
+use MabeEnum\Enum;
+
+class User
+{
+    protected $status;
+
+    public function setStatus(UserStatus $status)
+    {
+        $this->status = $status;
+    }
+
+    public function getStatus()
+    {
+        if (!$this->status) {
+            // initialize default
+            $this->status = UserStatus::INACTIVE();
+        }
+        return $this->status;
+    }
+}
+```
+
+### Type-Hint issue
+
+Because in normal OOP the above example allows `UserStatus` and types inherited from it.
+
+Please think about the following example:
+
+```php
+class ExtendedUserStatus extends UserStatus
+{
+    const EXTENDED = 'extended';
+}
+
+$user = new User();
+$user->setStatus(ExtendedUserStatus::EXTENDED());
+```
+
+Now the setter receives a status it doesn't know about but allows it.
+
+#### Solution 1: Finalize the enumeration
+
+```php
+final class UserStatus extends Enum
+{
+    // ...
+}
+
+class User
+{
+    protected $status;
+
+    public function setStatus(UserStatus $status)
+    {
+        $this->status = $status;
+    }
+}
+````
+
+* Nice and obvious solution
+
+* Resulting behaviour matches native enumeration implementation of most other languages (like Java)
+
+But as this library emulates enumerations it has a few downsides:
+
+* Enumerator values can not be used directly
+  * `$user->setStatus(UserStatus::ACTIVE)` fails
+  * `$user->setStatus(UserStatus::ACTIVE())` works
+
+* Does not help if the enumeration was defined in an external library
+
+
+#### Solution 2: Using `Enum::get()`
+
+```php
+class User
+{
+    public function setStatus($status)
+    {
+        $this->status = UserStatus::get($status);
+    }
+}
+```
+
+* Makes sure the resulting enumerator exactly matches an enumeration. (Inherited enumerators are not allowed).
+
+* Allows enumerator values directly
+  * `$user->setStatus(UserStatus::ACTIVE)` works
+  * `$user->setStatus(UserStatus::ACTIVE())` works
+
+* Also works for enumerations defined in external libraries
+
+But of course this solution has downsides, too:
+
+* Looses declarative type-hint
+
+* A bit slower
+
+
+## EnumSet
+
+An `EnumSet` is a specialized Set implementation for use with enumeration types.
+All of the enumerators in an `EnumSet` must come from a single enumeration type that is specified, when the set is
+created.
+
+Enum sets are represented internally as bit vectors. The bit vector is either an integer type or a binary string type
+depending on how many enumerators are defined in the enumeration type. This representation is extremely compact and
+efficient. Bulk operations will run very quickly. Enumerators of an `EnumSet` are unique and ordered based on its
+ordinal number by design.
+
+It implements `IteratorAggregate` and `Countable` to be directly iterable with `foreach` and countable with `count()`.
+
+The `EnumSet` has a mutable and an immutable interface.
+Mutable methods start with `set`, `add` or `remove` while immutable methods start with `with`.
+
+```php
+use MabeEnum\EnumSet;
+
+// create a new EnumSet and initialize with the given enumerators
+$enumSet = new EnumSet('UserStatus', [UserStatus::ACTIVE()]);
+
+// modify an EnumSet (mutable interface)
+
+// add enumerators (by value or by instance)
+$enumSet->addIterable([UserStatus::INACTIVE, UserStatus::DELETED()]);
+// or
+$enumSet->add(UserStatus::INACTIVE);
+$enumSet->add(UserStatus::DELETED());
+
+// remove enumerators (by value or by instance)
+$enumSet->removeIterable([UserStatus::INACTIVE, UserStatus::DELETED()]);
+// or
+$enumSet->remove(UserStatus::INACTIVE);
+$enumSet->remove(UserStatus::DELETED());
+
+
+// The immutable interface will create a new EnumSet for each modification 
+
+// add enumerators (by value or by instance)
+$enumSet = $enumSet->withIterable([UserStatus::INACTIVE, UserStatus::DELETED()]);
+// or
+$enumSet = $enumSet->with(UserStatus::INACTIVE);
+$enumSet = $enumSet->with(UserStatus::DELETED());
+
+// remove enumerators (by value or by instance)
+$enumSet->withoutIterable([UserStatus::INACTIVE, UserStatus::DELETED()]);
+// or
+$enumSet = $enumSet->without(UserStatus::INACTIVE);
+$enumSet = $enumSet->without(UserStatus::DELETED());
+
+
+// Test if an enumerator exists (by value or by instance)
+$enumSet->has(UserStatus::INACTIVE); // bool
+
+
+// count the number of enumerators
+$enumSet->count();
+count($enumSet);
+
+// test for elements
+$enumSet->isEmpty();
+
+// convert to array
+$enumSet->getValues();      // List of enumerator values
+$enumSet->getEnumerators(); // List of enumerator instances
+$enumSet->getNames();       // List of enumerator names
+$enumSet->getOrdinals();    // List of ordinal numbers
+
+
+// iterating over the set
+foreach ($enumSet as $ordinal => $enum) {
+    gettype($ordinal);  // int (the ordinal number of the enumerator)
+    get_class($enum);   // UserStatus (enumerator object)
+}
+
+
+// compare two EnumSets
+$enumSet->isEqual($other);    // Check if the EnumSet is the same as other
+$enumSet->isSubset($other);   // Check if the EnumSet is a subset of other
+$enumSet->isSuperset($other); // Check if the EnumSet is a superset of other
+
+
+// union, intersect, difference and symmetric difference
+
+// ... the mutable interface will modify the set
+$enumSet->setUnion($other);     // Enumerators from both this and other (this | other)
+$enumSet->setIntersect($other); // Enumerators common to both this and other (this & other)
+$enumSet->setDiff($other);      // Enumerators in this but not in other (this - other)
+$enumSet->setSymDiff($other);   // Enumerators in either this and other but not in both (this ^ other)
+
+// ... the immutable interface will produce a new set
+$enumSet = $enumSet->withUnion($other);     // Enumerators from both this and other (this | other)
+$enumSet = $enumSet->withIntersect($other); // Enumerators common to both this and other (this & other)
+$enumSet = $enumSet->withDiff($other);      // Enumerators in this but not in other (this - other)
+$enumSet = $enumSet->withSymDiff($other);   // Enumerators in either this and other but not in both (this ^ other)
+```
+
+
+## EnumMap
+
+An `EnumMap` maps enumerators of the same type to data assigned to.
+
+It implements `ArrayAccess`, `Countable` and `IteratorAggregate`
+so elements can be accessed, iterated and counted like a normal array
+using `$enumMap[$key]`, `foreach` and `count()`.
+
+```php
+use MabeEnum\EnumMap;
+
+// create a new EnumMap
+$enumMap = new EnumMap('UserStatus');
+
+
+// read and write key-value-pairs like an array
+$enumMap[UserStatus::INACTIVE] = 'inaktiv';
+$enumMap[UserStatus::ACTIVE]   = 'aktiv';
+$enumMap[UserStatus::DELETED]  = 'gelöscht';
+$enumMap[UserStatus::INACTIVE]; // 'inaktiv';
+$enumMap[UserStatus::ACTIVE];   // 'aktiv';
+$enumMap[UserStatus::DELETED];  // 'gelöscht';
+
+isset($enumMap[UserStatus::DELETED]); // true
+unset($enumMap[UserStatus::DELETED]);
+isset($enumMap[UserStatus::DELETED]); // false
+
+// ... no matter if you use enumerator values or enumerator objects
+$enumMap[UserStatus::INACTIVE()] = 'inaktiv';
+$enumMap[UserStatus::ACTIVE()]   = 'aktiv';
+$enumMap[UserStatus::DELETED()]  = 'gelöscht';
+$enumMap[UserStatus::INACTIVE()]; // 'inaktiv';
+$enumMap[UserStatus::ACTIVE()];   // 'aktiv';
+$enumMap[UserStatus::DELETED()];  // 'gelöscht';
+
+isset($enumMap[UserStatus::DELETED()]); // true
+unset($enumMap[UserStatus::DELETED()]);
+isset($enumMap[UserStatus::DELETED()]); // false
+
+
+// count number of attached elements
+$enumMap->count();
+count($enumMap);
+
+// test for elements
+$enumMap->isEmpty();
+
+// support for null aware exists check
+$enumMap[UserStatus::NULL] = null;
+isset($enumMap[UserStatus::NULL]); // false
+$enumMap->has(UserStatus::NULL);   // true
+
+
+// iterating over the map
+foreach ($enumMap as $enum => $value) {
+    get_class($enum);  // UserStatus (enumerator object)
+    gettype($value);   // mixed (the value the enumerators maps to)
+}
+
+// get a list of keys (= a list of enumerator objects)
+$enumMap->getKeys();
+
+// get a list of values (= a list of values the enumerator maps to)
+$enumMap->getValues();
+```
+
+
+## Serializing
+
+Because this enumeration implementation is based on a singleton pattern and in PHP
+it's currently impossible to unserialize a singleton without creating a new instance
+this feature isn't supported without any additional work.
+
+As of it's an often requested feature there is a trait that can be added to your
+enumeration definition. The trait adds serialization functionallity and injects
+the unserialized enumeration instance in case it's the first one.
+This reduces singleton behavior breakage but still it beaks if it's not the first
+instance and you could result in two different instance of the same enumeration.
+
+**Use it with caution!**
+
+PS: `EnumSet` and `EnumMap` are serializable by default as long as you don't set other non-serializable values.
+
+
+### Example of using EnumSerializableTrait
+
+```php
+use MabeEnum\Enum;
+use MabeEnum\EnumSerializableTrait;
+use Serializable;
+
+class CardinalDirection extends Enum implements Serializable
+{
+    use EnumSerializableTrait;
+
+    const NORTH = 'n';
+    const EAST  = 'e';
+    const WEST  = 'w';
+    const SOUTH = 's';
+}
+
+$north1 = CardinalDirection::NORTH();
+$north2 = unserialize(serialize($north1));
+
+var_dump($north1 === $north2);  // returns FALSE as described above
+var_dump($north1->is($north2)); // returns TRUE - this way the two instances are treated equal
+var_dump($north2->is($north1)); // returns TRUE - equality works in both directions
+```
+
+
+# Generics and Static Code Analyzer
+
+With version 4.3 we have added support for generics and added better type support.
+
+* `EnumSet`
+* `EnumMap`
+
+Generic types will be detected by [PHPStan](https://phpstan.org/) and [Psalm](https://psalm.dev/).
+
+Additionally, we have developed an [extension for PHPStan](https://github.com/marc-mabe/php-enum-phpstan/)
+to make enumerator accessor methods known.
+
+
+# Why not `SplEnum`
+
+* `SplEnum` is not built-in into PHP and requires pecl extension installed.
+* Instances of the same value of an `SplEnum` are not the same instance.
+* No support for `EnumMap` or `EnumSet`.
+
+
+# Changelog
+
+Changes are documented in the [release page](https://github.com/marc-mabe/php-enum/releases).
+
+
+# Install
+
+## Composer
+
+Add `marc-mabe/php-enum` to the project's composer.json dependencies and run
+`php composer.phar install`
+
+## GIT
+
+`git clone git://github.com/marc-mabe/php-enum.git`
+
+## ZIP / TAR
+
+Download the last version from [Github](https://github.com/marc-mabe/php-enum/tags)
+and extract it.
+
+
+# Versioning and Releases
+
+This project follows [SemVer](https://semver.org/) specification. 
+
+There are **no** [LTS](https://en.wikipedia.org/wiki/Long-term_support) releases
+and we don't have (fixed) time based release windows.
+Instead releases happen as necessary.
+
+We do support at least all maintained PHP versions.
+
+Bug fixes will be backported to the latest maintained minor release.
+
+Critical bug fixes and security relates fixes can also be backported to older releases.
+
+| Release | Status      | PHP-Version     |
+|---------|-------------|-----------------|
+| 1.x     | EOL         | \>=5.3          |
+| 2.x     | EOL         | \>=5.3 & HHVM<4 |
+| 3.x     | EOL         | \>=5.6 & HHVM<4 |
+| 4.x     | active      | \>=7.1          |
+
+
+# New BSD License
+
+The files in this archive are released under the New BSD License.
+You can find a copy of this license in LICENSE.txt file.
diff --git a/app/vendor/marc-mabe/php-enum/composer.json b/app/vendor/marc-mabe/php-enum/composer.json
new file mode 100644
index 000000000..b6dfe92d3
--- /dev/null
+++ b/app/vendor/marc-mabe/php-enum/composer.json
@@ -0,0 +1,50 @@
+{
+    "name": "marc-mabe/php-enum",
+    "description": "Simple and fast implementation of enumerations with native PHP",
+    "type": "library",
+    "keywords": [
+        "enum", "enumeration", "enumerator",
+        "enumset", "enum-set", "set",
+        "enummap", "enum-map", "map",
+        "type", "typehint", "type-hint"
+    ],
+    "homepage": "https://github.com/marc-mabe/php-enum",
+    "authors": [{
+        "name":     "Marc Bennewitz",
+        "email":    "dev@mabe.berlin",
+        "homepage": "https://mabe.berlin/",
+        "role":     "Lead"
+    }],
+    "license": "BSD-3-Clause",
+    "require": {
+        "php":            "^7.1 | ^8.0",
+        "ext-reflection": "*"
+    },
+    "require-dev": {
+        "phpbench/phpbench": "^0.16.10 || ^1.0.4",
+        "phpstan/phpstan": "^1.3.1",
+        "phpunit/phpunit": "^7.5.20 | ^8.5.22 | ^9.5.11",
+        "vimeo/psalm": "^4.17.0 | ^5.26.1"
+    },
+    "autoload": {
+        "psr-4": {
+            "MabeEnum\\": "src/"
+        },
+        "classmap": [
+            "stubs/Stringable.php"
+        ]
+    },
+    "autoload-dev": {
+        "psr-4": {
+            "MabeEnumTest\\":  "tests/MabeEnumTest/",
+            "MabeEnumStaticAnalysis\\": "tests/MabeEnumStaticAnalysis/",
+            "MabeEnumBench\\": "bench/"
+        }
+    },
+    "extra": {
+        "branch-alias": {
+            "dev-master": "4.7-dev",
+            "dev-3.x":    "3.2-dev"
+        }
+    }
+}
diff --git a/app/vendor/marc-mabe/php-enum/src/Enum.php b/app/vendor/marc-mabe/php-enum/src/Enum.php
new file mode 100644
index 000000000..d602d8bc6
--- /dev/null
+++ b/app/vendor/marc-mabe/php-enum/src/Enum.php
@@ -0,0 +1,484 @@
+
+     */
+    private $value;
+
+    /**
+     * The ordinal number of the enumerator
+     *
+     * @var null|int
+     */
+    private $ordinal;
+
+    /**
+     * A map of enumerator names and values by enumeration class
+     *
+     * @var array, array>>
+     */
+    private static $constants = [];
+
+    /**
+     * A List of available enumerator names by enumeration class
+     *
+     * @var array, string[]>
+     */
+    private static $names = [];
+
+    /**
+     * A map of enumerator names and instances by enumeration class
+     *
+     * @var array, array>
+     */
+    private static $instances = [];
+
+    /**
+     * Constructor
+     *
+     * @param null|bool|int|float|string|array $value   The value of the enumerator
+     * @param int|null                                $ordinal The ordinal number of the enumerator
+     */
+    final private function __construct($value, $ordinal = null)
+    {
+        $this->value   = $value;
+        $this->ordinal = $ordinal;
+    }
+
+    /**
+     * Get the name of the enumerator
+     *
+     * @return string
+     * @see getName()
+     */
+    public function __toString(): string
+    {
+        return $this->getName();
+    }
+
+    /**
+     * @throws LogicException Enums are not cloneable
+     *                        because instances are implemented as singletons
+     */
+    final public function __clone()
+    {
+        throw new LogicException('Enums are not cloneable');
+    }
+
+    /**
+     * @throws LogicException Serialization is not supported by default in this pseudo-enum implementation
+     *
+     * @psalm-return never-return
+     */
+    final public function __sleep()
+    {
+        throw new LogicException('Serialization is not supported by default in this pseudo-enum implementation');
+    }
+
+    /**
+     * @throws LogicException Serialization is not supported by default in this pseudo-enum implementation
+     *
+     * @psalm-return never-return
+     */
+    final public function __wakeup()
+    {
+        throw new LogicException('Serialization is not supported by default in this pseudo-enum implementation');
+    }
+
+    /**
+     * Get the value of the enumerator
+     *
+     * @return null|bool|int|float|string|array
+     */
+    final public function getValue()
+    {
+        return $this->value;
+    }
+
+    /**
+     * Get the name of the enumerator
+     *
+     * @return string
+     *
+     * @phpstan-return string
+     * @psalm-return non-empty-string
+     */
+    final public function getName()
+    {
+        return self::$names[static::class][$this->ordinal ?? $this->getOrdinal()];
+    }
+
+    /**
+     * Get the ordinal number of the enumerator
+     *
+     * @return int
+     */
+    final public function getOrdinal()
+    {
+        if ($this->ordinal === null) {
+            $ordinal   = 0;
+            $value     = $this->value;
+            $constants = self::$constants[static::class] ?? static::getConstants();
+            foreach ($constants as $constValue) {
+                if ($value === $constValue) {
+                    break;
+                }
+                ++$ordinal;
+            }
+
+            $this->ordinal = $ordinal;
+        }
+
+        return $this->ordinal;
+    }
+
+    /**
+     * Compare this enumerator against another and check if it's the same.
+     *
+     * @param static|null|bool|int|float|string|array $enumerator An enumerator object or value
+     * @return bool
+     */
+    final public function is($enumerator)
+    {
+        return $this === $enumerator || $this->value === $enumerator
+
+            // The following additional conditions are required only because of the issue of serializable singletons
+            || ($enumerator instanceof static
+                && \get_class($enumerator) === static::class
+                && $enumerator->value === $this->value
+            );
+    }
+
+    /**
+     * Get an enumerator instance of the given enumerator value or instance
+     *
+     * @param static|null|bool|int|float|string|array $enumerator An enumerator object or value
+     * @return static
+     * @throws InvalidArgumentException On an unknown or invalid value
+     * @throws LogicException           On ambiguous constant values
+     *
+     * @psalm-pure
+     */
+    final public static function get($enumerator)
+    {
+        if ($enumerator instanceof static) {
+            if (\get_class($enumerator) !== static::class) {
+                throw new InvalidArgumentException(sprintf(
+                    'Invalid value of type %s for enumeration %s',
+                    \get_class($enumerator),
+                    static::class
+                ));
+            }
+
+            return $enumerator;
+        }
+
+        return static::byValue($enumerator);
+    }
+
+    /**
+     * Get an enumerator instance by the given value
+     *
+     * @param null|bool|int|float|string|array $value Enumerator value
+     * @return static
+     * @throws InvalidArgumentException On an unknown or invalid value
+     * @throws LogicException           On ambiguous constant values
+     *
+     * @psalm-pure
+     */
+    final public static function byValue($value)
+    {
+        /** @var mixed $value */
+
+        $constants = self::$constants[static::class] ?? static::getConstants();
+
+        $name = \array_search($value, $constants, true);
+        if ($name === false) {
+            throw new InvalidArgumentException(sprintf(
+                'Unknown value %s for enumeration %s',
+                \is_scalar($value)
+                    ? \var_export($value, true)
+                    : 'of type ' . (\is_object($value) ? \get_class($value) : \gettype($value)),
+                static::class
+            ));
+        }
+
+        /** @var static $instance */
+        $instance = self::$instances[static::class][$name]
+            ?? self::$instances[static::class][$name] = new static($constants[$name]);
+
+        return $instance;
+    }
+
+    /**
+     * Get an enumerator instance by the given name
+     *
+     * @param string $name The name of the enumerator
+     * @return static
+     * @throws InvalidArgumentException On an invalid or unknown name
+     * @throws LogicException           On ambiguous values
+     *
+     * @psalm-pure
+     */
+    final public static function byName(string $name)
+    {
+        if (isset(self::$instances[static::class][$name])) {
+            /** @var static $instance */
+            $instance = self::$instances[static::class][$name];
+            return $instance;
+        }
+
+        $const = static::class . "::{$name}";
+        if (!\defined($const)) {
+            throw new InvalidArgumentException("{$const} not defined");
+        }
+
+        assert(
+            self::noAmbiguousValues(static::getConstants()),
+            'Ambiguous enumerator values detected for ' . static::class
+        );
+
+        /** @var array|bool|float|int|string|null $value */
+        $value = \constant($const);
+        return self::$instances[static::class][$name] = new static($value);
+    }
+
+    /**
+     * Get an enumeration instance by the given ordinal number
+     *
+     * @param int $ordinal The ordinal number of the enumerator
+     * @return static
+     * @throws InvalidArgumentException On an invalid ordinal number
+     * @throws LogicException           On ambiguous values
+     *
+     * @psalm-pure
+     */
+    final public static function byOrdinal(int $ordinal)
+    {
+        $constants = self::$constants[static::class] ?? static::getConstants();
+
+        if (!isset(self::$names[static::class][$ordinal])) {
+            throw new InvalidArgumentException(\sprintf(
+                'Invalid ordinal number %s, must between 0 and %s',
+                $ordinal,
+                \count(self::$names[static::class]) - 1
+            ));
+        }
+
+        $name = self::$names[static::class][$ordinal];
+
+        /** @var static $instance */
+        $instance = self::$instances[static::class][$name]
+            ?? self::$instances[static::class][$name] = new static($constants[$name], $ordinal);
+
+        return $instance;
+    }
+
+    /**
+     * Get a list of enumerator instances ordered by ordinal number
+     *
+     * @return static[]
+     *
+     * @phpstan-return array
+     * @psalm-return list
+     * @psalm-pure
+     */
+    final public static function getEnumerators()
+    {
+        if (!isset(self::$names[static::class])) {
+            static::getConstants();
+        }
+
+        /** @var callable $byNameFn */
+        $byNameFn = [static::class, 'byName'];
+        return \array_map($byNameFn, self::$names[static::class]);
+    }
+
+    /**
+     * Get a list of enumerator values ordered by ordinal number
+     *
+     * @return (null|bool|int|float|string|array)[]
+     *
+     * @phpstan-return array>
+     * @psalm-return list
+     * @psalm-pure
+     */
+    final public static function getValues()
+    {
+        return \array_values(self::$constants[static::class] ?? static::getConstants());
+    }
+
+    /**
+     * Get a list of enumerator names ordered by ordinal number
+     *
+     * @return string[]
+     *
+     * @phpstan-return array
+     * @psalm-return list
+     * @psalm-pure
+     */
+    final public static function getNames()
+    {
+        if (!isset(self::$names[static::class])) {
+            static::getConstants();
+        }
+        return self::$names[static::class];
+    }
+
+    /**
+     * Get a list of enumerator ordinal numbers
+     *
+     * @return int[]
+     *
+     * @phpstan-return array
+     * @psalm-return list
+     * @psalm-pure
+     */
+    final public static function getOrdinals()
+    {
+        $count = \count(self::$constants[static::class] ?? static::getConstants());
+        return $count ? \range(0, $count - 1) : [];
+    }
+
+    /**
+     * Get all available constants of the called class
+     *
+     * @return (null|bool|int|float|string|array)[]
+     * @throws LogicException On ambiguous constant values
+     *
+     * @phpstan-return array>
+     * @psalm-return array
+     * @psalm-pure
+     */
+    final public static function getConstants()
+    {
+        if (isset(self::$constants[static::class])) {
+            return self::$constants[static::class];
+        }
+
+        $reflection = new ReflectionClass(static::class);
+        $constants  = [];
+
+        do {
+            $scopeConstants = [];
+            // Enumerators must be defined as public class constants
+            foreach ($reflection->getReflectionConstants() as $reflConstant) {
+                if ($reflConstant->isPublic()) {
+                    $scopeConstants[ $reflConstant->getName() ] = $reflConstant->getValue();
+                }
+            }
+
+            $constants = $scopeConstants + $constants;
+        } while (($reflection = $reflection->getParentClass()) && $reflection->name !== __CLASS__);
+
+        /** @var array> $constants */
+
+        assert(
+            self::noAmbiguousValues($constants),
+            'Ambiguous enumerator values detected for ' . static::class
+        );
+
+        self::$names[static::class] = \array_keys($constants);
+        return self::$constants[static::class] = $constants;
+    }
+
+    /**
+     * Test that the given constants does not contain ambiguous values
+     * @param array> $constants
+     * @return bool
+     */
+    private static function noAmbiguousValues($constants)
+    {
+        foreach ($constants as $value) {
+            $names = \array_keys($constants, $value, true);
+            if (\count($names) > 1) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Test if the given enumerator is part of this enumeration
+     *
+     * @param static|null|bool|int|float|string|array $enumerator
+     * @return bool
+     *
+     * @psalm-pure
+     */
+    final public static function has($enumerator)
+    {
+        if ($enumerator instanceof static) {
+            return \get_class($enumerator) === static::class;
+        }
+
+        return static::hasValue($enumerator);
+    }
+
+    /**
+     * Test if the given enumerator value is part of this enumeration
+     *
+     * @param null|bool|int|float|string|array $value
+     * @return bool
+     *
+     * @psalm-pure
+     */
+    final public static function hasValue($value)
+    {
+        return \in_array($value, self::$constants[static::class] ?? static::getConstants(), true);
+    }
+
+    /**
+     * Test if the given enumerator name is part of this enumeration
+     *
+     * @param string $name
+     * @return bool
+     *
+     * @psalm-pure
+     */
+    final public static function hasName(string $name)
+    {
+        return \defined("static::{$name}");
+    }
+
+    /**
+     * Get an enumerator instance by the given name.
+     *
+     * This will be called automatically on calling a method
+     * with the same name of a defined enumerator.
+     *
+     * @param string       $method The name of the enumerator (called as method)
+     * @param array $args   There should be no arguments
+     * @return static
+     * @throws InvalidArgumentException On an invalid or unknown name
+     * @throws LogicException           On ambiguous constant values
+     *
+     * @psalm-pure
+     */
+    final public static function __callStatic(string $method, array $args)
+    {
+        return static::byName($method);
+    }
+}
diff --git a/app/vendor/marc-mabe/php-enum/src/EnumMap.php b/app/vendor/marc-mabe/php-enum/src/EnumMap.php
new file mode 100644
index 000000000..eae61bac8
--- /dev/null
+++ b/app/vendor/marc-mabe/php-enum/src/EnumMap.php
@@ -0,0 +1,393 @@
+).
+ *
+ * @template T of Enum
+ * @implements ArrayAccess
+ * @implements IteratorAggregate
+ *
+ * @copyright 2020, Marc Bennewitz
+ * @license http://github.com/marc-mabe/php-enum/blob/master/LICENSE.txt New BSD License
+ * @link http://github.com/marc-mabe/php-enum for the canonical source repository
+ */
+class EnumMap implements ArrayAccess, Countable, IteratorAggregate
+{
+    /**
+     * The classname of the enumeration type
+     * @var class-string
+     */
+    private $enumeration;
+
+    /**
+     * Internal map of ordinal number and data value
+     * @var array
+     */
+    private $map = [];
+
+    /**
+     * Constructor
+     * @param class-string $enumeration The classname of the enumeration type
+     * @param null|iterable, mixed> $map Initialize map
+     * @throws InvalidArgumentException
+     */
+    public function __construct(string $enumeration, ?iterable $map = null)
+    {
+        if (!\is_subclass_of($enumeration, Enum::class)) {
+            throw new InvalidArgumentException(\sprintf(
+                '%s can handle subclasses of %s only',
+                 __CLASS__,
+                Enum::class
+            ));
+        }
+        $this->enumeration = $enumeration;
+
+        if ($map) {
+            $this->addIterable($map);
+        }
+    }
+
+    /**
+     * Add virtual private property "__pairs" with a list of key-value-pairs
+     * to the result of var_dump.
+     *
+     * This helps debugging as internally the map is using the ordinal number.
+     *
+     * @return array
+     */
+    public function __debugInfo(): array {
+        $dbg = (array)$this;
+        $dbg["\0" . self::class . "\0__pairs"] = array_map(function ($k, $v) {
+            return [$k, $v];
+        }, $this->getKeys(), $this->getValues());
+        return $dbg;
+    }
+
+    /* write access (mutable) */
+
+    /**
+     * Adds the given enumerator (object or value) mapping to the specified data value.
+     * @param T|null|bool|int|float|string|array $enumerator
+     * @param mixed                                                 $value
+     * @throws InvalidArgumentException On an invalid given enumerator
+     * @see offsetSet()
+     */
+    public function add($enumerator, $value): void
+    {
+        $ord = ($this->enumeration)::get($enumerator)->getOrdinal();
+        $this->map[$ord] = $value;
+    }
+
+    /**
+     * Adds the given iterable, mapping enumerators (objects or values) to data values.
+     * @param iterable, mixed> $map
+     * @throws InvalidArgumentException On an invalid given enumerator
+     */
+    public function addIterable(iterable $map): void
+    {
+        $innerMap = $this->map;
+        foreach ($map as $enumerator => $value) {
+            $ord = ($this->enumeration)::get($enumerator)->getOrdinal();
+            $innerMap[$ord] = $value;
+        }
+        $this->map = $innerMap;
+    }
+
+    /**
+     * Removes the given enumerator (object or value) mapping.
+     * @param T|null|bool|int|float|string|array $enumerator
+     * @throws InvalidArgumentException On an invalid given enumerator
+     * @see offsetUnset()
+     */
+    public function remove($enumerator): void
+    {
+        $ord = ($this->enumeration)::get($enumerator)->getOrdinal();
+        unset($this->map[$ord]);
+    }
+
+    /**
+     * Removes the given iterable enumerator (object or value) mappings.
+     * @param iterable> $enumerators
+     * @throws InvalidArgumentException On an invalid given enumerator
+     */
+    public function removeIterable(iterable $enumerators): void
+    {
+        $map = $this->map;
+        foreach ($enumerators as $enumerator) {
+            $ord = ($this->enumeration)::get($enumerator)->getOrdinal();
+            unset($map[$ord]);
+        }
+
+        $this->map = $map;
+    }
+
+    /* write access (immutable) */
+
+    /**
+     * Creates a new map with the given enumerator (object or value) mapping to the specified data value added.
+     * @param T|null|bool|int|float|string|array $enumerator
+     * @param mixed                                                 $value
+     * @return static
+     * @throws InvalidArgumentException On an invalid given enumerator
+     */
+    public function with($enumerator, $value): self
+    {
+        $clone = clone $this;
+        $clone->add($enumerator, $value);
+        return $clone;
+    }
+
+    /**
+     * Creates a new map with the given iterable mapping enumerators (objects or values) to data values added.
+     * @param iterable, mixed> $map
+     * @return static
+     * @throws InvalidArgumentException On an invalid given enumerator
+     */
+    public function withIterable(iterable $map): self
+    {
+        $clone = clone $this;
+        $clone->addIterable($map);
+        return $clone;
+    }
+
+    /**
+     * Create a new map with the given enumerator mapping removed.
+     * @param T|null|bool|int|float|string|array $enumerator
+     * @return static
+     * @throws InvalidArgumentException On an invalid given enumerator
+     */
+    public function without($enumerator): self
+    {
+        $clone = clone $this;
+        $clone->remove($enumerator);
+        return $clone;
+    }
+
+    /**
+     * Creates a new map with the given iterable enumerator (object or value) mappings removed.
+     * @param iterable> $enumerators
+     * @return static
+     * @throws InvalidArgumentException On an invalid given enumerator
+     */
+    public function withoutIterable(iterable $enumerators): self
+    {
+        $clone = clone $this;
+        $clone->removeIterable($enumerators);
+        return $clone;
+    }
+
+    /* read access */
+
+    /**
+     * Get the classname of the enumeration type.
+     * @return class-string
+     */
+    public function getEnumeration(): string
+    {
+        return $this->enumeration;
+    }
+
+    /**
+     * Get the mapped data value of the given enumerator (object or value).
+     * @param T|null|bool|int|float|string|array $enumerator
+     * @return mixed
+     * @throws InvalidArgumentException On an invalid given enumerator
+     * @throws UnexpectedValueException If the given enumerator does not exist in this map
+     * @see offsetGet()
+     */
+    public function get($enumerator)
+    {
+        $enumerator = ($this->enumeration)::get($enumerator);
+        $ord = $enumerator->getOrdinal();
+        if (!\array_key_exists($ord, $this->map)) {
+            throw new UnexpectedValueException(sprintf(
+                'Enumerator %s could not be found',
+                \var_export($enumerator->getValue(), true)
+            ));
+        }
+
+        return $this->map[$ord];
+    }
+
+    /**
+     * Get a list of enumerator keys.
+     * @return T[]
+     *
+     * @phpstan-return array
+     * @psalm-return list
+     */
+    public function getKeys(): array
+    {
+        /** @var callable $byOrdinalFn */
+        $byOrdinalFn = [$this->enumeration, 'byOrdinal'];
+
+        return \array_map($byOrdinalFn, \array_keys($this->map));
+    }
+
+    /**
+     * Get a list of mapped data values.
+     * @return mixed[]
+     *
+     * @phpstan-return array
+     * @psalm-return list
+     */
+    public function getValues(): array
+    {
+        return \array_values($this->map);
+    }
+
+    /**
+     * Search for the given data value.
+     * @param mixed $value
+     * @param bool $strict Use strict type comparison
+     * @return T|null The enumerator object of the first matching data value or NULL
+     */
+    public function search($value, bool $strict = false)
+    {
+        /** @var false|int $ord */
+        $ord = \array_search($value, $this->map, $strict);
+        if ($ord !== false) {
+            return ($this->enumeration)::byOrdinal($ord);
+        }
+
+        return null;
+    }
+
+    /**
+     * Test if the given enumerator key (object or value) exists.
+     * @param T|null|bool|int|float|string|array $enumerator
+     * @return bool
+     * @see offsetExists()
+     */
+    public function has($enumerator): bool
+    {
+        try {
+            $ord = ($this->enumeration)::get($enumerator)->getOrdinal();
+            return \array_key_exists($ord, $this->map);
+        } catch (InvalidArgumentException $e) {
+            // An invalid enumerator can't be contained in this map
+            return false;
+        }
+    }
+
+    /**
+     * Test if the given enumerator key (object or value) exists.
+     * @param T|null|bool|int|float|string|array $enumerator
+     * @return bool
+     * @see offsetExists()
+     * @see has()
+     * @deprecated Will trigger deprecation warning in last 4.x and removed in 5.x
+     */
+    public function contains($enumerator): bool
+    {
+        return $this->has($enumerator);
+    }
+
+    /* ArrayAccess */
+
+    /**
+     * Test if the given enumerator key (object or value) exists and is not NULL
+     * @param T|null|bool|int|float|string|array $enumerator
+     * @return bool
+     * @see contains()
+     */
+    public function offsetExists($enumerator): bool
+    {
+        try {
+            return isset($this->map[($this->enumeration)::get($enumerator)->getOrdinal()]);
+        } catch (InvalidArgumentException $e) {
+            // An invalid enumerator can't be an offset of this map
+            return false;
+        }
+    }
+
+    /**
+     * Get the mapped data value of the given enumerator (object or value).
+     * @param T|null|bool|int|float|string|array $enumerator
+     * @return mixed The mapped date value of the given enumerator or NULL
+     * @throws InvalidArgumentException On an invalid given enumerator
+     * @see get()
+     */
+    #[\ReturnTypeWillChange]
+    public function offsetGet($enumerator)
+    {
+        try {
+            return $this->get($enumerator);
+        } catch (UnexpectedValueException $e) {
+            return null;
+        }
+    }
+
+    /**
+     * Adds the given enumerator (object or value) mapping to the specified data value.
+     * @param T|null|bool|int|float|string|array $enumerator
+     * @param mixed                                     $value
+     * @return void
+     * @throws InvalidArgumentException On an invalid given enumerator
+     * @see add()
+     */
+    public function offsetSet($enumerator, $value = null): void
+    {
+        $this->add($enumerator, $value);
+    }
+
+    /**
+     * Removes the given enumerator (object or value) mapping.
+     * @param T|null|bool|int|float|string|array $enumerator
+     * @return void
+     * @throws InvalidArgumentException On an invalid given enumerator
+     * @see remove()
+     */
+    public function offsetUnset($enumerator): void
+    {
+        $this->remove($enumerator);
+    }
+
+    /* IteratorAggregate */
+
+    /**
+     * Get a new Iterator.
+     *
+     * @return Iterator Iterator
+     */
+    public function getIterator(): Iterator
+    {
+        $map = $this->map;
+        foreach ($map as $ordinal => $value) {
+            yield ($this->enumeration)::byOrdinal($ordinal) => $value;
+        }
+    }
+
+    /* Countable */
+
+    /**
+     * Count the number of elements
+     *
+     * @return int
+     */
+    public function count(): int
+    {
+        return \count($this->map);
+    }
+
+    /**
+     * Tests if the map is empty
+     *
+     * @return bool
+     */
+    public function isEmpty(): bool
+    {
+        return empty($this->map);
+    }
+}
diff --git a/app/vendor/marc-mabe/php-enum/src/EnumSerializableTrait.php b/app/vendor/marc-mabe/php-enum/src/EnumSerializableTrait.php
new file mode 100644
index 000000000..1f54b9d4a
--- /dev/null
+++ b/app/vendor/marc-mabe/php-enum/src/EnumSerializableTrait.php
@@ -0,0 +1,110 @@
+
+     */
+    abstract public function getValue();
+
+    /**
+     * Returns an array of data to be serialized.
+     * This magic method will be called by serialize() in PHP >= 7.4
+     *
+     * @return array>
+     */
+    public function __serialize(): array
+    {
+        return ['value' => $this->getValue()];
+    }
+
+    /**
+     * Receives an array of data to be unserialized on a new instance without constructor.
+     * This magic method will be called in PHP >= 7.4 is the data where serialized with PHP >= 7.4.
+     *
+     * @throws RuntimeException On missing, unknown or invalid value
+     * @throws LogicException   On calling this method on an already initialized enumerator
+     *
+     * @param array $data
+     * @return void
+     */
+    public function __unserialize(array $data): void
+    {
+        if (!\array_key_exists('value', $data)) {
+            throw new RuntimeException('Missing array key "value"');
+        }
+
+        /** @var mixed $value */
+        $value     = $data['value'];
+        $constants = self::getConstants();
+        $name      = \array_search($value, $constants, true);
+        if ($name === false) {
+            $message = \is_scalar($value)
+                ? 'Unknown value ' . \var_export($value, true)
+                : 'Invalid value of type ' . (\is_object($value) ? \get_class($value) : \gettype($value));
+            throw new RuntimeException($message);
+        }
+
+        $class      = static::class;
+        $enumerator = $this;
+        $closure    = function () use ($class, $name, $value, $enumerator) {
+            if ($value !== null && $this->value !== null) {
+                throw new LogicException('Do not call this directly - please use unserialize($enum) instead');
+            }
+
+            $this->value = $value;
+
+            if (!isset(self::$instances[$class][$name])) {
+                self::$instances[$class][$name] = $enumerator;
+            }
+        };
+        $closure->bindTo($this, Enum::class)();
+    }
+
+    /**
+     * Serialize the value of the enumeration
+     * This will be called automatically on `serialize()` if the enumeration implements the `Serializable` interface
+     *
+     * @return string
+     * @deprecated Since PHP 7.4
+     */
+    public function serialize(): string
+    {
+        return \serialize($this->getValue());
+    }
+
+    /**
+     * Unserializes a given serialized value and push it into the current instance
+     * This will be called automatically on `unserialize()` if the enumeration implements the `Serializable` interface
+     * @param string $serialized
+     * @return void
+     * @throws RuntimeException On an unknown or invalid value
+     * @throws LogicException   On calling this method on an already initialized enumerator
+     * @deprecated Since PHP 7.4
+     */
+    public function unserialize($serialized): void
+    {
+        $this->__unserialize(['value' => \unserialize($serialized)]);
+    }
+}
diff --git a/app/vendor/marc-mabe/php-enum/src/EnumSet.php b/app/vendor/marc-mabe/php-enum/src/EnumSet.php
new file mode 100644
index 000000000..42e34b398
--- /dev/null
+++ b/app/vendor/marc-mabe/php-enum/src/EnumSet.php
@@ -0,0 +1,1193 @@
+)
+ * based on an integer or binary bitset depending of given enumeration size.
+ *
+ * @template T of Enum
+ * @implements IteratorAggregate
+ *
+ * @copyright 2020, Marc Bennewitz
+ * @license http://github.com/marc-mabe/php-enum/blob/master/LICENSE.txt New BSD License
+ * @link http://github.com/marc-mabe/php-enum for the canonical source repository
+ */
+class EnumSet implements IteratorAggregate, Countable
+{
+    /**
+     * The classname of the Enumeration
+     * @var class-string
+     */
+    private $enumeration;
+
+    /**
+     * Number of enumerators defined in the enumeration
+     * @var int
+     */
+    private $enumerationCount;
+
+    /**
+     * Integer or binary (little endian) bitset
+     * @var int|string
+     */
+    private $bitset = 0;
+
+    /**
+     * Integer or binary (little endian) empty bitset
+     *
+     * @var int|string
+     */
+    private $emptyBitset = 0;
+
+    /**#@+
+     * Defines private method names to be called depended of how the bitset type was set too.
+     * ... Integer or binary bitset.
+     * ... *Int or *Bin method
+     *
+     * @var string
+     */
+    /** @var string */
+    private $fnDoGetIterator       = 'doGetIteratorInt';
+
+    /** @var string */
+    private $fnDoCount             = 'doCountInt';
+
+    /** @var string */
+    private $fnDoGetOrdinals       = 'doGetOrdinalsInt';
+
+    /** @var string */
+    private $fnDoGetBit            = 'doGetBitInt';
+
+    /** @var string */
+    private $fnDoSetBit            = 'doSetBitInt';
+
+    /** @var string */
+    private $fnDoUnsetBit          = 'doUnsetBitInt';
+
+    /** @var string */
+    private $fnDoGetBinaryBitsetLe = 'doGetBinaryBitsetLeInt';
+
+    /** @var string */
+    private $fnDoSetBinaryBitsetLe = 'doSetBinaryBitsetLeInt';
+    /**#@-*/
+
+    /**
+     * Constructor
+     *
+     * @param class-string $enumeration The classname of the enumeration
+     * @param iterable>|null $enumerators iterable list of enumerators initializing the set
+     * @throws InvalidArgumentException
+     */
+    public function __construct(string $enumeration, ?iterable $enumerators = null)
+    {
+        if (!\is_subclass_of($enumeration, Enum::class)) {
+            throw new InvalidArgumentException(\sprintf(
+                '%s can handle subclasses of %s only',
+                __METHOD__,
+                Enum::class
+            ));
+        }
+
+        $this->enumeration      = $enumeration;
+        $this->enumerationCount = \count($enumeration::getConstants());
+
+        // By default the bitset is initialized as integer bitset
+        // in case the enumeration has more enumerators then integer bits
+        // we will switch this into a binary bitset
+        if ($this->enumerationCount > \PHP_INT_SIZE * 8) {
+            // init binary bitset with zeros
+            $this->bitset = $this->emptyBitset = \str_repeat("\0", (int)\ceil($this->enumerationCount / 8));
+
+            // switch internal binary bitset functions
+            $this->fnDoGetIterator       = 'doGetIteratorBin';
+            $this->fnDoCount             = 'doCountBin';
+            $this->fnDoGetOrdinals       = 'doGetOrdinalsBin';
+            $this->fnDoGetBit            = 'doGetBitBin';
+            $this->fnDoSetBit            = 'doSetBitBin';
+            $this->fnDoUnsetBit          = 'doUnsetBitBin';
+            $this->fnDoGetBinaryBitsetLe = 'doGetBinaryBitsetLeBin';
+            $this->fnDoSetBinaryBitsetLe = 'doSetBinaryBitsetLeBin';
+        }
+
+        if ($enumerators !== null) {
+            foreach ($enumerators as $enumerator) {
+                $this->{$this->fnDoSetBit}($enumeration::get($enumerator)->getOrdinal());
+            }
+        }
+    }
+
+    /**
+     * Add virtual private property "__enumerators" with a list of enumerator values set
+     * to the result of var_dump.
+     *
+     * This helps debugging as internally the enumerators of this EnumSet gets stored
+     * as either integer or binary bit-array.
+     *
+     * @return array
+     */
+    public function __debugInfo() {
+        $dbg = (array)$this;
+        $dbg["\0" . self::class . "\0__enumerators"] = $this->getValues();
+        return $dbg;
+    }
+
+    /**
+     * Get the classname of the enumeration
+     * @return class-string
+     */
+    public function getEnumeration(): string
+    {
+        return $this->enumeration;
+    }
+
+    /* write access (mutable) */
+
+    /**
+     * Adds an enumerator object or value
+     * @param T|null|bool|int|float|string|array $enumerator Enumerator object or value
+     * @return void
+     * @throws InvalidArgumentException On an invalid given enumerator
+     */
+    public function add($enumerator): void
+    {
+        $this->{$this->fnDoSetBit}(($this->enumeration)::get($enumerator)->getOrdinal());
+    }
+
+    /**
+     * Adds all enumerator objects or values of the given iterable
+     * @param iterable> $enumerators Iterable list of enumerator objects or values
+     * @return void
+     * @throws InvalidArgumentException On an invalid given enumerator
+     */
+    public function addIterable(iterable $enumerators): void
+    {
+        $bitset = $this->bitset;
+
+        try {
+            foreach ($enumerators as $enumerator) {
+                $this->{$this->fnDoSetBit}(($this->enumeration)::get($enumerator)->getOrdinal());
+            }
+        } catch (\Throwable $e) {
+            // reset all changes until error happened
+            $this->bitset = $bitset;
+            throw $e;
+        }
+    }
+
+    /**
+     * Removes the given enumerator object or value
+     * @param T|null|bool|int|float|string|array $enumerator Enumerator object or value
+     * @return void
+     * @throws InvalidArgumentException On an invalid given enumerator
+     */
+    public function remove($enumerator): void
+    {
+        $this->{$this->fnDoUnsetBit}(($this->enumeration)::get($enumerator)->getOrdinal());
+    }
+
+    /**
+     * Adds an enumerator object or value
+     * @param T|null|bool|int|float|string|array $enumerator Enumerator object or value
+     * @return void
+     * @throws InvalidArgumentException On an invalid given enumerator
+     * @see add()
+     * @see with()
+     * @deprecated Will trigger deprecation warning in last 4.x and removed in 5.x
+     */
+    public function attach($enumerator): void
+    {
+        $this->add($enumerator);
+    }
+
+    /**
+     * Removes the given enumerator object or value
+     * @param T|null|bool|int|float|string|array $enumerator Enumerator object or value
+     * @return void
+     * @throws InvalidArgumentException On an invalid given enumerator
+     * @see remove()
+     * @see without()
+     * @deprecated Will trigger deprecation warning in last 4.x and removed in 5.x
+     */
+    public function detach($enumerator): void
+    {
+        $this->remove($enumerator);
+    }
+
+    /**
+     * Removes all enumerator objects or values of the given iterable
+     * @param iterable> $enumerators Iterable list of enumerator objects or values
+     * @return void
+     * @throws InvalidArgumentException On an invalid given enumerator
+     */
+    public function removeIterable(iterable $enumerators): void
+    {
+        $bitset = $this->bitset;
+
+        try {
+            foreach ($enumerators as $enumerator) {
+                $this->{$this->fnDoUnsetBit}(($this->enumeration)::get($enumerator)->getOrdinal());
+            }
+        } catch (\Throwable $e) {
+            // reset all changes until error happened
+            $this->bitset = $bitset;
+            throw $e;
+        }
+    }
+
+    /**
+     * Modify this set from both this and other (this | other)
+     *
+     * @param EnumSet $other EnumSet of the same enumeration to produce the union
+     * @return void
+     * @throws InvalidArgumentException If $other doesn't match the enumeration
+     */
+    public function setUnion(EnumSet $other): void
+    {
+        if ($this->enumeration !== $other->enumeration) {
+            throw new InvalidArgumentException(\sprintf(
+                'Other should be of the same enumeration as this %s',
+                $this->enumeration
+            ));
+        }
+
+        $this->bitset = $this->bitset | $other->bitset;
+    }
+
+    /**
+     * Modify this set with enumerators common to both this and other (this & other)
+     *
+     * @param EnumSet $other EnumSet of the same enumeration to produce the intersect
+     * @return void
+     * @throws InvalidArgumentException If $other doesn't match the enumeration
+     */
+    public function setIntersect(EnumSet $other): void
+    {
+        if ($this->enumeration !== $other->enumeration) {
+            throw new InvalidArgumentException(\sprintf(
+                'Other should be of the same enumeration as this %s',
+                $this->enumeration
+            ));
+        }
+
+        $this->bitset = $this->bitset & $other->bitset;
+    }
+
+    /**
+     * Modify this set with enumerators in this but not in other (this - other)
+     *
+     * @param EnumSet $other EnumSet of the same enumeration to produce the diff
+     * @return void
+     * @throws InvalidArgumentException If $other doesn't match the enumeration
+     */
+    public function setDiff(EnumSet $other): void
+    {
+        if ($this->enumeration !== $other->enumeration) {
+            throw new InvalidArgumentException(\sprintf(
+                'Other should be of the same enumeration as this %s',
+                $this->enumeration
+            ));
+        }
+
+        $this->bitset = $this->bitset & ~$other->bitset;
+    }
+
+    /**
+     * Modify this set with enumerators in either this and other but not in both (this ^ other)
+     *
+     * @param EnumSet $other EnumSet of the same enumeration to produce the symmetric difference
+     * @return void
+     * @throws InvalidArgumentException If $other doesn't match the enumeration
+     */
+    public function setSymDiff(EnumSet $other): void
+    {
+        if ($this->enumeration !== $other->enumeration) {
+            throw new InvalidArgumentException(\sprintf(
+                'Other should be of the same enumeration as this %s',
+                $this->enumeration
+            ));
+        }
+
+        $this->bitset = $this->bitset ^ $other->bitset;
+    }
+
+    /**
+     * Set the given binary bitset in little-endian order
+     *
+     * @param string $bitset
+     * @return void
+     * @throws InvalidArgumentException On out-of-range bits given as input bitset
+     * @uses doSetBinaryBitsetLeBin()
+     * @uses doSetBinaryBitsetLeInt()
+     */
+    public function setBinaryBitsetLe(string $bitset): void
+    {
+        $this->{$this->fnDoSetBinaryBitsetLe}($bitset);
+    }
+
+    /**
+     * Set binary bitset in little-endian order
+     *
+     * @param string $bitset
+     * @return void
+     * @throws InvalidArgumentException On out-of-range bits given as input bitset
+     * @see setBinaryBitsetLeBin()
+     * @see doSetBinaryBitsetLeInt()
+     */
+    private function doSetBinaryBitsetLeBin($bitset): void
+    {
+        /** @var string $thisBitset */
+        $thisBitset = $this->bitset;
+
+        $size   = \strlen($thisBitset);
+        $sizeIn = \strlen($bitset);
+
+        if ($sizeIn < $size) {
+            // add "\0" if the given bitset is not long enough
+            $bitset .= \str_repeat("\0", $size - $sizeIn);
+        } elseif ($sizeIn > $size) {
+            if (\ltrim(\substr($bitset, $size), "\0") !== '') {
+                throw new InvalidArgumentException('out-of-range bits detected');
+            }
+            $bitset = \substr($bitset, 0, $size);
+        }
+
+        // truncate out-of-range bits of last byte
+        $lastByteMaxOrd = $this->enumerationCount % 8;
+        if ($lastByteMaxOrd !== 0) {
+            $lastByte         = $bitset[-1];
+            $lastByteExpected = \chr((1 << $lastByteMaxOrd) - 1) & $lastByte;
+            if ($lastByte !== $lastByteExpected) {
+                throw new InvalidArgumentException('out-of-range bits detected');
+            }
+
+            $this->bitset = \substr($bitset, 0, -1) . $lastByteExpected;
+        }
+
+        $this->bitset = $bitset;
+    }
+
+    /**
+     * Set binary bitset in little-endian order
+     *
+     * @param string $bitset
+     * @return void
+     * @throws InvalidArgumentException On out-of-range bits given as input bitset
+     * @see setBinaryBitsetLeBin()
+     * @see doSetBinaryBitsetLeBin()
+     */
+    private function doSetBinaryBitsetLeInt($bitset): void
+    {
+        $len = \strlen($bitset);
+        $int = 0;
+        for ($i = 0; $i < $len; ++$i) {
+            $ord = \ord($bitset[$i]);
+
+            if ($ord && $i > \PHP_INT_SIZE - 1) {
+                throw new InvalidArgumentException('out-of-range bits detected');
+            }
+
+            $int |= $ord << (8 * $i);
+        }
+
+        if ($int & (~0 << $this->enumerationCount)) {
+            throw new InvalidArgumentException('out-of-range bits detected');
+        }
+
+        $this->bitset = $int;
+    }
+
+    /**
+     * Set the given binary bitset in big-endian order
+     *
+     * @param string $bitset
+     * @return void
+     * @throws InvalidArgumentException On out-of-range bits given as input bitset
+     */
+    public function setBinaryBitsetBe(string $bitset): void
+    {
+        $this->{$this->fnDoSetBinaryBitsetLe}(\strrev($bitset));
+    }
+
+    /**
+     * Set a bit at the given ordinal number
+     *
+     * @param int $ordinal Ordinal number of bit to set
+     * @param bool $bit    The bit to set
+     * @return void
+     * @throws InvalidArgumentException If the given ordinal number is out-of-range
+     * @uses doSetBitBin()
+     * @uses doSetBitInt()
+     * @uses doUnsetBitBin()
+     * @uses doUnsetBitInt()
+     */
+    public function setBit(int $ordinal, bool $bit): void
+    {
+        if ($ordinal < 0 || $ordinal > $this->enumerationCount) {
+            throw new InvalidArgumentException("Ordinal number must be between 0 and {$this->enumerationCount}");
+        }
+
+        if ($bit) {
+            $this->{$this->fnDoSetBit}($ordinal);
+        } else {
+            $this->{$this->fnDoUnsetBit}($ordinal);
+        }
+    }
+
+    /**
+     * Set a bit at the given ordinal number.
+     *
+     * This is the binary bitset implementation.
+     *
+     * @param int $ordinal Ordinal number of bit to set
+     * @return void
+     * @see setBit()
+     * @see doSetBitInt()
+     */
+    private function doSetBitBin($ordinal): void
+    {
+        /** @var string $thisBitset */
+        $thisBitset = $this->bitset;
+
+        $byte = (int) ($ordinal / 8);
+        $thisBitset[$byte] = $thisBitset[$byte] | \chr(1 << ($ordinal % 8));
+
+        $this->bitset = $thisBitset;
+    }
+
+    /**
+     * Set a bit at the given ordinal number.
+     *
+     * This is the binary bitset implementation.
+     *
+     * @param int $ordinal Ordinal number of bit to set
+     * @return void
+     * @see setBit()
+     * @see doSetBitBin()
+     */
+    private function doSetBitInt($ordinal): void
+    {
+        /** @var int $thisBitset */
+        $thisBitset = $this->bitset;
+
+        $this->bitset = $thisBitset | (1 << $ordinal);
+    }
+
+    /**
+     * Unset a bit at the given ordinal number.
+     *
+     * This is the binary bitset implementation.
+     *
+     * @param int $ordinal Ordinal number of bit to unset
+     * @return void
+     * @see setBit()
+     * @see doUnsetBitInt()
+     */
+    private function doUnsetBitBin($ordinal): void
+    {
+        /** @var string $thisBitset */
+        $thisBitset = $this->bitset;
+
+        $byte = (int) ($ordinal / 8);
+        $thisBitset[$byte] = $thisBitset[$byte] & \chr(~(1 << ($ordinal % 8)));
+
+        $this->bitset = $thisBitset;
+    }
+
+    /**
+     * Unset a bit at the given ordinal number.
+     *
+     * This is the integer bitset implementation.
+     *
+     * @param int $ordinal Ordinal number of bit to unset
+     * @return void
+     * @see setBit()
+     * @see doUnsetBitBin()
+     */
+    private function doUnsetBitInt($ordinal): void
+    {
+        /** @var int $thisBitset */
+        $thisBitset = $this->bitset;
+
+        $this->bitset = $thisBitset & ~(1 << $ordinal);
+    }
+
+    /* write access (immutable) */
+
+    /**
+     * Creates a new set with the given enumerator object or value added
+     * @param T|null|bool|int|float|string|array $enumerator Enumerator object or value
+     * @return static
+     * @throws InvalidArgumentException On an invalid given enumerator
+     */
+    public function with($enumerator): self
+    {
+        $clone = clone $this;
+        $clone->{$this->fnDoSetBit}(($this->enumeration)::get($enumerator)->getOrdinal());
+        return $clone;
+    }
+
+    /**
+     * Creates a new set with the given enumeration objects or values added
+     * @param iterable> $enumerators Iterable list of enumerator objects or values
+     * @return static
+     * @throws InvalidArgumentException On an invalid given enumerator
+     */
+    public function withIterable(iterable $enumerators): self
+    {
+        $clone = clone $this;
+        foreach ($enumerators as $enumerator) {
+            $clone->{$this->fnDoSetBit}(($this->enumeration)::get($enumerator)->getOrdinal());
+        }
+        return $clone;
+    }
+
+    /**
+     * Create a new set with the given enumerator object or value removed
+     * @param T|null|bool|int|float|string|array $enumerator Enumerator object or value
+     * @return static
+     * @throws InvalidArgumentException On an invalid given enumerator
+     */
+    public function without($enumerator): self
+    {
+        $clone = clone $this;
+        $clone->{$this->fnDoUnsetBit}(($this->enumeration)::get($enumerator)->getOrdinal());
+        return $clone;
+    }
+
+    /**
+     * Creates a new set with the given enumeration objects or values removed
+     * @param iterable> $enumerators Iterable list of enumerator objects or values
+     * @return static
+     * @throws InvalidArgumentException On an invalid given enumerator
+     */
+    public function withoutIterable(iterable $enumerators): self
+    {
+        $clone = clone $this;
+        foreach ($enumerators as $enumerator) {
+            $clone->{$this->fnDoUnsetBit}(($this->enumeration)::get($enumerator)->getOrdinal());
+        }
+        return $clone;
+    }
+
+    /**
+     * Create a new set with enumerators from both this and other (this | other)
+     *
+     * @param EnumSet $other EnumSet of the same enumeration to produce the union
+     * @return static
+     * @throws InvalidArgumentException If $other doesn't match the enumeration
+     */
+    public function withUnion(EnumSet $other): self
+    {
+        $clone = clone $this;
+        $clone->setUnion($other);
+        return $clone;
+    }
+
+    /**
+     * Create a new set with enumerators from both this and other (this | other)
+     *
+     * @param EnumSet $other EnumSet of the same enumeration to produce the union
+     * @return static
+     * @throws InvalidArgumentException If $other doesn't match the enumeration
+     * @see withUnion()
+     * @see setUnion()
+     * @deprecated Will trigger deprecation warning in last 4.x and removed in 5.x
+     */
+    public function union(EnumSet $other): self
+    {
+        return $this->withUnion($other);
+    }
+
+    /**
+     * Create a new set with enumerators common to both this and other (this & other)
+     *
+     * @param EnumSet $other EnumSet of the same enumeration to produce the intersect
+     * @return static
+     * @throws InvalidArgumentException If $other doesn't match the enumeration
+     */
+    public function withIntersect(EnumSet $other): self
+    {
+        $clone = clone $this;
+        $clone->setIntersect($other);
+        return $clone;
+    }
+
+    /**
+     * Create a new set with enumerators common to both this and other (this & other)
+     *
+     * @param EnumSet $other EnumSet of the same enumeration to produce the intersect
+     * @return static
+     * @throws InvalidArgumentException If $other doesn't match the enumeration
+     * @see withIntersect()
+     * @see setIntersect()
+     * @deprecated Will trigger deprecation warning in last 4.x and removed in 5.x
+     */
+    public function intersect(EnumSet $other): self
+    {
+        return $this->withIntersect($other);
+    }
+
+    /**
+     * Create a new set with enumerators in this but not in other (this - other)
+     *
+     * @param EnumSet $other EnumSet of the same enumeration to produce the diff
+     * @return static
+     * @throws InvalidArgumentException If $other doesn't match the enumeration
+     */
+    public function withDiff(EnumSet $other): self
+    {
+        $clone = clone $this;
+        $clone->setDiff($other);
+        return $clone;
+    }
+
+    /**
+     * Create a new set with enumerators in this but not in other (this - other)
+     *
+     * @param EnumSet $other EnumSet of the same enumeration to produce the diff
+     * @return static
+     * @throws InvalidArgumentException If $other doesn't match the enumeration
+     * @see withDiff()
+     * @see setDiff()
+     * @deprecated Will trigger deprecation warning in last 4.x and removed in 5.x
+     */
+    public function diff(EnumSet $other): self
+    {
+        return $this->withDiff($other);
+    }
+
+    /**
+     * Create a new set with enumerators in either this and other but not in both (this ^ other)
+     *
+     * @param EnumSet $other EnumSet of the same enumeration to produce the symmetric difference
+     * @return static
+     * @throws InvalidArgumentException If $other doesn't match the enumeration
+     */
+    public function withSymDiff(EnumSet $other): self
+    {
+        $clone = clone $this;
+        $clone->setSymDiff($other);
+        return $clone;
+    }
+
+    /**
+     * Create a new set with enumerators in either this and other but not in both (this ^ other)
+     *
+     * @param EnumSet $other EnumSet of the same enumeration to produce the symmetric difference
+     * @return static
+     * @throws InvalidArgumentException If $other doesn't match the enumeration
+     * @see withSymDiff()
+     * @see setSymDiff()
+     * @deprecated Will trigger deprecation warning in last 4.x and removed in 5.x
+     */
+    public function symDiff(EnumSet $other): self
+    {
+        return $this->withSymDiff($other);
+    }
+
+    /**
+     * Create a new set with the given binary bitset in little-endian order
+     *
+     * @param string $bitset
+     * @return static
+     * @throws InvalidArgumentException On out-of-range bits given as input bitset
+     * @uses doSetBinaryBitsetLeBin()
+     * @uses doSetBinaryBitsetLeInt()
+     */
+    public function withBinaryBitsetLe(string $bitset): self
+    {
+        $clone = clone $this;
+        $clone->{$this->fnDoSetBinaryBitsetLe}($bitset);
+        return $clone;
+    }
+
+    /**
+     * Create a new set with the given binary bitset in big-endian order
+     *
+     * @param string $bitset
+     * @return static
+     * @throws InvalidArgumentException On out-of-range bits given as input bitset
+     */
+    public function withBinaryBitsetBe(string $bitset): self
+    {
+        $clone = $this;
+        $clone->{$this->fnDoSetBinaryBitsetLe}(\strrev($bitset));
+        return $clone;
+    }
+
+    /**
+     * Create a new set with the bit at the given ordinal number set
+     *
+     * @param int $ordinal Ordinal number of bit to set
+     * @param bool $bit    The bit to set
+     * @return static
+     * @throws InvalidArgumentException If the given ordinal number is out-of-range
+     * @uses doSetBitBin()
+     * @uses doSetBitInt()
+     * @uses doUnsetBitBin()
+     * @uses doUnsetBitInt()
+     */
+    public function withBit(int $ordinal, bool $bit): self
+    {
+        $clone = clone $this;
+        $clone->setBit($ordinal, $bit);
+        return $clone;
+    }
+
+    /* read access */
+
+    /**
+     * Test if the given enumerator exists
+     * @param T|null|bool|int|float|string|array $enumerator
+     * @return bool
+     */
+    public function has($enumerator): bool
+    {
+        return $this->{$this->fnDoGetBit}(($this->enumeration)::get($enumerator)->getOrdinal());
+    }
+
+    /**
+     * Test if the given enumerator exists
+     * @param T|null|bool|int|float|string|array $enumerator
+     * @return bool
+     * @see has()
+     * @deprecated Will trigger deprecation warning in last 4.x and removed in 5.x
+     */
+    public function contains($enumerator): bool
+    {
+        return $this->has($enumerator);
+    }
+
+    /* IteratorAggregate */
+
+    /**
+     * Get a new iterator
+     * @return Iterator
+     * @uses doGetIteratorInt()
+     * @uses doGetIteratorBin()
+     */
+    public function getIterator(): Iterator
+    {
+        return $this->{$this->fnDoGetIterator}();
+    }
+
+    /**
+     * Get a new Iterator.
+     *
+     * This is the binary bitset implementation.
+     *
+     * @return Iterator
+     * @see getIterator()
+     * @see goGetIteratorInt()
+     */
+    private function doGetIteratorBin()
+    {
+        /** @var string $bitset */
+        $bitset   = $this->bitset;
+        $byteLen  = \strlen($bitset);
+        for ($bytePos = 0; $bytePos < $byteLen; ++$bytePos) {
+            if ($bitset[$bytePos] === "\0") {
+                // fast skip null byte
+                continue;
+            }
+
+            $ord = \ord($bitset[$bytePos]);
+            for ($bitPos = 0; $bitPos < 8; ++$bitPos) {
+                if ($ord & (1 << $bitPos)) {
+                    $ordinal = $bytePos * 8 + $bitPos;
+                    yield $ordinal => ($this->enumeration)::byOrdinal($ordinal);
+                }
+            }
+        }
+    }
+
+    /**
+     * Get a new Iterator.
+     *
+     * This is the integer bitset implementation.
+     *
+     * @return Iterator
+     * @see getIterator()
+     * @see doGetIteratorBin()
+     */
+    private function doGetIteratorInt()
+    {
+        /** @var int $bitset */
+        $bitset = $this->bitset;
+        $count  = $this->enumerationCount;
+        for ($ordinal = 0; $ordinal < $count; ++$ordinal) {
+            if ($bitset & (1 << $ordinal)) {
+                yield $ordinal => ($this->enumeration)::byOrdinal($ordinal);
+            }
+        }
+    }
+
+    /* Countable */
+
+    /**
+     * Count the number of elements
+     *
+     * @return int
+     * @uses doCountBin()
+     * @uses doCountInt()
+     */
+    public function count(): int
+    {
+        return $this->{$this->fnDoCount}();
+    }
+
+    /**
+     * Count the number of elements.
+     *
+     * This is the binary bitset implementation.
+     *
+     * @return int
+     * @see count()
+     * @see doCountInt()
+     */
+    private function doCountBin()
+    {
+        /** @var string $bitset */
+        $bitset  = $this->bitset;
+        $count   = 0;
+        $byteLen = \strlen($bitset);
+        for ($bytePos = 0; $bytePos < $byteLen; ++$bytePos) {
+            if ($bitset[$bytePos] === "\0") {
+                // fast skip null byte
+                continue;
+            }
+
+            $ord = \ord($bitset[$bytePos]);
+            if ($ord & 0b00000001) ++$count;
+            if ($ord & 0b00000010) ++$count;
+            if ($ord & 0b00000100) ++$count;
+            if ($ord & 0b00001000) ++$count;
+            if ($ord & 0b00010000) ++$count;
+            if ($ord & 0b00100000) ++$count;
+            if ($ord & 0b01000000) ++$count;
+            if ($ord & 0b10000000) ++$count;
+        }
+        return $count;
+    }
+
+    /**
+     * Count the number of elements.
+     *
+     * This is the integer bitset implementation.
+     *
+     * @return int
+     * @see count()
+     * @see doCountBin()
+     */
+    private function doCountInt()
+    {
+        /** @var int $bitset */
+        $bitset = $this->bitset;
+        $count  = 0;
+
+        // PHP does not support right shift unsigned
+        if ($bitset < 0) {
+            $count  = 1;
+            $bitset = $bitset & \PHP_INT_MAX;
+        }
+
+        // iterate byte by byte and count set bits
+        $phpIntBitSize = \PHP_INT_SIZE * 8;
+        for ($bitPos = 0; $bitPos < $phpIntBitSize; $bitPos += 8) {
+            $bitChk = 0xff << $bitPos;
+            $byte = $bitset & $bitChk;
+            if ($byte) {
+                $byte = $byte >> $bitPos;
+                if ($byte & 0b00000001) ++$count;
+                if ($byte & 0b00000010) ++$count;
+                if ($byte & 0b00000100) ++$count;
+                if ($byte & 0b00001000) ++$count;
+                if ($byte & 0b00010000) ++$count;
+                if ($byte & 0b00100000) ++$count;
+                if ($byte & 0b01000000) ++$count;
+                if ($byte & 0b10000000) ++$count;
+            }
+
+            if ($bitset <= $bitChk) {
+                break;
+            }
+        }
+
+        return $count;
+    }
+
+    /**
+     * Check if this EnumSet is the same as other
+     * @param EnumSet $other
+     * @return bool
+     */
+    public function isEqual(EnumSet $other): bool
+    {
+        return $this->enumeration === $other->enumeration
+            && $this->bitset === $other->bitset;
+    }
+
+    /**
+     * Check if this EnumSet is a subset of other
+     * @param EnumSet $other
+     * @return bool
+     */
+    public function isSubset(EnumSet $other): bool
+    {
+        return $this->enumeration === $other->enumeration
+            && ($this->bitset & $other->bitset) === $this->bitset;
+    }
+
+    /**
+     * Check if this EnumSet is a superset of other
+     * @param EnumSet $other
+     * @return bool
+     */
+    public function isSuperset(EnumSet $other): bool
+    {
+        return $this->enumeration === $other->enumeration
+            && ($this->bitset | $other->bitset) === $this->bitset;
+    }
+
+    /**
+     * Tests if the set is empty
+     *
+     * @return bool
+     */
+    public function isEmpty(): bool
+    {
+        return $this->bitset === $this->emptyBitset;
+    }
+
+    /**
+     * Get ordinal numbers of the defined enumerators as array
+     * @return array
+     * @uses  doGetOrdinalsBin()
+     * @uses  doGetOrdinalsInt()
+     */
+    public function getOrdinals(): array
+    {
+        return $this->{$this->fnDoGetOrdinals}();
+    }
+
+    /**
+     * Get ordinal numbers of the defined enumerators as array.
+     *
+     * This is the binary bitset implementation.
+     *
+     * @return array
+     * @see getOrdinals()
+     * @see goGetOrdinalsInt()
+     */
+    private function doGetOrdinalsBin()
+    {
+        /** @var string $bitset */
+        $bitset   = $this->bitset;
+        $ordinals = [];
+        $byteLen  = \strlen($bitset);
+        for ($bytePos = 0; $bytePos < $byteLen; ++$bytePos) {
+            if ($bitset[$bytePos] === "\0") {
+                // fast skip null byte
+                continue;
+            }
+
+            $ord = \ord($bitset[$bytePos]);
+            for ($bitPos = 0; $bitPos < 8; ++$bitPos) {
+                if ($ord & (1 << $bitPos)) {
+                    $ordinals[] = $bytePos * 8 + $bitPos;
+                }
+            }
+        }
+        return $ordinals;
+    }
+
+    /**
+     * Get ordinal numbers of the defined enumerators as array.
+     *
+     * This is the integer bitset implementation.
+     *
+     * @return array
+     * @see getOrdinals()
+     * @see doGetOrdinalsBin()
+     */
+    private function doGetOrdinalsInt()
+    {
+        /** @var int $bitset */
+        $bitset   = $this->bitset;
+        $ordinals = [];
+        $count    = $this->enumerationCount;
+        for ($ordinal = 0; $ordinal < $count; ++$ordinal) {
+            if ($bitset & (1 << $ordinal)) {
+                $ordinals[] = $ordinal;
+            }
+        }
+        return $ordinals;
+    }
+
+    /**
+     * Get values of the defined enumerators as array
+     * @return (null|bool|int|float|string|array)[]
+     *
+     * @phpstan-return array>
+     * @psalm-return list
+     */
+    public function getValues(): array
+    {
+        $enumeration = $this->enumeration;
+        $values      = [];
+        foreach ($this->getOrdinals() as $ord) {
+            $values[] = $enumeration::byOrdinal($ord)->getValue();
+        }
+        return $values;
+    }
+
+    /**
+     * Get names of the defined enumerators as array
+     * @return string[]
+     *
+     * @phpstan-return array
+     * @psalm-return list
+     */
+    public function getNames(): array
+    {
+        $enumeration = $this->enumeration;
+        $names       = [];
+        foreach ($this->getOrdinals() as $ord) {
+            $names[] = $enumeration::byOrdinal($ord)->getName();
+        }
+        return $names;
+    }
+
+    /**
+     * Get the defined enumerators as array
+     * @return Enum[]
+     *
+     * @phpstan-return array
+     * @psalm-return list
+     */
+    public function getEnumerators(): array
+    {
+        $enumeration = $this->enumeration;
+        $enumerators = [];
+        foreach ($this->getOrdinals() as $ord) {
+            $enumerators[] = $enumeration::byOrdinal($ord);
+        }
+        return $enumerators;
+    }
+
+    /**
+     * Get binary bitset in little-endian order
+     *
+     * @return string
+     * @uses doGetBinaryBitsetLeBin()
+     * @uses doGetBinaryBitsetLeInt()
+     */
+    public function getBinaryBitsetLe(): string
+    {
+        return $this->{$this->fnDoGetBinaryBitsetLe}();
+    }
+
+    /**
+     * Get binary bitset in little-endian order.
+     *
+     * This is the binary bitset implementation.
+     *
+     * @return string
+     * @see getBinaryBitsetLe()
+     * @see doGetBinaryBitsetLeInt()
+     */
+    private function doGetBinaryBitsetLeBin()
+    {
+        /** @var string $bitset */
+        $bitset = $this->bitset;
+
+        return $bitset;
+    }
+
+    /**
+     * Get binary bitset in little-endian order.
+     *
+     * This is the integer bitset implementation.
+     *
+     * @return string
+     * @see getBinaryBitsetLe()
+     * @see doGetBinaryBitsetLeBin()
+     */
+    private function doGetBinaryBitsetLeInt()
+    {
+        $bin = \pack(\PHP_INT_SIZE === 8 ? 'P' : 'V', $this->bitset);
+        return \substr($bin, 0, (int)\ceil($this->enumerationCount / 8));
+    }
+
+    /**
+     * Get binary bitset in big-endian order
+     *
+     * @return string
+     */
+    public function getBinaryBitsetBe(): string
+    {
+        return \strrev($this->getBinaryBitsetLe());
+    }
+
+    /**
+     * Get a bit at the given ordinal number
+     *
+     * @param int $ordinal Ordinal number of bit to get
+     * @return bool
+     * @throws InvalidArgumentException If the given ordinal number is out-of-range
+     * @uses doGetBitBin()
+     * @uses doGetBitInt()
+     */
+    public function getBit(int $ordinal): bool
+    {
+        if ($ordinal < 0 || $ordinal > $this->enumerationCount) {
+            throw new InvalidArgumentException("Ordinal number must be between 0 and {$this->enumerationCount}");
+        }
+
+        return $this->{$this->fnDoGetBit}($ordinal);
+    }
+
+    /**
+     * Get a bit at the given ordinal number.
+     *
+     * This is the binary bitset implementation.
+     *
+     * @param int $ordinal Ordinal number of bit to get
+     * @return bool
+     * @see getBit()
+     * @see doGetBitInt()
+     */
+    private function doGetBitBin($ordinal)
+    {
+        /** @var string $bitset */
+        $bitset = $this->bitset;
+
+        return (\ord($bitset[(int) ($ordinal / 8)]) & 1 << ($ordinal % 8)) !== 0;
+    }
+
+    /**
+     * Get a bit at the given ordinal number.
+     *
+     * This is the integer bitset implementation.
+     *
+     * @param int $ordinal Ordinal number of bit to get
+     * @return bool
+     * @see getBit()
+     * @see doGetBitBin()
+     */
+    private function doGetBitInt($ordinal)
+    {
+        /** @var int $bitset */
+        $bitset = $this->bitset;
+
+        return (bool)($bitset & (1 << $ordinal));
+    }
+}
diff --git a/app/vendor/marc-mabe/php-enum/stubs/Stringable.php b/app/vendor/marc-mabe/php-enum/stubs/Stringable.php
new file mode 100644
index 000000000..77e037cb5
--- /dev/null
+++ b/app/vendor/marc-mabe/php-enum/stubs/Stringable.php
@@ -0,0 +1,11 @@
+scanner->whitespace();
 
         $val = $this->attributeValue();
-        if ($isValidAttribute) {
+        if ($isValidAttribute && !array_key_exists($name, $attributes)) {
             $attributes[$name] = $val;
         }
 
@@ -729,6 +729,7 @@ protected function isCommentEnd()
         // Test for '!>'
         if ('!' == $this->scanner->current() && '>' == $this->scanner->peek()) {
             $this->scanner->consume(); // Consume the last '>'
+
             return true;
         }
         // Unread '-' and one of '!' or '>';
@@ -1127,7 +1128,7 @@ protected function decodeCharacterReference($inAttribute = false)
                 return '&';
             }
 
-            // Hexidecimal encoding.
+            // Hexadecimal encoding.
             // X[0-9a-fA-F]+;
             // x[0-9a-fA-F]+;
             if ('x' === $tok || 'X' === $tok) {
diff --git a/app/vendor/masterminds/html5/src/HTML5/Parser/TreeBuildingRules.php b/app/vendor/masterminds/html5/src/HTML5/Parser/TreeBuildingRules.php
index 00d3951fd..4c6983b2e 100644
--- a/app/vendor/masterminds/html5/src/HTML5/Parser/TreeBuildingRules.php
+++ b/app/vendor/masterminds/html5/src/HTML5/Parser/TreeBuildingRules.php
@@ -80,7 +80,6 @@ public function evaluate($new, $current)
             case 'thead':
             case 'tfoot':
             case 'table': // Spec isn't explicit about this, but it's necessary.
-
                 return $this->closeIfCurrentMatches($new, $current, array(
                     'thead',
                     'tfoot',
diff --git a/app/vendor/masterminds/html5/src/HTML5/Serializer/OutputRules.php b/app/vendor/masterminds/html5/src/HTML5/Serializer/OutputRules.php
index ec467f22c..13cbdc66b 100644
--- a/app/vendor/masterminds/html5/src/HTML5/Serializer/OutputRules.php
+++ b/app/vendor/masterminds/html5/src/HTML5/Serializer/OutputRules.php
@@ -206,6 +206,9 @@ protected function doctype()
         $this->nl();
     }
 
+    /**
+     * @param \DOMElement $ele
+     */
     public function element($ele)
     {
         $name = $ele->tagName;
@@ -227,6 +230,9 @@ public function element($ele)
         }
 
         $this->openTag($ele);
+        // The tag is already self-closed (`` or ``) in `openTag` if there are no child nodes.
+        $handledAsVoidTag = $this->outputMode !== static::IM_IN_HTML && !$ele->hasChildNodes();
+
         if (Elements::isA($name, Elements::TEXT_RAW)) {
             foreach ($ele->childNodes as $child) {
                 if ($child instanceof \DOMCharacterData) {
@@ -248,7 +254,7 @@ public function element($ele)
         }
 
         // If not unary, add a closing tag.
-        if (!Elements::isA($name, Elements::VOID_TAG)) {
+        if (!$handledAsVoidTag && !Elements::isA($name, Elements::VOID_TAG)) {
             $this->closeTag($ele);
         }
     }
diff --git a/app/vendor/myclabs/deep-copy/.github/FUNDING.yml b/app/vendor/myclabs/deep-copy/.github/FUNDING.yml
deleted file mode 100644
index b8da664dd..000000000
--- a/app/vendor/myclabs/deep-copy/.github/FUNDING.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-# These are supported funding model platforms
-
-github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
-patreon: # Replace with a single Patreon username
-open_collective: # Replace with a single Open Collective username
-ko_fi: # Replace with a single Ko-fi username
-tidelift: "packagist/myclabs/deep-copy"
-community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
-liberapay: # Replace with a single Liberapay username
-issuehunt: # Replace with a single IssueHunt username
-otechie: # Replace with a single Otechie username
-custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
diff --git a/app/vendor/myclabs/deep-copy/.github/workflows/ci.yaml b/app/vendor/myclabs/deep-copy/.github/workflows/ci.yaml
deleted file mode 100644
index eac2812e3..000000000
--- a/app/vendor/myclabs/deep-copy/.github/workflows/ci.yaml
+++ /dev/null
@@ -1,101 +0,0 @@
-name: "Continuous Integration"
-
-on:
-  - pull_request
-  - push
-
-env:
-  COMPOSER_ROOT_VERSION: 1.99
-
-jobs:
-  composer-json-lint:
-    name: "Lint composer.json"
-
-    runs-on: "ubuntu-latest"
-
-    strategy:
-      matrix:
-        php-version:
-          - "8.1"
-
-    steps:
-      - name: "Checkout"
-        uses: "actions/checkout@v2"
-
-      - name: "Install PHP"
-        uses: "shivammathur/setup-php@v2"
-        with:
-          coverage: "none"
-          php-version: "${{ matrix.php-version }}"
-          tools: composer-normalize
-
-      - name: "Get composer cache directory"
-        id: composercache
-        run: echo "::set-output name=dir::$(composer config cache-files-dir)"
-
-      - name: "Cache dependencies"
-        uses: actions/cache@v2
-        with:
-          path: ${{ steps.composercache.outputs.dir }}
-          key: ${{ runner.os }}-php-${{ matrix.php-version }}-${{ matrix.dependencies }}-composer-${{ hashFiles('**/composer.json') }}
-          restore-keys: ${{ runner.os }}-php-${{ matrix.php-version }}-${{ matrix.dependencies }}-composer-
-
-      - name: "Install dependencies"
-        run: "composer update --no-interaction --no-progress"
-
-      - name: "Validate composer.json"
-        run: "composer validate --strict"
-
-      - name: "Normalize composer.json"
-        run: "composer-normalize --dry-run"
-
-  tests:
-    name: "Tests"
-
-    runs-on: "ubuntu-latest"
-
-    strategy:
-      matrix:
-        php-version:
-          - "7.1"
-          - "7.2"
-          - "7.3"
-          - "7.4"
-          - "8.0"
-          - "8.1"
-        dependencies:
-          - "lowest"
-          - "highest"
-
-    steps:
-      - name: "Checkout"
-        uses: "actions/checkout@v2"
-
-      - name: "Install PHP"
-        uses: "shivammathur/setup-php@v2"
-        with:
-          php-version: "${{ matrix.php-version }}"
-          ini-values: zend.assertions=1
-
-      - name: "Get composer cache directory"
-        id: composercache
-        run: echo "::set-output name=dir::$(composer config cache-files-dir)"
-
-      - name: "Cache dependencies"
-        uses: actions/cache@v2
-        with:
-          path: ${{ steps.composercache.outputs.dir }}
-          key: ${{ runner.os }}-php-${{ matrix.php-version }}-${{ matrix.dependencies }}-composer-${{ hashFiles('**/composer.json') }}
-          restore-keys: ${{ runner.os }}-php-${{ matrix.php-version }}-${{ matrix.dependencies }}-composer-
-
-      - name: "Install lowest dependencies"
-        if: ${{ matrix.dependencies == 'lowest' }}
-        run: "composer update --no-interaction --no-progress --prefer-lowest"
-
-      - name: "Install highest dependencies"
-        if: ${{ matrix.dependencies == 'highest' }}
-        run: "composer update --no-interaction --no-progress"
-
-      - name: "Run tests"
-        timeout-minutes: 3
-        run: "vendor/bin/phpunit"
diff --git a/app/vendor/myclabs/deep-copy/README.md b/app/vendor/myclabs/deep-copy/README.md
index 94aaa06d6..88ae14cca 100644
--- a/app/vendor/myclabs/deep-copy/README.md
+++ b/app/vendor/myclabs/deep-copy/README.md
@@ -3,7 +3,7 @@
 DeepCopy helps you create deep copies (clones) of your objects. It is designed to handle cycles in the association graph.
 
 [![Total Downloads](https://poser.pugx.org/myclabs/deep-copy/downloads.svg)](https://packagist.org/packages/myclabs/deep-copy)
-[![Integrate](https://github.com/myclabs/DeepCopy/workflows/ci/badge.svg?branch=1.x)](https://github.com/myclabs/DeepCopy/actions)
+[![Integrate](https://github.com/myclabs/DeepCopy/actions/workflows/ci.yaml/badge.svg?branch=1.x)](https://github.com/myclabs/DeepCopy/actions/workflows/ci.yaml)
 
 ## Table of Contents
 
diff --git a/app/vendor/myclabs/deep-copy/composer.json b/app/vendor/myclabs/deep-copy/composer.json
index 66fb34a58..f115fff85 100644
--- a/app/vendor/myclabs/deep-copy/composer.json
+++ b/app/vendor/myclabs/deep-copy/composer.json
@@ -16,11 +16,12 @@
     "require-dev": {
         "doctrine/collections": "^1.6.8",
         "doctrine/common": "^2.13.3 || ^3.2.2",
+        "phpspec/prophecy": "^1.10",
         "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
     },
     "conflict": {
         "doctrine/collections": "<1.6.8",
-        "doctrine/common": "<2.13.3 || >=3,<3.2.2"
+        "doctrine/common": "<2.13.3 || >=3 <3.2.2"
     },
     "autoload": {
         "psr-4": {
@@ -32,8 +33,8 @@
     },
     "autoload-dev": {
         "psr-4": {
-            "DeepCopy\\": "fixtures/",
-            "DeepCopyTest\\": "tests/DeepCopyTest/"
+            "DeepCopyTest\\": "tests/DeepCopyTest/",
+            "DeepCopy\\": "fixtures/"
         }
     },
     "config": {
diff --git a/app/vendor/myclabs/deep-copy/src/DeepCopy/DeepCopy.php b/app/vendor/myclabs/deep-copy/src/DeepCopy/DeepCopy.php
index 6e766d80e..a944697dd 100644
--- a/app/vendor/myclabs/deep-copy/src/DeepCopy/DeepCopy.php
+++ b/app/vendor/myclabs/deep-copy/src/DeepCopy/DeepCopy.php
@@ -4,6 +4,7 @@
 
 use ArrayObject;
 use DateInterval;
+use DatePeriod;
 use DateTimeInterface;
 use DateTimeZone;
 use DeepCopy\Exception\CloneException;
@@ -12,6 +13,7 @@
 use DeepCopy\Matcher\Matcher;
 use DeepCopy\Reflection\ReflectionHelper;
 use DeepCopy\TypeFilter\Date\DateIntervalFilter;
+use DeepCopy\TypeFilter\Date\DatePeriodFilter;
 use DeepCopy\TypeFilter\Spl\ArrayObjectFilter;
 use DeepCopy\TypeFilter\Spl\SplDoublyLinkedListFilter;
 use DeepCopy\TypeFilter\TypeFilter;
@@ -64,6 +66,7 @@ public function __construct($useCloneMethod = false)
 
         $this->addTypeFilter(new ArrayObjectFilter($this), new TypeMatcher(ArrayObject::class));
         $this->addTypeFilter(new DateIntervalFilter(), new TypeMatcher(DateInterval::class));
+        $this->addTypeFilter(new DatePeriodFilter(), new TypeMatcher(DatePeriod::class));
         $this->addTypeFilter(new SplDoublyLinkedListFilter($this), new TypeMatcher(SplDoublyLinkedList::class));
     }
 
@@ -84,9 +87,11 @@ public function skipUncloneable($skipUncloneable = true)
     /**
      * Deep copies the given object.
      *
-     * @param mixed $object
+     * @template TObject
      *
-     * @return mixed
+     * @param TObject $object
+     *
+     * @return TObject
      */
     public function copy($object)
     {
@@ -119,6 +124,14 @@ public function addTypeFilter(TypeFilter $filter, TypeMatcher $matcher)
         ];
     }
 
+    public function prependTypeFilter(TypeFilter $filter, TypeMatcher $matcher)
+    {
+        array_unshift($this->typeFilters, [
+            'matcher' => $matcher,
+            'filter'  => $filter,
+        ]);
+    }
+
     private function recursiveCopy($var)
     {
         // Matches Type Filter
@@ -224,6 +237,11 @@ private function copyObjectProperty($object, ReflectionProperty $property)
             return;
         }
 
+        // Ignore readonly properties
+        if (method_exists($property, 'isReadOnly') && $property->isReadOnly()) {
+            return;
+        }
+
         // Apply the filters
         foreach ($this->filters as $item) {
             /** @var Matcher $matcher */
@@ -249,7 +267,9 @@ function ($object) {
             }
         }
 
-        $property->setAccessible(true);
+        if (PHP_VERSION_ID < 80100) {
+            $property->setAccessible(true);
+        }
 
         // Ignore uninitialized properties (for PHP >7.4)
         if (method_exists($property, 'isInitialized') && !$property->isInitialized($object)) {
diff --git a/app/vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineCollectionFilter.php b/app/vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineCollectionFilter.php
index e6d937710..66e91e598 100644
--- a/app/vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineCollectionFilter.php
+++ b/app/vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineCollectionFilter.php
@@ -19,7 +19,9 @@ public function apply($object, $property, $objectCopier)
     {
         $reflectionProperty = ReflectionHelper::getProperty($object, $property);
 
-        $reflectionProperty->setAccessible(true);
+        if (PHP_VERSION_ID < 80100) {
+            $reflectionProperty->setAccessible(true);
+        }
         $oldCollection = $reflectionProperty->getValue($object);
 
         $newCollection = $oldCollection->map(
diff --git a/app/vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineEmptyCollectionFilter.php b/app/vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineEmptyCollectionFilter.php
index 7b33fd547..fa1c03418 100644
--- a/app/vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineEmptyCollectionFilter.php
+++ b/app/vendor/myclabs/deep-copy/src/DeepCopy/Filter/Doctrine/DoctrineEmptyCollectionFilter.php
@@ -21,7 +21,9 @@ class DoctrineEmptyCollectionFilter implements Filter
     public function apply($object, $property, $objectCopier)
     {
         $reflectionProperty = ReflectionHelper::getProperty($object, $property);
-        $reflectionProperty->setAccessible(true);
+        if (PHP_VERSION_ID < 80100) {
+            $reflectionProperty->setAccessible(true);
+        }
 
         $reflectionProperty->setValue($object, new ArrayCollection());
     }
diff --git a/app/vendor/myclabs/deep-copy/src/DeepCopy/Filter/ReplaceFilter.php b/app/vendor/myclabs/deep-copy/src/DeepCopy/Filter/ReplaceFilter.php
index 7aca593bb..fda8e726e 100644
--- a/app/vendor/myclabs/deep-copy/src/DeepCopy/Filter/ReplaceFilter.php
+++ b/app/vendor/myclabs/deep-copy/src/DeepCopy/Filter/ReplaceFilter.php
@@ -30,7 +30,9 @@ public function __construct(callable $callable)
     public function apply($object, $property, $objectCopier)
     {
         $reflectionProperty = ReflectionHelper::getProperty($object, $property);
-        $reflectionProperty->setAccessible(true);
+        if (PHP_VERSION_ID < 80100) {
+            $reflectionProperty->setAccessible(true);
+        }
 
         $value = call_user_func($this->callback, $reflectionProperty->getValue($object));
 
diff --git a/app/vendor/myclabs/deep-copy/src/DeepCopy/Filter/SetNullFilter.php b/app/vendor/myclabs/deep-copy/src/DeepCopy/Filter/SetNullFilter.php
index bea86b884..672227242 100644
--- a/app/vendor/myclabs/deep-copy/src/DeepCopy/Filter/SetNullFilter.php
+++ b/app/vendor/myclabs/deep-copy/src/DeepCopy/Filter/SetNullFilter.php
@@ -18,7 +18,9 @@ public function apply($object, $property, $objectCopier)
     {
         $reflectionProperty = ReflectionHelper::getProperty($object, $property);
 
-        $reflectionProperty->setAccessible(true);
+        if (PHP_VERSION_ID < 80100) {
+            $reflectionProperty->setAccessible(true);
+        }
         $reflectionProperty->setValue($object, null);
     }
 }
diff --git a/app/vendor/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyTypeMatcher.php b/app/vendor/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyTypeMatcher.php
index c7f46908c..7980bfa20 100644
--- a/app/vendor/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyTypeMatcher.php
+++ b/app/vendor/myclabs/deep-copy/src/DeepCopy/Matcher/PropertyTypeMatcher.php
@@ -39,7 +39,9 @@ public function matches($object, $property)
             return false;
         }
 
-        $reflectionProperty->setAccessible(true);
+        if (PHP_VERSION_ID < 80100) {
+            $reflectionProperty->setAccessible(true);
+        }
 
         // Uninitialized properties (for PHP >7.4)
         if (method_exists($reflectionProperty, 'isInitialized') && !$reflectionProperty->isInitialized($object)) {
diff --git a/app/vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/Date/DatePeriodFilter.php b/app/vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/Date/DatePeriodFilter.php
new file mode 100644
index 000000000..6bd2f7e57
--- /dev/null
+++ b/app/vendor/myclabs/deep-copy/src/DeepCopy/TypeFilter/Date/DatePeriodFilter.php
@@ -0,0 +1,42 @@
+= 80200 && $element->include_end_date) {
+            $options |= DatePeriod::INCLUDE_END_DATE;
+        }
+        if (!$element->include_start_date) {
+            $options |= DatePeriod::EXCLUDE_START_DATE;
+        }
+
+        if ($element->getEndDate()) {
+            return new DatePeriod($element->getStartDate(), $element->getDateInterval(), $element->getEndDate(), $options);
+        }
+
+        if (PHP_VERSION_ID >= 70217) {
+            $recurrences = $element->getRecurrences();
+        } else {
+            $recurrences = $element->recurrences - $element->include_start_date;
+        }
+
+        return new DatePeriod($element->getStartDate(), $element->getDateInterval(), $recurrences, $options);
+    }
+}
diff --git a/app/vendor/nikic/php-parser/README.md b/app/vendor/nikic/php-parser/README.md
index 36de23cde..3bca288b9 100644
--- a/app/vendor/nikic/php-parser/README.md
+++ b/app/vendor/nikic/php-parser/README.md
@@ -6,7 +6,7 @@ PHP Parser
 This is a PHP 5.2 to PHP 8.2 parser written in PHP. Its purpose is to simplify static code analysis and
 manipulation.
 
-[**Documentation for version 4.x**][doc_4_x] (stable; for running on PHP >= 7.0; for parsing PHP 5.2 to PHP 8.2).
+[**Documentation for version 4.x**][doc_4_x] (stable; for running on PHP >= 7.1; for parsing PHP 5.2 to PHP 8.2).
 
 [Documentation for version 3.x][doc_3_x] (unsupported; for running on PHP >= 5.5; for parsing PHP 5.2 to PHP 7.2).
 
diff --git a/app/vendor/nikic/php-parser/composer.json b/app/vendor/nikic/php-parser/composer.json
index 2fd064a21..6eef359e0 100644
--- a/app/vendor/nikic/php-parser/composer.json
+++ b/app/vendor/nikic/php-parser/composer.json
@@ -13,11 +13,11 @@
         }
     ],
     "require": {
-        "php": ">=7.0",
+        "php": ">=7.1",
         "ext-tokenizer": "*"
     },
     "require-dev": {
-        "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0",
+        "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
         "ircmaxell/php-yacc": "^0.0.7"
     },
     "extra": {
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/Builder/ClassConst.php b/app/vendor/nikic/php-parser/lib/PhpParser/Builder/ClassConst.php
index a7fe129b0..7c1512d07 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/Builder/ClassConst.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/Builder/ClassConst.php
@@ -26,7 +26,7 @@ class ClassConst implements PhpParser\Builder
      * Creates a class constant builder
      *
      * @param string|Identifier                          $name  Name
-     * @param Node\Expr|bool|null|int|float|string|array $value Value
+     * @param Node\Expr|bool|null|int|float|string|array|\UnitEnum $value Value
      */
     public function __construct($name, $value) {
         $this->constants = [new Const_($name, BuilderHelpers::normalizeValue($value))];
@@ -36,7 +36,7 @@ public function __construct($name, $value) {
      * Add another constant to const group
      *
      * @param string|Identifier                          $name  Name
-     * @param Node\Expr|bool|null|int|float|string|array $value Value
+     * @param Node\Expr|bool|null|int|float|string|array|\UnitEnum $value Value
      *
      * @return $this The builder instance (for fluid interface)
      */
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/BuilderFactory.php b/app/vendor/nikic/php-parser/lib/PhpParser/BuilderFactory.php
index af010e028..0aae8738c 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/BuilderFactory.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/BuilderFactory.php
@@ -213,7 +213,7 @@ public function enumCase($name) : Builder\EnumCase {
     /**
      * Creates node a for a literal value.
      *
-     * @param Expr|bool|null|int|float|string|array $value $value
+     * @param Expr|bool|null|int|float|string|array|\UnitEnum $value $value
      *
      * @return Expr
      */
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/BuilderHelpers.php b/app/vendor/nikic/php-parser/lib/PhpParser/BuilderHelpers.php
index af6ceb996..05e7868f4 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/BuilderHelpers.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/BuilderHelpers.php
@@ -6,6 +6,7 @@
 use PhpParser\Node\Expr;
 use PhpParser\Node\Identifier;
 use PhpParser\Node\Name;
+use PhpParser\Node\Name\FullyQualified;
 use PhpParser\Node\NullableType;
 use PhpParser\Node\Scalar;
 use PhpParser\Node\Stmt;
@@ -215,7 +216,7 @@ public static function normalizeType($type) {
      * Normalizes a value: Converts nulls, booleans, integers,
      * floats, strings and arrays into their respective nodes
      *
-     * @param Node\Expr|bool|null|int|float|string|array $value The value to normalize
+     * @param Node\Expr|bool|null|int|float|string|array|\UnitEnum $value The value to normalize
      *
      * @return Expr The normalized value
      */
@@ -269,6 +270,10 @@ public static function normalizeValue($value) : Expr {
             return new Expr\Array_($items);
         }
 
+        if ($value instanceof \UnitEnum) {
+            return new Expr\ClassConstFetch(new FullyQualified(\get_class($value)), new Identifier($value->name));
+        }
+
         throw new \LogicException('Invalid value');
     }
 
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/ConstExprEvaluator.php b/app/vendor/nikic/php-parser/lib/PhpParser/ConstExprEvaluator.php
index 7131c3d25..ceb3f11f3 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/ConstExprEvaluator.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/ConstExprEvaluator.php
@@ -37,7 +37,7 @@ class ConstExprEvaluator
      *
      * @param callable|null $fallbackEvaluator To call if subexpression cannot be evaluated
      */
-    public function __construct(callable $fallbackEvaluator = null) {
+    public function __construct(?callable $fallbackEvaluator = null) {
         $this->fallbackEvaluator = $fallbackEvaluator ?? function(Expr $expr) {
             throw new ConstExprEvaluationException(
                 "Expression of type {$expr->getType()} cannot be evaluated"
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/Internal/PrintableNewAnonClassNode.php b/app/vendor/nikic/php-parser/lib/PhpParser/Internal/PrintableNewAnonClassNode.php
index 676322701..fc276ecb9 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/Internal/PrintableNewAnonClassNode.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/Internal/PrintableNewAnonClassNode.php
@@ -31,7 +31,7 @@ class PrintableNewAnonClassNode extends Expr
     public $stmts;
 
     public function __construct(
-        array $attrGroups, int $flags, array $args, Node\Name $extends = null, array $implements,
+        array $attrGroups, int $flags, array $args, ?Node\Name $extends, array $implements,
         array $stmts, array $attributes
     ) {
         parent::__construct($attributes);
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/Lexer.php b/app/vendor/nikic/php-parser/lib/PhpParser/Lexer.php
index e15dd0a5d..60b809b8b 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/Lexer.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/Lexer.php
@@ -69,7 +69,7 @@ public function __construct(array $options = []) {
      * @param ErrorHandler|null $errorHandler Error handler to use for lexing errors. Defaults to
      *                                        ErrorHandler\Throwing
      */
-    public function startLexing(string $code, ErrorHandler $errorHandler = null) {
+    public function startLexing(string $code, ?ErrorHandler $errorHandler = null) {
         if (null === $errorHandler) {
             $errorHandler = new ErrorHandler\Throwing();
         }
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/Lexer/Emulative.php b/app/vendor/nikic/php-parser/lib/PhpParser/Lexer/Emulative.php
index b0929f3cc..a0e781d04 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/Lexer/Emulative.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/Lexer/Emulative.php
@@ -74,7 +74,7 @@ public function __construct(array $options = [])
         }
     }
 
-    public function startLexing(string $code, ErrorHandler $errorHandler = null) {
+    public function startLexing(string $code, ?ErrorHandler $errorHandler = null) {
         $emulators = array_filter($this->emulators, function($emulator) use($code) {
             return $emulator->isEmulationNeeded($code);
         });
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/NameContext.php b/app/vendor/nikic/php-parser/lib/PhpParser/NameContext.php
index 777a4afde..82c5acc2c 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/NameContext.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/NameContext.php
@@ -36,7 +36,7 @@ public function __construct(ErrorHandler $errorHandler) {
      *
      * @param Name|null $namespace Null is the global namespace
      */
-    public function startNamespace(Name $namespace = null) {
+    public function startNamespace(?Name $namespace = null) {
         $this->namespace = $namespace;
         $this->origAliases = $this->aliases = [
             Stmt\Use_::TYPE_NORMAL   => [],
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Arg.php b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Arg.php
index bcf130e68..17e680260 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Arg.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Arg.php
@@ -27,7 +27,7 @@ class Arg extends NodeAbstract
      */
     public function __construct(
         Expr $value, bool $byRef = false, bool $unpack = false, array $attributes = [],
-        Identifier $name = null
+        ?Identifier $name = null
     ) {
         $this->attributes = $attributes;
         $this->name = $name;
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ArrayDimFetch.php b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ArrayDimFetch.php
index 71694478e..46db975c4 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ArrayDimFetch.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ArrayDimFetch.php
@@ -18,7 +18,7 @@ class ArrayDimFetch extends Expr
      * @param null|Expr $dim        Array index / dim
      * @param array     $attributes Additional attributes
      */
-    public function __construct(Expr $var, Expr $dim = null, array $attributes = []) {
+    public function __construct(Expr $var, ?Expr $dim = null, array $attributes = []) {
         $this->attributes = $attributes;
         $this->var = $var;
         $this->dim = $dim;
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ArrayItem.php b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ArrayItem.php
index 1b078f821..5aaa9867e 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ArrayItem.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ArrayItem.php
@@ -23,7 +23,7 @@ class ArrayItem extends Expr
      * @param bool      $byRef      Whether to assign by reference
      * @param array     $attributes Additional attributes
      */
-    public function __construct(Expr $value, Expr $key = null, bool $byRef = false, array $attributes = [], bool $unpack = false) {
+    public function __construct(Expr $value, ?Expr $key = null, bool $byRef = false, array $attributes = [], bool $unpack = false) {
         $this->attributes = $attributes;
         $this->key = $key;
         $this->value = $value;
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Exit_.php b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Exit_.php
index b88a8f7e6..5469b8e4c 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Exit_.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Exit_.php
@@ -19,7 +19,7 @@ class Exit_ extends Expr
      * @param null|Expr $expr       Expression
      * @param array                    $attributes Additional attributes
      */
-    public function __construct(Expr $expr = null, array $attributes = []) {
+    public function __construct(?Expr $expr = null, array $attributes = []) {
         $this->attributes = $attributes;
         $this->expr = $expr;
     }
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Yield_.php b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Yield_.php
index aef8fc333..f15336ede 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Yield_.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Yield_.php
@@ -18,7 +18,7 @@ class Yield_ extends Expr
      * @param null|Expr $key        Key expression
      * @param array     $attributes Additional attributes
      */
-    public function __construct(Expr $value = null, Expr $key = null, array $attributes = []) {
+    public function __construct(?Expr $value = null, ?Expr $key = null, array $attributes = []) {
         $this->attributes = $attributes;
         $this->key = $key;
         $this->value = $value;
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Name.php b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Name.php
index f0a564ff0..0d6e4b1ff 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Name.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Name.php
@@ -162,7 +162,7 @@ public function __toString() : string {
      *
      * @return static|null Sliced name
      */
-    public function slice(int $offset, int $length = null) {
+    public function slice(int $offset, ?int $length = null) {
         $numParts = count($this->parts);
 
         $realOffset = $offset < 0 ? $offset + $numParts : $offset;
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Param.php b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Param.php
index 1e90b7944..dfb77f629 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Param.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Param.php
@@ -34,7 +34,7 @@ class Param extends NodeAbstract
      * @param AttributeGroup[]                        $attrGroups PHP attribute groups
      */
     public function __construct(
-        $var, Expr $default = null, $type = null,
+        $var, ?Expr $default = null, $type = null,
         bool $byRef = false, bool $variadic = false,
         array $attributes = [],
         int $flags = 0,
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Break_.php b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Break_.php
index 6adc5a6c6..d9464a1ae 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Break_.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Break_.php
@@ -15,7 +15,7 @@ class Break_ extends Node\Stmt
      * @param null|Node\Expr $num        Number of loops to break
      * @param array          $attributes Additional attributes
      */
-    public function __construct(Node\Expr $num = null, array $attributes = []) {
+    public function __construct(?Node\Expr $num = null, array $attributes = []) {
         $this->attributes = $attributes;
         $this->num = $num;
     }
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Catch_.php b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Catch_.php
index 9b9c09478..5d7b5c016 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Catch_.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Catch_.php
@@ -23,7 +23,7 @@ class Catch_ extends Node\Stmt
      * @param array                 $attributes Additional attributes
      */
     public function __construct(
-        array $types, Expr\Variable $var = null, array $stmts = [], array $attributes = []
+        array $types, ?Expr\Variable $var = null, array $stmts = [], array $attributes = []
     ) {
         $this->attributes = $attributes;
         $this->types = $types;
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Continue_.php b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Continue_.php
index 24882683b..f2b30d79f 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Continue_.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Continue_.php
@@ -15,7 +15,7 @@ class Continue_ extends Node\Stmt
      * @param null|Node\Expr $num        Number of loops to continue
      * @param array          $attributes Additional attributes
      */
-    public function __construct(Node\Expr $num = null, array $attributes = []) {
+    public function __construct(?Node\Expr $num = null, array $attributes = []) {
         $this->attributes = $attributes;
         $this->num = $num;
     }
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Declare_.php b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Declare_.php
index f46ff0baf..a3a5bfaa5 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Declare_.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Declare_.php
@@ -18,7 +18,7 @@ class Declare_ extends Node\Stmt
      * @param Node\Stmt[]|null $stmts      Statements
      * @param array            $attributes Additional attributes
      */
-    public function __construct(array $declares, array $stmts = null, array $attributes = []) {
+    public function __construct(array $declares, ?array $stmts = null, array $attributes = []) {
         $this->attributes = $attributes;
         $this->declares = $declares;
         $this->stmts = $stmts;
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/EnumCase.php b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/EnumCase.php
index 5beff8b39..4b1079bcd 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/EnumCase.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/EnumCase.php
@@ -20,7 +20,7 @@ class EnumCase extends Node\Stmt
      * @param AttributeGroup[]          $attrGroups PHP attribute groups
      * @param array                     $attributes Additional attributes
      */
-    public function __construct($name, Node\Expr $expr = null, array $attrGroups = [], array $attributes = []) {
+    public function __construct($name, ?Node\Expr $expr = null, array $attrGroups = [], array $attributes = []) {
         parent::__construct($attributes);
         $this->name = \is_string($name) ? new Node\Identifier($name) : $name;
         $this->expr = $expr;
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Namespace_.php b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Namespace_.php
index c63204577..fc249161a 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Namespace_.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Namespace_.php
@@ -22,7 +22,7 @@ class Namespace_ extends Node\Stmt
      * @param null|Node\Stmt[] $stmts      Statements
      * @param array            $attributes Additional attributes
      */
-    public function __construct(Node\Name $name = null, $stmts = [], array $attributes = []) {
+    public function __construct(?Node\Name $name = null, $stmts = [], array $attributes = []) {
         $this->attributes = $attributes;
         $this->name = $name;
         $this->stmts = $stmts;
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/PropertyProperty.php b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/PropertyProperty.php
index 205731e20..286b42961 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/PropertyProperty.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/PropertyProperty.php
@@ -18,7 +18,7 @@ class PropertyProperty extends Node\Stmt
      * @param null|Node\Expr                $default    Default value
      * @param array                         $attributes Additional attributes
      */
-    public function __construct($name, Node\Expr $default = null, array $attributes = []) {
+    public function __construct($name, ?Node\Expr $default = null, array $attributes = []) {
         $this->attributes = $attributes;
         $this->name = \is_string($name) ? new Node\VarLikeIdentifier($name) : $name;
         $this->default = $default;
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Return_.php b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Return_.php
index efc578c58..53731254c 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Return_.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Return_.php
@@ -15,7 +15,7 @@ class Return_ extends Node\Stmt
      * @param null|Node\Expr $expr       Expression
      * @param array          $attributes Additional attributes
      */
-    public function __construct(Node\Expr $expr = null, array $attributes = []) {
+    public function __construct(?Node\Expr $expr = null, array $attributes = []) {
         $this->attributes = $attributes;
         $this->expr = $expr;
     }
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/StaticVar.php b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/StaticVar.php
index 29584560d..0cc47b412 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/StaticVar.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/StaticVar.php
@@ -20,7 +20,7 @@ class StaticVar extends Node\Stmt
      * @param array          $attributes Additional attributes
      */
     public function __construct(
-        Expr\Variable $var, Node\Expr $default = null, array $attributes = []
+        Expr\Variable $var, ?Node\Expr $default = null, array $attributes = []
     ) {
         $this->attributes = $attributes;
         $this->var = $var;
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TryCatch.php b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TryCatch.php
index 7fc158c57..74e004380 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TryCatch.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TryCatch.php
@@ -21,7 +21,7 @@ class TryCatch extends Node\Stmt
      * @param null|Finally_ $finally    Optional finally node
      * @param array         $attributes Additional attributes
      */
-    public function __construct(array $stmts, array $catches, Finally_ $finally = null, array $attributes = []) {
+    public function __construct(array $stmts, array $catches, ?Finally_ $finally = null, array $attributes = []) {
         $this->attributes = $attributes;
         $this->stmts = $stmts;
         $this->catches = $catches;
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/NodeDumper.php b/app/vendor/nikic/php-parser/lib/PhpParser/NodeDumper.php
index ba622efd1..e0c7f783a 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/NodeDumper.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/NodeDumper.php
@@ -39,7 +39,7 @@ public function __construct(array $options = []) {
      *
      * @return string Dumped value
      */
-    public function dump($node, string $code = null) : string {
+    public function dump($node, ?string $code = null) : string {
         $this->code = $code;
         return $this->dumpRecursive($node);
     }
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/NameResolver.php b/app/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/NameResolver.php
index 83f3ea831..dd2e9ca76 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/NameResolver.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/NameResolver.php
@@ -35,7 +35,7 @@ class NameResolver extends NodeVisitorAbstract
      * @param ErrorHandler|null $errorHandler Error handler
      * @param array $options Options
      */
-    public function __construct(ErrorHandler $errorHandler = null, array $options = []) {
+    public function __construct(?ErrorHandler $errorHandler = null, array $options = []) {
         $this->nameContext = new NameContext($errorHandler ?? new ErrorHandler\Throwing);
         $this->preserveOriginalNames = $options['preserveOriginalNames'] ?? false;
         $this->replaceNodes = $options['replaceNodes'] ?? true;
@@ -164,7 +164,7 @@ public function enterNode(Node $node) {
         return null;
     }
 
-    private function addAlias(Stmt\UseUse $use, int $type, Name $prefix = null) {
+    private function addAlias(Stmt\UseUse $use, int $type, ?Name $prefix = null) {
         // Add prefix for group uses
         $name = $prefix ? Name::concat($prefix, $use->name) : $use->name;
         // Type is determined either by individual element or whole use declaration
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/Parser.php b/app/vendor/nikic/php-parser/lib/PhpParser/Parser.php
index 8956c7671..7236c68e2 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/Parser.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/Parser.php
@@ -14,5 +14,5 @@ interface Parser
      * @return Node\Stmt[]|null Array of statements (or null non-throwing error handler is used and
      *                          the parser was unable to recover from an error).
      */
-    public function parse(string $code, ErrorHandler $errorHandler = null);
+    public function parse(string $code, ?ErrorHandler $errorHandler = null);
 }
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/Parser/Multiple.php b/app/vendor/nikic/php-parser/lib/PhpParser/Parser/Multiple.php
index 77fd1f3fb..083ff465d 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/Parser/Multiple.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/Parser/Multiple.php
@@ -24,7 +24,7 @@ public function __construct(array $parsers) {
         $this->parsers = $parsers;
     }
 
-    public function parse(string $code, ErrorHandler $errorHandler = null) {
+    public function parse(string $code, ?ErrorHandler $errorHandler = null) {
         if (null === $errorHandler) {
             $errorHandler = new ErrorHandler\Throwing;
         }
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/Parser/Php5.php b/app/vendor/nikic/php-parser/lib/PhpParser/Parser/Php5.php
index 59bd1e8cf..80ebdfb37 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/Parser/Php5.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/Parser/Php5.php
@@ -27,7 +27,7 @@ class Php5 extends \PhpParser\ParserAbstract
     protected $unexpectedTokenRule = 32767;
 
     protected $YY2TBLSTATE = 415;
-    protected $numNonLeafStates = 663;
+    protected $numNonLeafStates = 664;
 
     protected $symbolToName = array(
         "EOF",
@@ -244,116 +244,116 @@ class Php5 extends \PhpParser\ParserAbstract
     );
 
     protected $action = array(
-          700,  670,  671,  672,  673,  674,  286,  675,  676,  677,
-          713,  714,  223,  224,  225,  226,  227,  228,  229,  230,
+          701,  671,  672,  673,  674,  675,  286,  676,  677,  678,
+          714,  715,  223,  224,  225,  226,  227,  228,  229,  230,
           231,  232,    0,  233,  234,  235,  236,  237,  238,  239,
           240,  241,  242,  243,  244,-32766,-32766,-32766,-32766,-32766,
         -32766,-32766,-32766,-32766,-32767,-32767,-32767,-32767,  245,  246,
-          242,  243,  244,-32766,-32766,  678,-32766,-32766,-32766,-32766,
-        -32766,-32766,-32766,-32766,-32766, 1229,  245,  246, 1230,  679,
-          680,  681,  682,  683,  684,  685,  899,  900,  747,-32766,
-        -32766,-32766,-32766,-32766,-32766,  686,  687,  688,  689,  690,
-          691,  692,  693,  694,  695,  696,  716,  739,  717,  718,
-          719,  720,  708,  709,  710,  738,  711,  712,  697,  698,
-          699,  701,  702,  703,  741,  742,  743,  744,  745,  746,
-          875,  704,  705,  706,  707,  737,  728,  726,  727,  723,
-          724, 1046,  715,  721,  722,  729,  730,  732,  731,  733,
-          734,   55,   56,  425,   57,   58,  725,  736,  735,  755,
+          242,  243,  244,-32766,-32766,  679,-32766,-32766,-32766,-32766,
+        -32766,-32766,-32766,-32766,-32766, 1230,  245,  246, 1231,  680,
+          681,  682,  683,  684,  685,  686,  900,  901,  748,-32766,
+        -32766,-32766,-32766,-32766,-32766,  687,  688,  689,  690,  691,
+          692,  693,  694,  695,  696,  697,  717,  740,  718,  719,
+          720,  721,  709,  710,  711,  739,  712,  713,  698,  699,
+          700,  702,  703,  704,  742,  743,  744,  745,  746,  747,
+          876,  705,  706,  707,  708,  738,  729,  727,  728,  724,
+          725, 1047,  716,  722,  723,  730,  731,  733,  732,  734,
+          735,   55,   56,  425,   57,   58,  726,  737,  736,  756,
            59,   60, -226,   61,-32766,-32766,-32766,-32766,-32766,-32766,
         -32766,-32766,-32766,-32766,  337,-32767,-32767,-32767,-32767,   29,
           107,  108,  109,  110,  111,  112,  113,  114,  115,  116,
-          117,  118,  119,  620,-32766,-32766,-32766,-32766,   62,   63,
-         1046,-32766,-32766,-32766,   64,  419,   65,  294,  295,   66,
-           67,   68,   69,   70,   71,   72,   73,  823,   25,  302,
-           74,  418,  984,  986,  669,  668, 1100, 1101, 1078,  755,
-          755,  767, 1220,  768,  470,-32766,-32766,-32766,  341,  749,
-          824,   54,-32767,-32767,-32767,-32767,   98,   99,  100,  101,
-          102,  220,  221,  222,  362,  876,-32766,   27,-32766,-32766,
-        -32766,-32766,-32766, 1046,  493,  126, 1080, 1079, 1081,  370,
-         1068,  930,  207,  478,  479,  952,  953,  954,  951,  950,
-          949,  128,  480,  481,  803, 1106, 1107, 1108, 1109, 1103,
-         1104,  319,   32,  297,   10,  211, -515, 1110, 1105,  669,
-          668, 1080, 1079, 1081,  220,  221,  222,   41,  364,  341,
-          334,  421,  336,  426, -128, -128, -128,  313, 1046,  469,
-           -4,  824,   54,  812,  770,  207,   40,   21,  427, -128,
-          471, -128,  472, -128,  473, -128, 1046,  428,  220,  221,
+          117,  118,  119,  621,-32766,-32766,-32766,-32766,   62,   63,
+         1047,-32766,-32766,-32766,   64,  419,   65,  294,  295,   66,
+           67,   68,   69,   70,   71,   72,   73,  824,   25,  302,
+           74,  418,  985,  987,  670,  669, 1101, 1102, 1079,  756,
+          756,  768, 1221,  769,  470,-32766,-32766,-32766,  341,  750,
+          825,   54,-32767,-32767,-32767,-32767,   98,   99,  100,  101,
+          102,  220,  221,  222,  362,  877,-32766,   27,-32766,-32766,
+        -32766,-32766,-32766, 1047,  492,  126, 1081, 1080, 1082,  370,
+         1069,  931,  207,  478,  479,  953,  954,  955,  952,  951,
+          950,  128,  480,  481,  804, 1107, 1108, 1109, 1110, 1104,
+         1105,  319,   32,  297,   10,  211, -515, 1111, 1106,  670,
+          669, 1081, 1080, 1082,  220,  221,  222,   41,  364,  341,
+          334,  421,  336,  426, -128, -128, -128,  313, 1047,  469,
+           -4,  825,   54,  813,  597,  207,   40,   21,  427, -128,
+          471, -128,  472, -128,  473, -128, 1047,  428,  220,  221,
           222,-32766,   33,   34,  429,  361,  327,   52,   35,  474,
         -32766,-32766,-32766,  342,  357,  358,  475,  476,   48,  207,
-          249,  669,  668,  477,  443,  300,  795,  846,  430,  431,
-           28,-32766,  814,-32766,-32766,-32766,-32766,-32766,-32766,-32766,
-        -32767,-32767,-32767,-32767,-32767,  952,  953,  954,  951,  950,
-          949,  422,  755,  424,  426,  826,  634, -128,-32766,-32766,
-          469,  824,   54,  288,  812, 1151,  755,   40,   21,  427,
-          317,  471,  345,  472,  129,  473,    9, 1186,  428,  769,
-          360,  324,  905,   33,   34,  429,  361, 1046,  415,   35,
-          474,  944, 1068,  315,  125,  357,  358,  475,  476,-32766,
-        -32766,-32766,  926,  302,  477,  121, 1068,  759,  846,  430,
-          431,  669,  668,  423,  755, 1152,  809, 1046,  480,  766,
-        -32766,  805,-32766,-32766,-32766,-32766, -261,  127,  347,  436,
-          841,  341, 1078, 1200,  426,  446,  826,  634,   -4,  807,
-          469,  824,   54,  436,  812,  341,  755,   40,   21,  427,
-          444,  471,  130,  472, 1068,  473,  346,  767,  428,  768,
-         -211, -211, -211,   33,   34,  429,  361,  308, 1076,   35,
-          474,-32766,-32766,-32766, 1046,  357,  358,  475,  476,-32766,
-        -32766,-32766,  906,  120,  477,  539, 1068,  795,  846,  430,
-          431,  436,-32766,  341,-32766,-32766,-32766, 1046,  480,  810,
-        -32766,  925,-32766,-32766,  754, 1080, 1079, 1081,   49,-32766,
-        -32766,-32766,  749,  751,  426, 1201,  826,  634, -211,   30,
-          469,  669,  668,  436,  812,  341,   75,   40,   21,  427,
-        -32766,  471, 1064,  472,  124,  473,  669,  668,  428,  212,
-         -210, -210, -210,   33,   34,  429,  361,   51, 1186,   35,
-          474,  755,-32766,-32766,-32766,  357,  358,  475,  476,  213,
-          824,   54,  221,  222,  477,   20,  581,  795,  846,  430,
-          431,  220,  221,  222,  755,  222,  247,   78,   79,   80,
-           81,  341,  207,  517,  103,  104,  105,  752,  307,  131,
-          637, 1068,  207,  341,  207,  122,  826,  634, -210,   36,
+          249,  670,  669,  477,  443,  300,  796,  847,  430,  431,
+           28,-32766,  815,-32766,-32766,-32766,-32766,-32766,-32766,-32766,
+        -32767,-32767,-32767,-32767,-32767,  953,  954,  955,  952,  951,
+          950,  422,  756,  424,  426,  827,  635, -128,-32766,-32766,
+          469,  825,   54,  288,  813, 1152,  756,   40,   21,  427,
+          317,  471,  345,  472,  129,  473,    9, 1187,  428,  612,
+          360,  324,  906,   33,   34,  429,  361, 1047,  415,   35,
+          474,  945, 1069,  315,  125,  357,  358,  475,  476,-32766,
+        -32766,-32766,  927,  302,  477,  121, 1069,  760,  847,  430,
+          431,  670,  669,  423,  756, 1153,  810, 1047,  480,  767,
+        -32766,  806,-32766,-32766,-32766,-32766, -261,  127,  347,  436,
+          842,  341, 1079, 1201,  426,  446,  827,  635,   -4,  808,
+          469,  825,   54,  436,  813,  341,  756,   40,   21,  427,
+          444,  471,  130,  472, 1069,  473,  346,  768,  428,  769,
+         -211, -211, -211,   33,   34,  429,  361,  308, 1077,   35,
+          474,-32766,-32766,-32766, 1047,  357,  358,  475,  476,-32766,
+        -32766,-32766,  907,  120,  477,  538, 1069,  796,  847,  430,
+          431,  436,-32766,  341,-32766,-32766,-32766, 1047,  480,  811,
+        -32766,  926,-32766,-32766,  755, 1081, 1080, 1082,   49,-32766,
+        -32766,-32766,  750,  752,  426, 1202,  827,  635, -211,   30,
+          469,  670,  669,  436,  813,  341,   75,   40,   21,  427,
+        -32766,  471, 1065,  472,  124,  473,  670,  669,  428,  212,
+         -210, -210, -210,   33,   34,  429,  361,   51, 1187,   35,
+          474,  756,-32766,-32766,-32766,  357,  358,  475,  476,  213,
+          825,   54,  221,  222,  477,   20,  580,  796,  847,  430,
+          431,  220,  221,  222,  756,  222,  247,   78,   79,   80,
+           81,  341,  207,  516,  103,  104,  105,  753,  307,  131,
+          638, 1069,  207,  341,  207,  122,  827,  635, -210,   36,
           106,   82,   83,   84,   85,   86,   87,   88,   89,   90,
            91,   92,   93,   94,   95,   96,   97,   98,   99,  100,
-          101,  102,  103,  104,  105, 1112,  307,  346,  436,  214,
-          341,  824,   54,  426,  123,  250,  129,  134,  106,  469,
-        -32766,  572, 1112,  812,  245,  246,   40,   21,  427,  251,
-          471,  252,  472,  341,  473,  453,   22,  428,  207,  899,
-          900,  638,   33,   34,  429,  824,   54,  -86,   35,  474,
+          101,  102,  103,  104,  105, 1113,  307,  346,  436,  214,
+          341,  825,   54,  426,  123,  250,  129,  134,  106,  469,
+        -32766,  571, 1113,  813,  245,  246,   40,   21,  427,  251,
+          471,  252,  472,  341,  473,  453,   22,  428,  207,  900,
+          901,  639,   33,   34,  429,  825,   54,  -86,   35,  474,
           220,  221,  222,  314,  357,  358,  100,  101,  102,  239,
-          240,  241,  645,  477, -230,  458,  589,  135,  374,  596,
-          597,  207,  760,  640,  648,  642,  941,  654,  929,  662,
-          822,  133,  307,  837,  426,-32766,  106,  749,   43,   44,
-          469,   45,  442,   46,  812,  826,  634,   40,   21,  427,
+          240,  241,  646,  477, -230,  458,  588,  135,  374,  595,
+          596,  207,  761,  641,  649,  643,  942,  655,  930,  663,
+          823,  133,  307,  838,  426,-32766,  106,  750,   43,   44,
+          469,   45,  442,   46,  813,  827,  635,   40,   21,  427,
            47,  471,   50,  472,   53,  473,  132,  608,  428,  302,
-          604, -280,-32766,   33,   34,  429,  824,   54,  426,   35,
-          474,  755,  957,  -84,  469,  357,  358,  521,  812,  628,
-          363,   40,   21,  427,  477,  471,  575,  472, -515,  473,
-          847,  616,  428, -423,-32766,   11,  646,   33,   34,  429,
-          824,   54,  445,   35,  474,  462,  285,  578, 1111,  357,
-          358,  593,  369,  848,  594,  290,  826,  634,  477,    0,
-            0,  532,    0,    0,  325,    0,    0,    0,    0,    0,
-          651,    0,    0,    0,  322,  326,    0,    0,    0,  426,
-            0,    0,    0,    0,  323,  469,  316,  318, -516,  812,
-          862,  634,   40,   21,  427,    0,  471,    0,  472,    0,
-          473, 1158,    0,  428,    0, -414,    6,    7,   33,   34,
-          429,  824,   54,  426,   35,  474,   12,   14,  373,  469,
-          357,  358, -424,  812,  563,  754,   40,   21,  427,  477,
-          471,  248,  472,  839,  473,   38,   39,  428,  657,  658,
-          765,  813,   33,   34,  429,  821,  800,  815,   35,  474,
-          215,  216,  878,  869,  357,  358,  217,  870,  218,  798,
-          863,  826,  634,  477,  860,  858,  936,  937,  934,  820,
-          209,  804,  806,  808,  811,  933,  763,  764, 1100, 1101,
-          935,  659,   78,  335,  426,  359, 1102,  635,  639,  641,
-          469,  643,  644,  647,  812,  826,  634,   40,   21,  427,
-          649,  471,  650,  472,  652,  473,  653,  636,  428,  796,
-         1226, 1228,  762,   33,   34,  429,  215,  216,  845,   35,
-          474,  761,  217,  844,  218,  357,  358, 1227,  843, 1060,
-          831, 1048,  842, 1049,  477,  559,  209, 1106, 1107, 1108,
-         1109, 1103, 1104,  398, 1100, 1101,  829,  942,  867, 1110,
-         1105,  868, 1102,  457, 1225, 1194, 1192, 1177, 1157,  219,
-         1190, 1091,  917, 1198, 1188,    0,  826,  634,   24, -433,
-           26,   31,   37,   42,   76,   77,  210,  287,  292,  293,
+          604, -280,-32766,   33,   34,  429,  825,   54,  426,   35,
+          474,  756,  958,  -84,  469,  357,  358,  520,  813,  629,
+          363,   40,   21,  427,  477,  471,  574,  472, -515,  473,
+          848,  617,  428, -423,-32766,   11,  647,   33,   34,  429,
+          825,   54,  445,   35,  474,  462,  285,  577, 1112,  357,
+          358,  592,  369,  849,  593,  290,  827,  635,  477,    0,
+            0,  531,    0,    0,  325,    0,    0,    0,    0,    0,
+          652,    0,    0,    0,  322,  326,    0,    0,    0,  426,
+            0,    0,    0,    0,  323,  469,  316,  318, -516,  813,
+          863,  635,   40,   21,  427,    0,  471,    0,  472,    0,
+          473, 1159,    0,  428,    0, -414,    6,    7,   33,   34,
+          429,  825,   54,  426,   35,  474,   12,   14,  373,  469,
+          357,  358, -424,  813,  562,  755,   40,   21,  427,  477,
+          471,  248,  472,  840,  473,   38,   39,  428,  658,  659,
+          814,  822,   33,   34,  429,  801,  816,  879,   35,  474,
+          215,  216,  870,  871,  357,  358,  217,  771,  218,  799,
+          864,  827,  635,  477,  770,  861,  859,  937,  938,  935,
+          209,  821,  805,  807,  809,  812,  934,  764, 1101, 1102,
+          765,  936,   24,   78,  426,  335, 1103,  359,  636,  640,
+          469,  642,  644,  645,  813,  827,  635,   40,   21,  427,
+          648,  471,  650,  472,  651,  473,  653,  654,  428,  637,
+           26,  660,  797,   33,   34,  429,  215,  216, 1227,   35,
+          474, 1229,  217,  763,  218,  357,  358,  846,  762,  845,
+         1228,  844, 1061,  832,  477,  558,  209, 1107, 1108, 1109,
+         1110, 1104, 1105,  398, 1101, 1102, 1049,  843, 1050, 1111,
+         1106,  830, 1103,  943,  868,  869,  457, 1226, 1158,  219,
+         1195, 1193, 1178, 1191, 1092,  918,  827,  635,   31, 1199,
+         1189, 1056,   37,   42,   76,   77,  210,  287,  292,  293,
           308,  309,  310,  311,  339,  356,  416,    0, -227, -226,
-           16,   17,   18,  393,  454,  461,  463,  467,  553,  625,
-         1051,  559, 1054, 1106, 1107, 1108, 1109, 1103, 1104,  398,
-          907, 1116, 1050, 1026,  564, 1110, 1105, 1025, 1093, 1055,
-            0, 1044,    0, 1057, 1056,  219, 1059, 1058, 1075,    0,
-         1191, 1176, 1172, 1189, 1090, 1223, 1117, 1171,  600
+           16,   17,   18,  393,  454,  461,  463,  467,  552,  626,
+         1052,  558, 1055, 1107, 1108, 1109, 1110, 1104, 1105,  398,
+          908, 1117, 1051, 1027,  563, 1111, 1106, 1026, 1094, 1058,
+            0, -433, 1045,    0, 1057,  219, 1060, 1059, 1076,    0,
+         1192, 1177, 1173, 1190, 1091, 1224, 1118, 1172,  600
     );
 
     protected $actionCheck = array(
@@ -451,26 +451,26 @@ class Php5 extends \PhpParser\ParserAbstract
            50,   51,  156,  156,  115,  116,   56,  156,   58,  156,
           156,  156,  157,  124,  156,  156,  156,  156,  156,  156,
            70,  156,  156,  156,  156,  156,  156,  156,   78,   79,
-          156,  158,  157,  157,   74,  157,   86,  157,  157,  157,
+          156,  156,  159,  157,   74,  157,   86,  157,  157,  157,
            80,  157,  157,  157,   84,  156,  157,   87,   88,   89,
-          157,   91,  157,   93,  157,   95,  157,  157,   98,  158,
-          158,  158,  158,  103,  104,  105,   50,   51,  158,  109,
+          157,   91,  157,   93,  157,   95,  157,  157,   98,  157,
+          159,  158,  158,  103,  104,  105,   50,   51,  158,  109,
           110,  158,   56,  158,   58,  115,  116,  158,  158,  158,
           158,  158,  158,  158,  124,  135,   70,  137,  138,  139,
           140,  141,  142,  143,   78,   79,  158,  158,  158,  149,
           150,  158,   86,  158,  158,  158,  158,  158,  164,  159,
-          158,  158,  158,  158,  158,   -1,  156,  157,  159,  162,
-          159,  159,  159,  159,  159,  159,  159,  159,  159,  159,
+          158,  158,  158,  158,  158,  158,  156,  157,  159,  158,
+          158,  163,  159,  159,  159,  159,  159,  159,  159,  159,
           159,  159,  159,  159,  159,  159,  159,   -1,  160,  160,
           160,  160,  160,  160,  160,  160,  160,  160,  160,  160,
           160,  135,  160,  137,  138,  139,  140,  141,  142,  143,
           160,  160,  160,  160,  160,  149,  150,  160,  160,  163,
-           -1,  162,   -1,  163,  163,  159,  163,  163,  163,   -1,
+           -1,  162,  162,   -1,  163,  159,  163,  163,  163,   -1,
           163,  163,  163,  163,  163,  163,  163,  163,  163
     );
 
     protected $actionBase = array(
-            0,  229,  310,  390,  470,  103,  325,  325,  784,   -2,
+            0,  229,  310,  390,  470,  103,  325,  325,  785,   -2,
            -2,  149,   -2,   -2,   -2,  660,  765,  799,  765,  589,
           694,  870,  870,  870,  252,  404,  404,  404,  514,  177,
           177,  918,  434,  118,  295,  313,  240,  491,  491,  491,
@@ -483,9 +483,9 @@ class Php5 extends \PhpParser\ParserAbstract
           491,  491,  491,  491,  491,  491,  491,  491,  491,  491,
           491,  491,  491,  491,  491,  491,  491,  491,  491,  491,
           491,  491,  491,  491,  491,  491,  491,  491,  491,  491,
-          491,  491,  491,  491,  491,  491,   89,  206,  773,  550,
-          535,  775,  776,  777,  912,  709,  913,  856,  857,  700,
-          858,  859,  862,  863,  864,  855,  865,  935,  866,  599,
+          491,  491,  491,  491,  491,  491,   89,  206,  775,  550,
+          535,  776,  777,  778,  912,  709,  913,  859,  862,  700,
+          863,  864,  865,  866,  867,  858,  871,  935,  872,  599,
           599,  599,  599,  599,  599,  599,  599,  599,  599,  599,
           599,  322,  592,  285,  319,  232,   44,  691,  691,  691,
           691,  691,  691,  691,  182,  182,  182,  182,  182,  182,
@@ -504,43 +504,44 @@ class Php5 extends \PhpParser\ParserAbstract
           554,  554,  679,  -59,  -59,  381,  462,  462,  462,  528,
           717,  854,  382,  382,  382,  382,  382,  382,  561,  561,
           561,   -3,   -3,   -3,  692,  115,  137,  115,  137,  678,
-          732,  450,  732,  338,  677,  -15,  510,  810,  468,  707,
-          850,  711,  853,  572,  735,  267,  529,  654,  674,  463,
+          732,  450,  732,  338,  677,  -15,  510,  812,  468,  707,
+          856,  711,  857,  572,  735,  267,  529,  654,  674,  463,
           529,  529,  529,  529,  654,  610,  640,  608,  463,  529,
-          463,  718,  323,  496,   89,  570,  507,  675,  778,  293,
-          670,  780,  290,  373,  332,  566,  278,  435,  733,  781,
+          463,  718,  323,  496,   89,  570,  507,  675,  779,  293,
+          670,  781,  290,  373,  332,  566,  278,  435,  733,  784,
           914,  917,  385,  715,  675,  675,  675,  352,  511,  278,
            -8,  605,  605,  605,  605,  156,  605,  605,  605,  605,
-          251,  276,  375,  402,  779,  657,  657,  690,  872,  869,
-          869,  657,  689,  657,  690,  874,  874,  874,  874,  657,
-          657,  657,  657,  869,  869,  869,  688,  869,  239,  703,
-          704,  704,  874,  742,  743,  657,  657,  712,  869,  869,
-          869,  712,  695,  874,  701,  741,  277,  869,  874,  672,
+          251,  276,  375,  402,  780,  657,  657,  690,  869,  783,
+          783,  657,  689,  657,  690,  874,  874,  874,  874,  657,
+          657,  657,  657,  783,  783,  783,  688,  783,  239,  703,
+          704,  704,  874,  742,  743,  657,  657,  712,  783,  783,
+          783,  712,  695,  874,  701,  741,  277,  783,  874,  672,
           689,  672,  657,  701,  672,  689,  689,  672,   22,  666,
-          668,  873,  875,  887,  790,  662,  685,  879,  880,  876,
-          878,  871,  699,  744,  745,  497,  669,  671,  673,  680,
-          719,  682,  713,  674,  667,  667,  667,  655,  720,  655,
-          667,  667,  667,  667,  667,  667,  667,  667,  916,  646,
-          731,  714,  653,  749,  553,  573,  791,  664,  811,  900,
-          893,  867,  919,  881,  898,  655,  920,  739,  247,  643,
-          882,  783,  786,  655,  883,  655,  792,  655,  902,  812,
-          686,  813,  814,  667,  910,  921,  923,  924,  925,  927,
-          928,  929,  930,  684,  931,  750,  696,  894,  299,  877,
-          718,  729,  705,  788,  751,  820,  328,  932,  823,  655,
-          655,  794,  785,  655,  795,  756,  740,  890,  757,  895,
-          933,  664,  708,  896,  655,  706,  825,  934,  328,  681,
-          683,  888,  661,  761,  886,  911,  885,  796,  649,  663,
-          829,  830,  831,  693,  763,  891,  892,  889,  764,  803,
-          665,  805,  697,  832,  807,  884,  768,  833,  834,  899,
-          676,  730,  710,  698,  687,  809,  835,  897,  769,  770,
-          771,  848,  772,  849,    0,    0,    0,    0,    0,    0,
+          668,  873,  875,  887,  791,  662,  685,  879,  880,  876,
+          878,  811,  699,  744,  497,  669,  671,  673,  680,  719,
+          682,  713,  674,  667,  667,  667,  655,  720,  655,  667,
+          667,  667,  667,  667,  667,  667,  667,  868,  646,  731,
+          714,  653,  745,  553,  573,  792,  664,  814,  900,  893,
+          919,  920,  881,  898,  655,  916,  739,  247,  643,  882,
+          813,  788,  655,  883,  655,  794,  655,  902,  820,  686,
+          823,  825,  667,  910,  921,  923,  924,  925,  927,  928,
+          929,  930,  684,  931,  749,  696,  894,  299,  877,  718,
+          729,  705,  790,  750,  829,  328,  932,  830,  655,  655,
+          795,  786,  655,  796,  751,  740,  890,  756,  895,  933,
+          664,  708,  896,  655,  706,  831,  934,  328,  681,  683,
+          888,  661,  757,  886,  911,  885,  803,  761,  649,  663,
+          832,  833,  834,  693,  763,  891,  892,  889,  764,  805,
+          665,  807,  768,  697,  835,  809,  884,  769,  848,  849,
+          899,  676,  730,  710,  698,  687,  810,  850,  897,  770,
+          771,  772,  853,  773,  855,    0,    0,    0,    0,    0,
             0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
             0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-            0,    0,    0,    0,  138,  138,  138,  138,   -2,   -2,
-           -2,   -2,    0,    0,   -2,    0,    0,    0,  138,  138,
+            0,    0,    0,    0,    0,  138,  138,  138,  138,   -2,
+           -2,   -2,   -2,    0,    0,   -2,    0,    0,    0,  138,
           138,  138,  138,  138,  138,  138,  138,  138,  138,  138,
           138,  138,  138,  138,  138,  138,  138,  138,  138,  138,
-          138,  138,  138,  138,    0,    0,  138,  138,  138,  138,
+          138,  138,  138,  138,  138,    0,    0,  138,  138,  138,
+          138,  138,  138,  138,  138,  138,  138,  138,  138,  138,
           138,  138,  138,  138,  138,  138,  138,  138,  138,  138,
           138,  138,  138,  138,  138,  138,  138,  138,  138,  138,
           138,  138,  138,  138,  138,  138,  138,  138,  138,  138,
@@ -549,35 +550,34 @@ class Php5 extends \PhpParser\ParserAbstract
           138,  138,  138,  138,  138,  138,  138,  138,  138,  138,
           138,  138,  138,  138,  138,  138,  138,  138,  138,  138,
           138,  138,  138,  138,  138,  138,  138,  138,  138,  138,
-          138,  138,  138,  138,  138,  138,  138,  138,  138,  599,
           599,  599,  599,  599,  599,  599,  599,  599,  599,  599,
           599,  599,  599,  599,  599,  599,  599,  599,  599,  599,
-          599,  599,    0,    0,    0,    0,    0,    0,    0,    0,
-            0,    0,    0,    0,  599,  -21,  -21,  -21,  -21,  599,
-          -21,  -21,  -21,  -21,  -21,  -21,  -21,  599,  599,  599,
+          599,  599,  599,    0,    0,    0,    0,    0,    0,    0,
+            0,    0,    0,    0,    0,  599,  -21,  -21,  -21,  -21,
+          599,  -21,  -21,  -21,  -21,  -21,  -21,  -21,  599,  599,
           599,  599,  599,  599,  599,  599,  599,  599,  599,  599,
-          599,  599,  599,  599,  599,  -21,  599,  599,  599,  -21,
-          382,  -21,  382,  382,  382,  382,  382,  382,  382,  382,
+          599,  599,  599,  599,  599,  599,  -21,  599,  599,  599,
+          -21,  382,  -21,  382,  382,  382,  382,  382,  382,  382,
           382,  382,  382,  382,  382,  382,  382,  382,  382,  382,
           382,  382,  382,  382,  382,  382,  382,  382,  382,  382,
           382,  382,  382,  382,  382,  382,  382,  382,  382,  382,
-          382,  382,  382,  382,  382,  382,  599,    0,    0,  599,
-          -21,  599,  -21,  599,  -21,  -21,  599,  599,  599,  599,
-          599,  599,  599,  -21,  -21,  -21,  -21,  -21,  -21,    0,
-          561,  561,  561,  561,  -21,  -21,  -21,  -21,  382,  382,
-          382,  382,  382,  382,  259,  382,  382,  382,  382,  382,
-          382,  382,  382,  382,  382,  382,  561,  561,   -3,   -3,
-          382,  382,  382,  382,  382,  259,  382,  382,  463,  689,
-          689,  689,  137,  137,  137,    0,    0,    0,    0,    0,
-            0,    0,    0,    0,    0,    0,    0,  137,  463,    0,
-          463,    0,  382,  463,  689,  463,  657,  137,  689,  689,
-          463,  869,  616,  616,  616,  616,  328,  278,    0,    0,
-          689,  689,    0,    0,    0,    0,    0,  689,    0,    0,
-            0,    0,    0,    0,  869,    0,    0,    0,    0,    0,
-          667,  247,    0,  705,  335,    0,    0,    0,    0,    0,
-            0,  705,  335,  347,  347,    0,  684,  667,  667,  667,
-            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-            0,    0,    0,    0,    0,    0,    0,  328
+          382,  382,  382,  382,  382,  382,  382,  599,    0,    0,
+          599,  -21,  599,  -21,  599,  -21,  -21,  599,  599,  599,
+          599,  599,  599,  599,  -21,  -21,  -21,  -21,  -21,  -21,
+            0,  561,  561,  561,  561,  -21,  -21,  -21,  -21,  382,
+          382,  382,  382,  382,  382,  259,  382,  382,  382,  382,
+          382,  382,  382,  382,  382,  382,  382,  561,  561,   -3,
+           -3,  382,  382,  382,  382,  382,  259,  382,  382,  463,
+          689,  689,  689,  137,  137,  137,    0,    0,    0,    0,
+            0,    0,    0,    0,    0,    0,    0,    0,  137,  463,
+            0,  463,    0,  382,  463,  689,  463,  657,  137,  689,
+          689,  463,  783,  616,  616,  616,  616,  328,  278,    0,
+            0,  689,  689,    0,    0,    0,    0,    0,  689,    0,
+            0,    0,    0,    0,    0,  783,    0,    0,    0,    0,
+            0,  667,  247,    0,  705,  335,    0,    0,    0,    0,
+            0,    0,  705,  335,  347,  347,    0,  684,  667,  667,
+          667,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+            0,    0,    0,    0,    0,    0,    0,    0,  328
     );
 
     protected $actionDefault = array(
@@ -629,90 +629,90 @@ class Php5 extends \PhpParser\ParserAbstract
         32767,  190,  173,32767,  400,  175,  498,32767,32767,  240,
         32767,  240,32767,  400,  240,32767,32767,  240,32767,  415,
           439,32767,32767,32767,32767,32767,32767,32767,32767,32767,
-        32767,32767,32767,32767,32767,32767,  379,  380,  493,  506,
-        32767,  507,32767,  413,  343,  344,  346,  322,32767,  324,
-          369,  370,  371,  372,  373,  374,  375,  377,32767,  419,
-        32767,  422,32767,32767,32767,  257,32767,  557,32767,32767,
-          306,  557,32767,32767,32767,  551,32767,32767,  300,32767,
-        32767,32767,32767,  253,32767,  169,32767,  541,32767,  558,
-        32767,  515,32767,  342,32767,32767,32767,32767,32767,32767,
-        32767,32767,32767,  516,32767,32767,32767,32767,  229,32767,
-          452,32767,  116,32767,32767,32767,  189,32767,32767,  304,
-          248,32767,32767,  550,32767,32767,32767,32767,32767,32767,
-        32767,32767,  114,32767,  170,32767,32767,32767,  191,32767,
-        32767,  515,32767,32767,32767,32767,32767,32767,32767,  295,
+        32767,32767,32767,32767,32767,  379,  380,  493,  506,32767,
+          507,32767,  413,  343,  344,  346,  322,32767,  324,  369,
+          370,  371,  372,  373,  374,  375,  377,32767,  419,32767,
+          422,32767,32767,32767,  257,32767,  557,32767,32767,  306,
+          557,32767,32767,32767,  551,32767,32767,  300,32767,32767,
+        32767,32767,  253,32767,  169,32767,  541,32767,  558,32767,
+          515,32767,  342,32767,32767,32767,32767,32767,32767,32767,
+        32767,32767,  516,32767,32767,32767,32767,  229,32767,  452,
+        32767,  116,32767,32767,32767,  189,32767,32767,  304,  248,
+        32767,32767,  550,32767,32767,32767,32767,32767,32767,32767,
+        32767,  114,32767,  170,32767,32767,32767,  191,32767,32767,
+          515,32767,32767,32767,32767,32767,32767,32767,32767,  295,
         32767,32767,32767,32767,32767,32767,32767,  515,32767,32767,
           233,32767,32767,32767,32767,32767,32767,32767,32767,32767,
-          415,32767,  276,32767,32767,32767,32767,32767,32767,32767,
-        32767,32767,32767,32767,  127,  127,    3,  127,  127,  260,
-            3,  260,  127,  260,  260,  127,  127,  127,  127,  127,
-          127,  127,  127,  127,  127,  216,  219,  208,  208,  164,
-          127,  127,  268
+        32767,  415,32767,  276,32767,32767,32767,32767,32767,32767,
+        32767,32767,32767,32767,32767,  127,  127,    3,  127,  127,
+          260,    3,  260,  127,  260,  260,  127,  127,  127,  127,
+          127,  127,  127,  127,  127,  127,  216,  219,  208,  208,
+          164,  127,  127,  268
     );
 
     protected $goto = array(
           166,  140,  140,  140,  166,  187,  168,  144,  147,  141,
           142,  143,  149,  163,  163,  163,  163,  144,  144,  165,
           165,  165,  165,  165,  165,  165,  165,  165,  165,  165,
-          138,  159,  160,  161,  162,  184,  139,  185,  494,  495,
-          377,  496,  500,  501,  502,  503,  504,  505,  506,  507,
-          970,  164,  145,  146,  148,  171,  176,  186,  203,  253,
+          138,  159,  160,  161,  162,  184,  139,  185,  493,  494,
+          377,  495,  499,  500,  501,  502,  503,  504,  505,  506,
+          971,  164,  145,  146,  148,  171,  176,  186,  203,  253,
           256,  258,  260,  263,  264,  265,  266,  267,  268,  269,
           277,  278,  279,  280,  303,  304,  328,  329,  330,  394,
-          395,  396,  543,  188,  189,  190,  191,  192,  193,  194,
+          395,  396,  542,  188,  189,  190,  191,  192,  193,  194,
           195,  196,  197,  198,  199,  200,  201,  150,  151,  152,
           167,  153,  169,  154,  204,  170,  155,  156,  157,  205,
-          158,  136,  621,  561,  757,  561,  561,  561,  561,  561,
-          561,  561,  561,  561,  561,  561,  561,  561,  561,  561,
-          561,  561,  561,  561,  561,  561,  561,  561,  561,  561,
-          561,  561,  561,  561,  561,  561,  561,  561,  561,  561,
-          561,  561,  561,  561,  561,  561,  561,  561,  561, 1113,
-          629, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113,
-         1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113,
-         1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113,
-         1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113, 1113,
-         1113, 1113, 1113, 1113, 1113,  758,  520,  531,  509,  656,
-          556, 1183,  750,  509,  592,  786, 1183,  888,  612,  613,
-          884,  617,  618,  624,  626,  631,  633,  817,  855,  855,
-          855,  855,  850,  856,  174,  891,  891, 1205, 1205,  177,
+          158,  136,  622,  560,  758,  560,  560,  560,  560,  560,
+          560,  560,  560,  560,  560,  560,  560,  560,  560,  560,
+          560,  560,  560,  560,  560,  560,  560,  560,  560,  560,
+          560,  560,  560,  560,  560,  560,  560,  560,  560,  560,
+          560,  560,  560,  560,  560,  560,  560,  560,  560, 1114,
+          630, 1114, 1114, 1114, 1114, 1114, 1114, 1114, 1114, 1114,
+         1114, 1114, 1114, 1114, 1114, 1114, 1114, 1114, 1114, 1114,
+         1114, 1114, 1114, 1114, 1114, 1114, 1114, 1114, 1114, 1114,
+         1114, 1114, 1114, 1114, 1114, 1114, 1114, 1114, 1114, 1114,
+         1114, 1114, 1114, 1114, 1114,  759,  519,  530,  508,  657,
+          555, 1184,  350,  508,  591,  787, 1184,  889,  613,  614,
+          885,  618,  619,  625,  627,  632,  634,  751,  856,  856,
+          856,  856,  851,  857,  174,  892,  892, 1206, 1206,  177,
           178,  179,  401,  402,  403,  404,  173,  202,  206,  208,
           257,  259,  261,  262,  270,  271,  272,  273,  274,  275,
           281,  282,  283,  284,  305,  306,  331,  332,  333,  406,
           407,  408,  409,  175,  180,  254,  255,  181,  182,  183,
-          498,  498,  498,  498,  498,  498,  861,  498,  498,  498,
-          498,  498,  498,  498,  498,  498,  498,  510,  586,  538,
-          601,  602,  510,  545,  546,  547,  548,  549,  550,  551,
-          552,  554,  587, 1209,  560,  350,  560,  560,  560,  560,
-          560,  560,  560,  560,  560,  560,  560,  560,  560,  560,
-          560,  560,  560,  560,  560,  560,  560,  560,  560,  560,
-          560,  560,  560,  560,  560,  560,  560,  560,  560,  560,
-          560,  560,  560,  560,  560,  560,  560,  560,  560,  560,
-          400,  607,  537,  537,  569,  533,  909,  535,  535,  497,
-          499,  525,  541,  570,  573,  584,  591,  298,  296,  296,
-          296,  298,  289,  299,  611,  378,  511,  614,  595,  947,
-          375,  511,  437,  437,  437,  437,  437,  437, 1163,  437,
-          437,  437,  437,  437,  437,  437,  437,  437,  437, 1077,
-          948,  338, 1175,  321, 1077,  898,  898,  898,  898,  606,
-          898,  898, 1217, 1217, 1202,  753,  576,  605,  756, 1077,
-         1077, 1077, 1077, 1077, 1077, 1069,  384,  384,  384,  391,
-         1217,  877,  859,  857,  859,  655,  466,  512,  886,  881,
-          753,  384,  753,  384,  968,  384,  895,  385,  588,  353,
-          414,  384, 1231, 1019,  542, 1197, 1197, 1197,  568, 1094,
-          386,  386,  386,  904,  915,  515, 1029,   19,   15,  372,
-          389,  915,  940,  448,  450,  632,  340, 1216, 1216, 1114,
-          615,  938,  840,  555,  775,  386,  913, 1070, 1073, 1074,
-          399, 1069, 1182,  660,   23, 1216,  773, 1182,  544,  603,
-         1066, 1219, 1071, 1174, 1071,  519, 1199, 1199, 1199, 1089,
-         1088, 1072,  343,  523,  534,  519,  519,  772,  351,  352,
-           13,  579,  583,  627, 1061,  388,  782,  562,  771,  515,
-          783, 1181,    3,    4,  918,  956,  865,  451,  574, 1160,
+          497,  497,  497,  497,  497,  497,  818,  497,  497,  497,
+          497,  497,  497,  497,  497,  497,  497,  509,  585,  862,
+          601,  602,  509,  544,  545,  546,  547,  548,  549,  550,
+          551,  553,  586,  338,  559,  321,  559,  559,  559,  559,
+          559,  559,  559,  559,  559,  559,  559,  559,  559,  559,
+          559,  559,  559,  559,  559,  559,  559,  559,  559,  559,
+          559,  559,  559,  559,  559,  559,  559,  559,  559,  559,
+          559,  559,  559,  559,  559,  559,  559,  559,  559,  559,
+          400,  607,  536,  536,  568,  532,  537,  534,  534,  496,
+          498,  524,  540,  569,  572,  583,  590,  298,  296,  296,
+          296,  298,  289,  299,  611, 1210,  510,  615,  910,  948,
+          375,  510,  437,  437,  437,  437,  437,  437,  594,  437,
+          437,  437,  437,  437,  437,  437,  437,  437,  437, 1078,
+          949,  388, 1176,  561, 1078,  899,  899,  899,  899,  378,
+          899,  899, 1218, 1218, 1164,  754,  351,  352,  757, 1078,
+         1078, 1078, 1078, 1078, 1078, 1070,  384,  384,  384,  606,
+         1218,  878,  860,  858,  860,  656,  466,  511,  887,  882,
+          754,  384,  754,  384,  969,  384,  391,  385,  587,  353,
+          414,  384, 1232, 1203,  541, 1198, 1198, 1198,  567, 1095,
+          386,  386,  386, 1020,  916,  514, 1030,   19,   15,  372,
+          776,  916,  941,  448,  450,  633,  896, 1217, 1217, 1115,
+          616,  939,  841,  554,  905,  386,  340, 1071, 1074, 1075,
+          399, 1070, 1183,  914,   23, 1217,  774, 1183,  543,  603,
+          389, 1220, 1072, 1175, 1072,  518, 1200, 1200, 1200,  575,
+          605, 1073,  343,  522,  533,  518,  518,  773, 1090, 1089,
+           13,  578,  582,  628,    3,    4,  783, 1067,  772,  514,
+         1062, 1182,  784,  661,  919,  451,  866,  573,  957, 1161,
           464,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-            0,    0,    0,    0,  514,  529,    0,    0,    0,    0,
-          514,    0,  529,    0,    0,    0,    0,  610,  513,  516,
-          439,  440, 1067,  619,    0,    0,    0,    0,    0,    0,
-            0,    0,    0,    0,  780, 1224,    0,    0,    0,    0,
-            0,  524,    0,    0,    0,    0,    0,    0,    0,    0,
-            0,  778,    0,    0,    0,    0,    0,    0,    0,    0,
+            0,    0,    0,    0,  513,  528,    0,    0,    0,    0,
+          513,    0,  528,    0,    0,    0,    0,  610,  512,  515,
+          439,  440, 1068,  620,    0,    0,    0,    0,    0,    0,
+            0,    0,    0,    0,  781, 1225,    0,    0,    0,    0,
+            0,  523,    0,    0,    0,    0,    0,    0,    0,    0,
+            0,  779,    0,    0,    0,    0,    0,    0,    0,    0,
             0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
             0,    0,    0,    0,    0,    0,    0,    0,  301,  301
     );
@@ -739,40 +739,40 @@ class Php5 extends \PhpParser\ParserAbstract
           128,  128,  128,  128,  128,  128,  128,  128,  128,  128,
           128,  128,  128,  128,  128,  128,  128,  128,  128,  128,
           128,  128,  128,  128,  128,   16,  102,   32,   69,   32,
-           32,  120,    6,   69,   32,   29,  120,   32,   32,   32,
-           32,   32,   32,   32,   32,   32,   32,   50,   69,   69,
+           32,  120,   72,   69,   32,   29,  120,   32,   32,   32,
+           32,   32,   32,   32,   32,   32,   32,    6,   69,   69,
            69,   69,   69,   69,   27,   77,   77,   77,   77,   27,
            27,   27,   27,   27,   27,   27,   27,   27,   27,   27,
            27,   27,   27,   27,   27,   27,   27,   27,   27,   27,
            27,   27,   27,   27,   27,   27,   27,   27,   27,   27,
            27,   27,   27,   27,   27,   27,   27,   27,   27,   27,
-          119,  119,  119,  119,  119,  119,   33,  119,  119,  119,
-          119,  119,  119,  119,  119,  119,  119,  119,   67,  110,
+          119,  119,  119,  119,  119,  119,   50,  119,  119,  119,
+          119,  119,  119,  119,  119,  119,  119,  119,   67,   33,
            67,   67,  119,  111,  111,  111,  111,  111,  111,  111,
-          111,  111,  111,  142,   57,   72,   57,   57,   57,   57,
+          111,  111,  111,  127,   57,  127,   57,   57,   57,   57,
            57,   57,   57,   57,   57,   57,   57,   57,   57,   57,
            57,   57,   57,   57,   57,   57,   57,   57,   57,   57,
            57,   57,   57,   57,   57,   57,   57,   57,   57,   57,
            57,   57,   57,   57,   57,   57,   57,   57,   57,   57,
-           51,   51,   51,   51,   51,   51,   84,   51,   51,   51,
+           51,   51,   51,   51,   51,   51,  110,   51,   51,   51,
            51,   51,   51,   51,   51,   51,   51,    5,    5,    5,
-            5,    5,    5,    5,   63,   46,  124,   63,  129,   98,
-           63,  124,   57,   57,   57,   57,   57,   57,  133,   57,
+            5,    5,    5,    5,   63,  142,  124,   63,   84,   98,
+           63,  124,   57,   57,   57,   57,   57,   57,  129,   57,
            57,   57,   57,   57,   57,   57,   57,   57,   57,   57,
-           98,  127,   82,  127,   57,   57,   57,   57,   57,   49,
-           57,   57,  144,  144,  140,   11,   40,   40,   14,   57,
-           57,   57,   57,   57,   57,   82,   13,   13,   13,   48,
+           98,   12,   82,   12,   57,   57,   57,   57,   57,   46,
+           57,   57,  144,  144,  133,   11,   72,   72,   14,   57,
+           57,   57,   57,   57,   57,   82,   13,   13,   13,   49,
           144,   14,   14,   14,   14,   14,   57,   14,   14,   14,
-           11,   13,   11,   13,  102,   13,   79,   11,   70,   70,
-           70,   13,   13,  103,    2,    9,    9,    9,    2,   34,
-          125,  125,  125,   81,   13,   13,   34,   34,   34,   34,
-           17,   13,    8,    8,    8,    8,   18,  143,  143,    8,
-            8,    8,    9,   34,   25,  125,   85,   82,   82,   82,
-          125,   82,  121,   74,   34,  143,   24,  121,   47,   34,
-          116,  143,   82,   82,   82,   47,  121,  121,  121,  126,
-          126,   82,   58,   58,   58,   47,   47,   23,   72,   72,
-           58,   62,   62,   62,  114,   12,   23,   12,   23,   13,
-           26,  121,   30,   30,   86,  100,   71,   65,   66,  132,
+           11,   13,   11,   13,  102,   13,   48,   11,   70,   70,
+           70,   13,   13,  140,    2,    9,    9,    9,    2,   34,
+          125,  125,  125,  103,   13,   13,   34,   34,   34,   34,
+           25,   13,    8,    8,    8,    8,   79,  143,  143,    8,
+            8,    8,    9,   34,   81,  125,   18,   82,   82,   82,
+          125,   82,  121,   85,   34,  143,   24,  121,   47,   34,
+           17,  143,   82,   82,   82,   47,  121,  121,  121,   40,
+           40,   82,   58,   58,   58,   47,   47,   23,  126,  126,
+           58,   62,   62,   62,   30,   30,   23,  116,   23,   13,
+          114,  121,   26,   74,   86,   65,   71,   66,  100,  132,
           109,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
            -1,   -1,   -1,   -1,    9,    9,   -1,   -1,   -1,   -1,
             9,   -1,    9,   -1,   -1,   -1,   -1,   13,    9,    9,
@@ -785,39 +785,39 @@ class Php5 extends \PhpParser\ParserAbstract
     );
 
     protected $gotoBase = array(
-            0,    0, -172,    0,    0,  353,  201,    0,  477,  149,
-            0,  110,  195,  117,  426,  112,  203,  140,  171,    0,
-            0,    0,    0,  168,  164,  157,  119,   27,    0,  205,
-         -118,    0, -428,  266,   51,    0,    0,    0,    0,    0,
-          388,    0,    0,  -24,    0,    0,  345,  484,  146,  133,
-          209,   75,    0,    0,    0,    0,    0,  107,  161,    0,
-            0,    0,  222,  -77,    0,  106,   97, -343,    0,  -94,
-          135,  123, -129,    0,  129,    0,    0,  -50,    0,  143,
-            0,  159,   64,    0,  338,  132,  122,    0,    0,    0,
+            0,    0, -173,    0,    0,  353,  216,    0,  477,  149,
+            0,  110,   71,  117,  426,  112,  203,  170,  181,    0,
+            0,    0,    0,  168,  164,  143,  121,   27,    0,  205,
+         -127,    0, -429,  279,   51,    0,    0,    0,    0,    0,
+          481,    0,    0,  -24,    0,    0,  379,  484,  163,  153,
+          268,   75,    0,    0,    0,    0,    0,  107,  161,    0,
+            0,    0,  222,  -77,    0,  104,   96, -344,    0,  -94,
+          135,  123, -232,    0,  169,    0,    0,  -50,    0,  173,
+            0,  180,   64,    0,  360,  139,  122,    0,    0,    0,
             0,    0,    0,    0,    0,    0,    0,    0,   98,    0,
-          121,    0,  165,  156,    0,    0,    0,    0,    0,   87,
-          273,  259,    0,    0,  114,    0,  150,    0,    0,   -5,
-          -91,  200,    0,    0,   84,  154,  202,   77,  -48,  178,
-            0,    0,   93,  187,    0,    0,    0,    0,    0,    0,
-          136,    0,  286,  167,  102,    0,    0
+          124,    0,  165,  166,    0,    0,    0,    0,    0,   87,
+          340,  259,    0,    0,  120,    0,  177,    0,    0,   -5,
+          -91,  200,    0,    0,   84,  154,  211,  -21,  -48,  188,
+            0,    0,   93,  213,    0,    0,    0,    0,    0,    0,
+          175,    0,  358,  167,  102,    0,    0
     );
 
     protected $gotoDefault = array(
-        -32768,  468,  664,    2,  665,  835,  740,  748,  598,  482,
-          630,  582,  380, 1193,  792,  793,  794,  381,  368,  483,
-          379,  410,  405,  781,  774,  776,  784,  172,  411,  787,
-            1,  789,  518,  825, 1020,  365,  797,  366,  590,  799,
-          527,  801,  802,  137,  382,  383,  528,  484,  390,  577,
-          816,  276,  387,  818,  367,  819,  828,  371,  465,  455,
-          460,  530,  557,  609,  432,  447,  571,  565,  536, 1086,
-          566,  864,  349,  872,  661,  880,  883,  485,  558,  894,
-          452,  902, 1099,  397,  908,  914,  919,  291,  922,  417,
-          412,  585,  927,  928,    5,  932,  622,  623,    8,  312,
-          955,  599,  969,  420, 1039, 1041,  486,  487,  522,  459,
-          508,  526,  488, 1062,  441,  413, 1065,  433,  489,  490,
-          434,  435, 1083,  355, 1168,  354,  449,  320, 1155,  580,
-         1118,  456, 1208, 1164,  348,  491,  492,  376, 1187,  392,
-         1203,  438, 1210, 1218,  344,  540,  567
+        -32768,  468,  665,    2,  666,  836,  741,  749,  598,  482,
+          631,  581,  380, 1194,  793,  794,  795,  381,  368,  766,
+          379,  410,  405,  782,  775,  777,  785,  172,  411,  788,
+            1,  790,  517,  826, 1021,  365,  798,  366,  589,  800,
+          526,  802,  803,  137,  382,  383,  527,  483,  390,  576,
+          817,  276,  387,  819,  367,  820,  829,  371,  465,  455,
+          460,  529,  556,  609,  432,  447,  570,  564,  535, 1087,
+          565,  865,  349,  873,  662,  881,  884,  484,  557,  895,
+          452,  903, 1100,  397,  909,  915,  920,  291,  923,  417,
+          412,  584,  928,  929,    5,  933,  623,  624,    8,  312,
+          956,  599,  970,  420, 1040, 1042,  485,  486,  521,  459,
+          507,  525,  487, 1063,  441,  413, 1066,  433,  488,  489,
+          434,  435, 1084,  355, 1169,  354,  449,  320, 1156,  579,
+         1119,  456, 1209, 1165,  348,  490,  491,  376, 1188,  392,
+         1204,  438, 1211, 1219,  344,  539,  566
     );
 
     protected $ruleToNonTerminal = array(
@@ -891,7 +891,7 @@ class Php5 extends \PhpParser\ParserAbstract
             1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
             1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
             1,    1,    1,    1,    1,    1,    1,    3,    5,    4,
-            3,    4,    2,    3,    1,    1,    7,    6,    3,    1,
+            3,    4,    1,    3,    1,    1,    8,    7,    3,    1,
             3,    1,    3,    1,    1,    3,    1,    3,    1,    2,
             3,    1,    3,    3,    1,    3,    2,    0,    1,    1,
             1,    1,    1,    3,    5,    8,    3,    5,    9,    3,
@@ -1256,7 +1256,7 @@ protected function initReduceCallbacks() {
                  $this->semValue = new Stmt\Use_($this->semStack[$stackPos-(4-3)], $this->semStack[$stackPos-(4-2)], $this->startAttributeStack[$stackPos-(4-1)] + $this->endAttributes);
             },
             102 => function ($stackPos) {
-                 $this->semValue = $this->semStack[$stackPos-(2-1)];
+                 $this->semValue = $this->semStack[$stackPos-(1-1)];
             },
             103 => function ($stackPos) {
                  $this->semValue = new Stmt\Const_($this->semStack[$stackPos-(3-2)], $this->startAttributeStack[$stackPos-(3-1)] + $this->endAttributes);
@@ -1268,10 +1268,10 @@ protected function initReduceCallbacks() {
                  $this->semValue = Stmt\Use_::TYPE_CONSTANT;
             },
             106 => function ($stackPos) {
-                 $this->semValue = new Stmt\GroupUse($this->semStack[$stackPos-(7-3)], $this->semStack[$stackPos-(7-6)], $this->semStack[$stackPos-(7-2)], $this->startAttributeStack[$stackPos-(7-1)] + $this->endAttributes);
+                 $this->semValue = new Stmt\GroupUse($this->semStack[$stackPos-(8-3)], $this->semStack[$stackPos-(8-6)], $this->semStack[$stackPos-(8-2)], $this->startAttributeStack[$stackPos-(8-1)] + $this->endAttributes);
             },
             107 => function ($stackPos) {
-                 $this->semValue = new Stmt\GroupUse($this->semStack[$stackPos-(6-2)], $this->semStack[$stackPos-(6-5)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos-(6-1)] + $this->endAttributes);
+                 $this->semValue = new Stmt\GroupUse($this->semStack[$stackPos-(7-2)], $this->semStack[$stackPos-(7-5)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos-(7-1)] + $this->endAttributes);
             },
             108 => function ($stackPos) {
                  $this->semStack[$stackPos-(3-1)][] = $this->semStack[$stackPos-(3-3)]; $this->semValue = $this->semStack[$stackPos-(3-1)];
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/Parser/Php7.php b/app/vendor/nikic/php-parser/lib/PhpParser/Parser/Php7.php
index 6d2b4b0f9..d41bb8369 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/Parser/Php7.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/Parser/Php7.php
@@ -26,8 +26,8 @@ class Php7 extends \PhpParser\ParserAbstract
     protected $defaultAction = -32766;
     protected $unexpectedTokenRule = 32767;
 
-    protected $YY2TBLSTATE = 434;
-    protected $numNonLeafStates = 736;
+    protected $YY2TBLSTATE = 435;
+    protected $numNonLeafStates = 737;
 
     protected $symbolToName = array(
         "EOF",
@@ -244,130 +244,130 @@ class Php7 extends \PhpParser\ParserAbstract
     );
 
     protected $action = array(
-          133,  134,  135,  579,  136,  137,    0,  748,  749,  750,
+          133,  134,  135,  580,  136,  137,    0,  749,  750,  751,
           138,   38,  327,-32766,-32766,-32766,-32766,-32766,-32766,-32767,
-        -32767,-32767,-32767,  102,  103,  104,  105,  106, 1109, 1110,
-         1111, 1108, 1107, 1106, 1112,  742,  741,-32766, 1232,-32766,
+        -32767,-32767,-32767,  102,  103,  104,  105,  106, 1110, 1111,
+         1112, 1109, 1108, 1107, 1113,  743,  742,-32766, 1233,-32766,
         -32766,-32766,-32766,-32766,-32766,-32766,-32767,-32767,-32767,-32767,
-        -32767,    2,  107,  108,  109,  751,  274,  381,  380,-32766,
-        -32766,-32766,-32766,  104,  105,  106, 1024,  422,  110,  265,
-          139,  403,  755,  756,  757,  758,  466,  467,  428,  938,
-          291,-32766,  287,-32766,-32766,  759,  760,  761,  762,  763,
-          764,  765,  766,  767,  768,  769,  789,  580,  790,  791,
-          792,  793,  781,  782,  344,  345,  784,  785,  770,  771,
-          772,  774,  775,  776,  355,  816,  817,  818,  819,  820,
-          581,  777,  778,  582,  583,  810,  801,  799,  800,  813,
-          796,  797,  687, -545,  584,  585,  795,  586,  587,  588,
-          589,  590,  591, -328, -593, -367, 1234, -367,  798,  592,
-          593, -593,  140,-32766,-32766,-32766,  133,  134,  135,  579,
-          136,  137, 1057,  748,  749,  750,  138,   38,  688, 1020,
-         1019, 1018, 1021,  390,-32766,    7,-32766,-32766,-32766,-32766,
-        -32766,-32766,-32766,-32766,-32766,-32766,  379,  380, 1033,  689,
-          690,  742,  741,-32766,-32766,-32766,  422, -545, -545, -590,
-        -32766,-32766,-32766, 1032,-32766,  127, -590, 1236, 1235, 1237,
-         1318,  751, -545,  290,-32766,  283,-32766,-32766,-32766,-32766,
-        -32766, 1236, 1235, 1237, -545,  265,  139,  403,  755,  756,
-          757,  758,   16,  481,  428,  458,  459,  460,  298,  722,
-           35,  759,  760,  761,  762,  763,  764,  765,  766,  767,
-          768,  769,  789,  580,  790,  791,  792,  793,  781,  782,
-          344,  345,  784,  785,  770,  771,  772,  774,  775,  776,
-          355,  816,  817,  818,  819,  820,  581,  777,  778,  582,
-          583,  810,  801,  799,  800,  813,  796,  797,  129,  824,
-          584,  585,  795,  586,  587,  588,  589,  590,  591, -328,
-           83,   84,   85, -593,  798,  592,  593, -593,  149,  773,
-          743,  744,  745,  746,  747,  824,  748,  749,  750,  786,
-          787,   37,  145,   86,   87,   88,   89,   90,   91,   92,
+        -32767,    2,  107,  108,  109,  752,  274,  381,  380,-32766,
+        -32766,-32766,-32766,  104,  105,  106, 1025,  423,  110,  265,
+          139,  402,  756,  757,  758,  759,  467,  468,  429,  939,
+          291,-32766,  287,-32766,-32766,  760,  761,  762,  763,  764,
+          765,  766,  767,  768,  769,  770,  790,  581,  791,  792,
+          793,  794,  782,  783,  344,  345,  785,  786,  771,  772,
+          773,  775,  776,  777,  355,  817,  818,  819,  820,  821,
+          582,  778,  779,  583,  584,  811,  802,  800,  801,  814,
+          797,  798,  688, -545,  585,  586,  796,  587,  588,  589,
+          590,  591,  592, -328, -593, -367, 1235, -367,  799,  593,
+          594, -593,  140,-32766,-32766,-32766,  133,  134,  135,  580,
+          136,  137, 1058,  749,  750,  751,  138,   38,  689, 1021,
+         1020, 1019, 1022,  390,-32766,    7,-32766,-32766,-32766,-32766,
+        -32766,-32766,-32766,-32766,-32766,-32766,  379,  380, 1034,  690,
+          691,  743,  742,-32766,-32766,-32766,  423, -545, -545, -590,
+        -32766,-32766,-32766, 1033,-32766,  127, -590, 1237, 1236, 1238,
+         1319,  752, -545,  290,-32766,  283,-32766,-32766,-32766,-32766,
+        -32766, 1237, 1236, 1238, -545,  265,  139,  402,  756,  757,
+          758,  759,   16,  482,  429,  459,  460,  461,  298,  723,
+           35,  760,  761,  762,  763,  764,  765,  766,  767,  768,
+          769,  770,  790,  581,  791,  792,  793,  794,  782,  783,
+          344,  345,  785,  786,  771,  772,  773,  775,  776,  777,
+          355,  817,  818,  819,  820,  821,  582,  778,  779,  583,
+          584,  811,  802,  800,  801,  814,  797,  798,  129,  825,
+          585,  586,  796,  587,  588,  589,  590,  591,  592, -328,
+           83,   84,   85, -593,  799,  593,  594, -593,  149,  774,
+          744,  745,  746,  747,  748,  825,  749,  750,  751,  787,
+          788,   37,  145,   86,   87,   88,   89,   90,   91,   92,
            93,   94,   95,   96,   97,   98,   99,  100,  101,  102,
-          103,  104,  105,  106,  107,  108,  109,  291,  274,  835,
-          254, 1109, 1110, 1111, 1108, 1107, 1106, 1112, -590,  860,
-          110,  861, -590,  482,  751,-32766,-32766,-32766,-32766,-32766,
-          142,  603, 1085,  742,  741, 1262,  326,  987,  752,  753,
-          754,  755,  756,  757,  758,  309,-32766,  822,-32766,-32766,
-        -32766,-32766,  242,  553,  759,  760,  761,  762,  763,  764,
-          765,  766,  767,  768,  769,  789,  812,  790,  791,  792,
-          793,  781,  782,  783,  811,  784,  785,  770,  771,  772,
-          774,  775,  776,  815,  816,  817,  818,  819,  820,  821,
-          777,  778,  779,  780,  810,  801,  799,  800,  813,  796,
-          797,  311,  940,  788,  794,  795,  802,  803,  805,  804,
-          806,  807,  323,  609, 1274, 1033,  833,  798,  809,  808,
-           50,   51,   52,  512,   53,   54,  860,  241,  861,  918,
-           55,   56, -111,   57,-32766,-32766,-32766, -111,  826, -111,
-          290, 1302, 1347,  356,  305, 1348,  339, -111, -111, -111,
+          103,  104,  105,  106,  107,  108,  109,  291,  274,  836,
+          254, 1110, 1111, 1112, 1109, 1108, 1107, 1113, -590,  861,
+          110,  862, -590,  483,  752,-32766,-32766,-32766,-32766,-32766,
+          142,  604, 1086,  743,  742, 1263,  326,  988,  753,  754,
+          755,  756,  757,  758,  759,  309,-32766,  823,-32766,-32766,
+        -32766,-32766,  242,  554,  760,  761,  762,  763,  764,  765,
+          766,  767,  768,  769,  770,  790,  813,  791,  792,  793,
+          794,  782,  783,  784,  812,  785,  786,  771,  772,  773,
+          775,  776,  777,  816,  817,  818,  819,  820,  821,  822,
+          778,  779,  780,  781,  811,  802,  800,  801,  814,  797,
+          798,  311,  941,  789,  795,  796,  803,  804,  806,  805,
+          807,  808,  323,  610, 1275, 1034,  834,  799,  810,  809,
+           50,   51,   52,  513,   53,   54,  861,  241,  862,  919,
+           55,   56, -111,   57,-32766,-32766,-32766, -111,  827, -111,
+          290, 1303, 1348,  356,  305, 1349,  339, -111, -111, -111,
          -111, -111, -111, -111, -111,-32766, -194,-32766,-32766,-32766,
-         -193,  956,  957,  829,  -86,  988,  958,  834,   58,   59,
-          340,  428,  952, -544,   60,  832,   61,  247,  248,   62,
-           63,   64,   65,   66,   67,   68,   69, 1241,   28,  267,
-           70,  444,  513, -342,-32766,  141, 1268, 1269,  514,  918,
-          833,  326, -272,  918, 1266,   42,   25,  515,  940,  516,
-           14,  517,  908,  518,  828,  369,  519,  520,  373,  709,
-         1033,   44,   45,  445,  376,  375,  388,   46,  521,  712,
-          -86,  440, 1101,  367,  338, -543,  441, -544, -544,  830,
-         1227,  442,  523,  524,  525,  290, 1236, 1235, 1237,  361,
-         1030,  443, -544, 1087,  526,  527,  839, 1255, 1256, 1257,
-         1258, 1252, 1253,  297, -544,  151, -550, -584,  833, 1259,
-         1254, -584, 1033, 1236, 1235, 1237,  298, -154, -154, -154,
-          152,   71,  908,  321,  322,  326,  908,  920, 1030,  707,
-          833,  154, -154, 1337, -154,  155, -154,  283, -154, -543,
-         -543,   82, 1232, 1086, 1322,  734,  156,  326,  374,  158,
-         1033, 1321, -194,  -79, -543,  -88, -193,  742,  741,  956,
-          957,  653,   26,-32766,  522,  -51, -543,   33, -549,  894,
-          952, -111, -111, -111,   32,  111,  112,  113,  114,  115,
+         -193,  957,  958,  830,  -86,  989,  959,  835,   58,   59,
+          340,  429,  953, -544,   60,  833,   61,  247,  248,   62,
+           63,   64,   65,   66,   67,   68,   69, 1242,   28,  267,
+           70,  445,  514, -342,-32766,  141, 1269, 1270,  515,  919,
+          834,  326, -272,  919, 1267,   42,   25,  516,  941,  517,
+           14,  518,  909,  519,  829,  369,  520,  521,  373,  710,
+         1034,   44,   45,  446,  376,  375,  388,   46,  522,  713,
+          -86,  441, 1102,  367,  338, -543,  442, -544, -544,  831,
+         1228,  443,  524,  525,  526,  290, 1237, 1236, 1238,  361,
+         1031,  444, -544, 1088,  527,  528,  840, 1256, 1257, 1258,
+         1259, 1253, 1254,  297, -544,  151, -550, -584,  834, 1260,
+         1255, -584, 1034, 1237, 1236, 1238,  298, -154, -154, -154,
+          152,   71,  909,  321,  322,  326,  909,  921, 1031,  708,
+          834,  154, -154, 1338, -154,  155, -154,  283, -154, -543,
+         -543,   82, 1233, 1087, 1323,  735,  156,  326,  374,  158,
+         1034, 1322, -194,  -79, -543,  -88, -193,  743,  742,  957,
+          958,  654,   26,-32766,  523,  -51, -543,   33, -549,  895,
+          953, -111, -111, -111,   32,  111,  112,  113,  114,  115,
           116,  117,  118,  119,  120,  121,  122,  123,  -59,   75,
-           28,  672,  673,  326,  -58,   36,  250,  920,  124,  707,
-          125,  920,  833,  707, -154,  130, 1266,  131,-32766, -547,
-          144, -542,  150,  406, 1234,  377,  378, 1146, 1148,  382,
-          383,-32766,-32766,-32766,  -85,-32766, 1056,-32766, -542,-32766,
-          644,  645,-32766,  159,  160,  161, 1232,-32766,-32766,-32766,
-          162,  -79, 1227,-32766,-32766,  742,  741,  163, -302,-32766,
-          419,  -75,   -4,  918,  -73,  287,  526,  527,-32766, 1255,
-         1256, 1257, 1258, 1252, 1253,  -72,  -71,  -70,  -69,  -68,
-          -67, 1259, 1254, -547, -547, -542, -542,  742,  741,  -66,
-          -47,  -18,-32766,   73,  148,  918,  322,  326, 1234,  273,
-         -542,  284, -542, -542,  723,-32766,-32766,-32766,  726,-32766,
-         -547,-32766, -542,-32766,  917,  147,-32766, -542,  288,  289,
-         -298,-32766,-32766,-32766,-32766,  713,  279,-32766,-32766, -542,
-         1234,  280,  285,-32766,  419,   48,  286,-32766,-32766,-32766,
-          332,-32766,-32766,-32766,  292,-32766,  908,  293,-32766,  934,
-          274, 1030,  918,-32766,-32766,-32766,  110,  682,  132,-32766,
-        -32766,  833,  146,-32766,  559,-32766,  419,  659,  374,  824,
-          435, 1349,   74, 1033,-32766,  296,  654, 1116,  908,  956,
-          957,  306,  714,  698,  522,  555,  303,   13,  310,  852,
-          952, -111, -111, -111,  700,  463,  492,  953,  283,  299,
-          300,-32766,   49,  675,  918,  304,  660, 1234,  676,  936,
-         1273,-32766,   10, 1263,-32766,-32766,-32766,  642,-32766,  918,
-        -32766,  920,-32766,  707,   -4,-32766,  126,   34,  918,  565,
-        -32766,-32766,-32766,-32766,    0,  908,-32766,-32766,    0, 1234,
-          918,    0,-32766,  419,    0,    0,-32766,-32766,-32766,  717,
-        -32766,-32766,-32766,  920,-32766,  707, 1033,-32766,  724, 1275,
-            0,  487,-32766,-32766,-32766,-32766,  301,  302,-32766,-32766,
-         -507, 1234,  571, -497,-32766,  419,  607,    8,-32766,-32766,
-        -32766,  372,-32766,-32766,-32766,   17,-32766,  908,  371,-32766,
-          832,  298,  320,  128,-32766,-32766,-32766,   40,  370,   41,
-        -32766,-32766,  908, -250, -250, -250,-32766,  419,  731,  374,
-          973,  908,  707,  732,  899,-32766,  997,  974,  728,  981,
-          956,  957,  971,  908,  982,  522,  897,  969, 1090, 1093,
-          894,  952, -111, -111, -111,   28, 1094, 1091, 1092, -249,
-         -249, -249, 1241, 1098,  708,  374,  844,  833, 1288, 1306,
-         1340, 1266,  647, 1267,  711,  715,  956,  957,  716, 1241,
-          718,  522,  920,  719,  707, -250,  894,  952, -111, -111,
-         -111,  720,  -16,  721,  725,  710, -511,  920,  895,  707,
-         -578, 1232, 1344, 1346,  855,  854,  920, 1227,  707, -577,
-          863,  946,  989,  862, 1345,  945,  943,  944,  920,  947,
-          707, -249,  527, 1218, 1255, 1256, 1257, 1258, 1252, 1253,
-          927,  937,  925,  979,  980,  631, 1259, 1254, 1343, 1300,
-        -32766, 1289, 1307,  833, 1316, -275, 1234, -576,   73, -550,
+           28,  673,  674,  326,  -58,   36,  250,  921,  124,  708,
+          125,  921,  834,  708, -154,  130, 1267,  131,-32766, -547,
+          144, -542,  150,  406, 1235,  377,  378, 1147, 1149,  382,
+          383,-32766,-32766,-32766,  -85,-32766, 1057,-32766, -542,-32766,
+          645,  646,-32766,  159,  160,  161, 1233,-32766,-32766,-32766,
+          162,  -79, 1228,-32766,-32766,  743,  742,  163, -302,-32766,
+          420,  -75,   -4,  919,  -73,  287,  527,  528,-32766, 1256,
+         1257, 1258, 1259, 1253, 1254,  -72,  -71,  -70,  -69,  -68,
+          -67, 1260, 1255, -547, -547, -542, -542,  743,  742,  -66,
+          -47,  -18,-32766,   73,  148,  919,  322,  326, 1235,  273,
+         -542,  284, -542, -542,  724,-32766,-32766,-32766,  727,-32766,
+         -547,-32766, -542,-32766,  918,  147,-32766, -542,  288,  289,
+         -298,-32766,-32766,-32766,-32766,  714,  279,-32766,-32766, -542,
+         1235,  280,  285,-32766,  420,   48,  286,-32766,-32766,-32766,
+          332,-32766,-32766,-32766,  292,-32766,  909,  293,-32766,  935,
+          274, 1031,  919,-32766,-32766,-32766,  110,  683,  132,-32766,
+        -32766,  834,  146,-32766,  560,-32766,  420,  660,  374,  825,
+          436, 1350,   74, 1034,-32766,  296,  655, 1117,  909,  957,
+          958,  306,  715,  699,  523,  556,  303,   13,  310,  853,
+          953, -111, -111, -111,  701,  464,  493,  954,  283,  299,
+          300,-32766,   49,  676,  919,  304,  661, 1235,  677,  937,
+         1274,-32766,   10, 1264,-32766,-32766,-32766,  643,-32766,  919,
+        -32766,  921,-32766,  708,   -4,-32766,  126,   34,  919,  566,
+        -32766,-32766,-32766,-32766,    0,  909,-32766,-32766,    0, 1235,
+          919,    0,-32766,  420,    0,    0,-32766,-32766,-32766,  718,
+        -32766,-32766,-32766,  921,-32766,  708, 1034,-32766,  725, 1276,
+            0,  488,-32766,-32766,-32766,-32766,  301,  302,-32766,-32766,
+         -507, 1235,  572, -497,-32766,  420,  608,    8,-32766,-32766,
+        -32766,  372,-32766,-32766,-32766,   17,-32766,  909,  371,-32766,
+          833,  298,  320,  128,-32766,-32766,-32766,   40,  370,   41,
+        -32766,-32766,  909, -250, -250, -250,-32766,  420,  732,  374,
+          974,  909,  708,  733,  900,-32766,  998,  975,  405,  982,
+          957,  958,  972,  909,  983,  523,  898,  970, 1091, 1094,
+          895,  953, -111, -111, -111,   28, 1095, 1092, 1093, -249,
+         -249, -249, 1242, 1099,  709,  374,  845,  834, 1289, 1307,
+         1341, 1267,  648, 1268,  712,  716,  957,  958,  717, 1242,
+          719,  523,  921,  720,  708, -250,  895,  953, -111, -111,
+         -111,  721,  -16,  722,  726,  711, -511,  921,  409,  708,
+         -578, 1233,  729,  896, 1345, 1347,  921, 1228,  708, -577,
+          856,  855,  947,  990, 1346,  946,  944,  945,  921,  948,
+          708, -249,  528, 1219, 1256, 1257, 1258, 1259, 1253, 1254,
+          928,  938,  926,  980,  981,  632, 1260, 1255, 1344, 1301,
+        -32766, 1290, 1308,  834, 1317, -275, 1235, -576,   73, -550,
          -549,  322,  326,-32766,-32766,-32766, -548,-32766, -491,-32766,
-          833,-32766,    1,   29,-32766,   30,   39,   43,   47,-32766,
-        -32766,-32766,   72,   76,   77,-32766,-32766, 1232, -111, -111,
-           78,-32766,  419, -111,   79,   80,   81,  143,  153, -111,
-        -32766,  157,  246,  328, 1232, -111, -111,  356,-32766,  357,
+          834,-32766,    1,   29,-32766,   30,   39,   43,   47,-32766,
+        -32766,-32766,   72,   76,   77,-32766,-32766, 1233, -111, -111,
+           78,-32766,  420, -111,   79,   80,   81,  143,  153, -111,
+        -32766,  157,  246,  328, 1233, -111, -111,  356,-32766,  357,
          -111,  358,  359,  360,  361,  362, -111,  363,  364,  365,
-          366,  368,  436,    0, -273,-32766, -272,   19,   20,  298,
-           21,   22,   24,  405,   75, 1203,  483,  484,  326,  491,
-            0,  494,  495,  496,  497,  501,  298,  502,  503,  510,
-          693,   75,    0, 1245, 1186,  326, 1264, 1059, 1058, 1039,
-         1222, 1035, -277, -103,   18,   23,   27,  295,  404,  600,
-          604,  633,  699, 1190, 1240, 1187, 1319,    0,    0,    0,
+          366,  368,  437,    0, -273,-32766, -272,   19,   20,  298,
+           21,   22,   24,  404,   75, 1204,  484,  485,  326,  492,
+            0,  495,  496,  497,  498,  502,  298,  503,  504,  511,
+          694,   75,    0, 1246, 1187,  326, 1265, 1060, 1059, 1040,
+         1223, 1036, -277, -103,   18,   23,   27,  295,  403,  601,
+          605,  634,  700, 1191, 1241, 1188, 1320,    0,    0,    0,
           326
     );
 
@@ -539,43 +539,43 @@ class Php7 extends \PhpParser\ParserAbstract
          1058, 1058, 1058, 1058, 1058, 1058, 1058, 1073,  336, 1059,
           423, 1073, 1073, 1073,  336,  336,  336,  336,  336,  336,
           336,  336,  336,  336,  619,  423,  586,  616,  423,  795,
-          336,  348,  814,  348,  348,  348,  348,  348,  348,  348,
-          348,  348,  348,  750,  202,  348,  346,   78,   78,  484,
-           65,   78,   78,   78,   78,  348,  348,  348,  348,  609,
-          783,  766,  613,  813,  492,  783,  783,  783,  473,  135,
-          378,  488,  713,  775,   67,  779,  779,  785,  969,  969,
-          779,  769,  779,  785,  975,  779,  779,  969,  969,  823,
-          280,  563,  478,  550,  568,  969,  377,  779,  779,  779,
-          779,  746,  573,  779,  342,  314,  779,  779,  746,  744,
-          760,   43,  762,  969,  969,  969,  746,  547,  762,  762,
-          762,  839,  844,  794,  758,  444,  433,  588,  232,  801,
-          758,  758,  779,  558,  794,  758,  794,  758,  745,  758,
-          758,  758,  794,  758,  769,  502,  758,  717,  583,  224,
-          758,    6,  979,  980,  624,  981,  973,  987, 1019,  991,
-          992,  873,  965,  999,  974,  993,  972,  970,  773,  682,
-          684,  818,  811,  963,  777,  777,  777,  956,  777,  777,
-          777,  777,  777,  777,  777,  777,  682,  743,  829,  765,
-         1006,  689,  691,  754,  906,  901, 1030, 1004, 1049,  994,
-          828,  694, 1028, 1008,  846,  821, 1009, 1010, 1029, 1050,
-         1052,  910,  782,  911,  912,  876, 1012,  883,  777,  979,
-          992,  693,  974,  993,  972,  970,  748,  739,  737,  738,
-          736,  735,  723,  734,  753, 1053,  954,  907,  878, 1011,
-          957,  682,  879, 1023,  756, 1032, 1033,  827,  788,  778,
-          880,  913, 1014, 1015, 1016,  884, 1054,  887,  830, 1024,
-          951, 1035,  789,  918, 1037, 1038, 1039, 1040,  889,  919,
-          892,  916,  900,  845,  776, 1020,  761,  920,  591,  787,
-          791,  800, 1018,  606, 1000,  902,  921,  922, 1041, 1043,
-         1044,  923,  924,  995,  847, 1026,  799, 1027, 1022,  848,
-          850,  617,  797, 1055,  781,  786,  772,  621,  632,  925,
-          927,  931,  998,  763,  770,  853,  855, 1056,  771, 1057,
-          938,  635,  857,  718,  939, 1046,  719,  724,  637,  678,
-          672,  731,  792,  903,  826,  757,  780, 1017,  724,  767,
-          858,  940,  859,  860,  867, 1045,  868,    0,    0,    0,
+          336,  814,  348,  348,  348,  348,  348,  348,  348,  348,
+          348,  348,  750,  202,  348,  348,  346,   78,   78,  348,
+          484,   65,   78,   78,   78,   78,  348,  348,  348,  348,
+          609,  783,  766,  613,  813,  492,  783,  783,  783,  473,
+          135,  378,  488,  713,  775,   67,  779,  779,  785,  969,
+          969,  779,  769,  779,  785,  975,  779,  779,  969,  969,
+          823,  280,  563,  478,  550,  568,  969,  377,  779,  779,
+          779,  779,  746,  573,  779,  342,  314,  779,  779,  746,
+          744,  760,   43,  762,  969,  969,  969,  746,  547,  762,
+          762,  762,  839,  844,  794,  758,  444,  433,  588,  232,
+          801,  758,  758,  779,  558,  794,  758,  794,  758,  745,
+          758,  758,  758,  794,  758,  769,  502,  758,  717,  583,
+          224,  758,    6,  979,  980,  624,  981,  973,  987, 1019,
+          991,  992,  873,  965,  999,  974,  993,  972,  970,  773,
+          682,  684,  818,  811,  963,  777,  777,  777,  956,  777,
+          777,  777,  777,  777,  777,  777,  777,  682,  743,  829,
+          765, 1006,  689,  691,  754,  911,  901, 1030, 1004, 1049,
+          994,  828,  694, 1028, 1008,  910,  821, 1009, 1010, 1029,
+         1050, 1052,  912,  782,  913,  918,  876, 1012,  883,  777,
+          979,  992,  693,  974,  993,  972,  970,  748,  739,  737,
+          738,  736,  735,  723,  734,  753, 1053,  954,  907,  878,
+         1011,  957,  682,  879, 1023,  756, 1032, 1033,  827,  788,
+          778,  880,  919, 1014, 1015, 1016,  884, 1054,  887,  830,
+         1024,  951, 1035,  789,  846, 1037, 1038, 1039, 1040,  889,
+          920,  892,  916,  900,  845,  776, 1020,  761,  921,  591,
+          787,  791,  800, 1018,  606, 1000,  902,  906,  922, 1041,
+         1043, 1044,  923,  924,  995,  847, 1026,  799, 1027, 1022,
+          848,  850,  617,  797, 1055,  781,  786,  772,  621,  632,
+          925,  927,  931,  998,  763,  770,  853,  855, 1056,  771,
+         1057,  938,  635,  857,  718,  939, 1046,  719,  724,  637,
+          678,  672,  731,  792,  903,  826,  757,  780, 1017,  724,
+          767,  858,  940,  859,  860,  867, 1045,  868,    0,    0,
             0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
             0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-            0,    0,    0,    0,    0,    0,    0,  458,  458,  458,
-          458,  458,  458,  307,  307,  307,  307,  307,  307,  307,
-            0,    0,  307,    0,  458,  458,  458,  458,  458,  458,
+            0,    0,    0,    0,    0,    0,    0,    0,  458,  458,
+          458,  458,  458,  458,  307,  307,  307,  307,  307,  307,
+          307,    0,    0,  307,    0,  458,  458,  458,  458,  458,
           458,  458,  458,  458,  458,  458,  458,  458,  458,  458,
           458,  458,  458,  458,  458,  458,  458,  458,  458,  458,
           458,  458,  458,  458,  458,  458,  458,  458,  458,  458,
@@ -590,33 +590,34 @@ class Php7 extends \PhpParser\ParserAbstract
           458,  458,  458,  458,  458,  458,  458,  458,  458,  458,
           458,  458,  458,  458,  458,  458,  458,  458,  458,  458,
           458,  458,  458,  458,  458,  458,  458,  458,  458,  458,
+          458,  291,  291,  291,  291,  291,  291,  291,  291,  291,
           291,  291,  291,  291,  291,  291,  291,  291,  291,  291,
-          291,  291,  291,  291,  291,  291,  291,  291,  291,  291,
-          291,  291,  291,  291,    0,    0,    0,    0,    0,    0,
+          291,  291,  291,  291,  291,    0,    0,    0,    0,    0,
             0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
             0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-            0,  291,  291,  291,  291,  291,  291,  291,  291,  291,
+            0,    0,  291,  291,  291,  291,  291,  291,  291,  291,
           291,  291,  291,  291,  291,  291,  291,  291,  291,  291,
-          291,  291,  291,  291,  291,  291,  291,   66,   66,  291,
-          291,  291,   66,   66,   66,   66,   66,   66,   66,   66,
-           66,   66,    0,  291,  291,  291,  291,  291,  291,  291,
-          291,   66,  823,   66,   -1,   -1,   -1,   -1,   66,   66,
-           66,  -88,  -88,   66,  384,   66,   66,   -1,   -1,   66,
+          291,  291,  291,  291,  291,  291,  291,  291,   66,   66,
+          291,  291,  291,   66,   66,   66,   66,   66,   66,   66,
+           66,   66,   66,    0,  291,  291,  291,  291,  291,  291,
+          291,  291,   66,  823,   66,   -1,   -1,   -1,   -1,   66,
+           66,   66,  -88,  -88,   66,  384,   66,   66,   -1,   -1,
            66,   66,   66,   66,   66,   66,   66,   66,   66,   66,
-            0,    0,  423,  548,   66,  769,  769,  769,  769,   66,
-           66,   66,   66,  548,  548,   66,   66,   66,    0,    0,
-            0,    0,    0,    0,    0,    0,  423,  548,    0,  423,
-            0,    0,  769,  769,   66,  384,  823,  643,   66,    0,
-            0,    0,    0,  423,  769,  423,  336,  779,  548,  779,
-          336,  336,   78,  348,  643,  611,  611,  611,  611,    0,
-            0,  609,  823,  823,  823,  823,  823,  823,  823,  823,
-          823,  823,  823,  769,    0,  823,    0,  769,  769,  769,
-            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-            0,    0,    0,    0,    0,  769,    0,    0,  969,    0,
+           66,    0,    0,  423,  548,   66,  769,  769,  769,  769,
+           66,   66,   66,   66,  548,  548,   66,   66,   66,    0,
+            0,    0,    0,    0,    0,    0,    0,  423,  548,    0,
+          423,    0,    0,  769,  769,   66,  384,  823,  643,   66,
+            0,    0,    0,    0,  423,  769,  423,  336,  779,  548,
+          779,  336,  336,   78,  348,  643,  611,  611,  611,  611,
+            0,    0,  609,  823,  823,  823,  823,  823,  823,  823,
+          823,  823,  823,  823,  769,    0,  823,    0,  769,  769,
+          769,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+            0,    0,    0,    0,    0,    0,  769,    0,  969,    0,
             0,    0,    0,    0,    0,    0,    0,    0,    0,  975,
-            0,    0,    0,    0,    0,    0,  769,    0,    0,    0,
-            0,    0,    0,    0,    0,    0,  777,  788,    0,  788,
-            0,  777,  777,  777,    0,    0,    0,    0,  797,  771
+            0,    0,    0,    0,    0,    0,    0,    0,  769,    0,
+            0,    0,    0,    0,    0,    0,    0,    0,  777,  788,
+            0,  788,    0,  777,  777,  777,    0,    0,    0,    0,
+          797,  771
     );
 
     protected $actionDefault = array(
@@ -659,102 +660,102 @@ class Php7 extends \PhpParser\ParserAbstract
           111,  111,  111,  111,  111,  111,  111,32767,  195,  111,
         32767,32767,32767,  101,  195,  195,  195,  195,  195,  195,
           195,  195,  195,  195,  190,32767,  268,  270,  103,  557,
-          195,32767,  515,32767,32767,32767,32767,32767,32767,32767,
-        32767,32767,32767,  508,32767,32767,32767,32767,32767,32767,
-        32767,32767,32767,32767,32767,32767,32767,32767,32767,  496,
-          434,  139,32767,  139,  542,  426,  427,  428,  498,  542,
-          542,  542,  312,  289,32767,32767,32767,32767,  513,  513,
-          101,  101,  101,  101,  508,32767,32767,32767,32767,  112,
-          100,  100,  100,  100,  100,  104,  102,32767,32767,32767,
-        32767,  223,  100,32767,  102,  102,32767,32767,  223,  225,
-          212,  102,  227,32767,  561,  562,  223,  102,  227,  227,
-          227,  247,  247,  485,  318,  102,  100,  102,  102,  197,
-          318,  318,32767,  102,  485,  318,  485,  318,  199,  318,
-          318,  318,  485,  318,32767,  102,  318,  214,  100,  100,
-          318,32767,32767,32767,  498,32767,32767,32767,32767,32767,
-        32767,32767,  222,32767,32767,32767,32767,32767,32767,32767,
-          529,32767,  546,  559,  432,  433,  435,  544,  457,  458,
-          459,  460,  461,  462,  463,  465,  591,32767,  502,32767,
-        32767,32767,  338,  601,32767,  601,32767,32767,32767,32767,
+          195,  515,32767,32767,32767,32767,32767,32767,32767,32767,
+        32767,32767,  508,32767,32767,32767,32767,32767,32767,32767,
+        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
+          496,  434,  139,32767,  139,  542,  426,  427,  428,  498,
+          542,  542,  542,  312,  289,32767,32767,32767,32767,  513,
+          513,  101,  101,  101,  101,  508,32767,32767,32767,32767,
+          112,  100,  100,  100,  100,  100,  104,  102,32767,32767,
+        32767,32767,  223,  100,32767,  102,  102,32767,32767,  223,
+          225,  212,  102,  227,32767,  561,  562,  223,  102,  227,
+          227,  227,  247,  247,  485,  318,  102,  100,  102,  102,
+          197,  318,  318,32767,  102,  485,  318,  485,  318,  199,
+          318,  318,  318,  485,  318,32767,  102,  318,  214,  100,
+          100,  318,32767,32767,32767,  498,32767,32767,32767,32767,
+        32767,32767,32767,  222,32767,32767,32767,32767,32767,32767,
+        32767,  529,32767,  546,  559,  432,  433,  435,  544,  457,
+          458,  459,  460,  461,  462,  463,  465,  591,32767,  502,
+        32767,32767,32767,  338,  601,32767,  601,32767,32767,32767,
         32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
-        32767,  602,32767,  542,32767,32767,32767,32767,  431,    9,
-           76,  491,   43,   44,   52,   58,  519,  520,  521,  522,
-          516,  517,  523,  518,32767,32767,  524,  567,32767,32767,
-          543,  594,32767,32767,32767,32767,32767,32767,  139,32767,
+        32767,32767,  602,32767,  542,32767,32767,32767,32767,  431,
+            9,   76,  491,   43,   44,   52,   58,  519,  520,  521,
+          522,  516,  517,  523,  518,32767,32767,  524,  567,32767,
+        32767,  543,  594,32767,32767,32767,32767,32767,32767,  139,
         32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
-          529,32767,  137,32767,32767,32767,32767,32767,32767,32767,
-        32767,  525,32767,32767,32767,  542,32767,32767,32767,32767,
-          314,  311,32767,32767,32767,32767,32767,32767,32767,32767,
-        32767,32767,32767,32767,32767,32767,32767,32767,  542,32767,
-        32767,32767,32767,32767,  291,32767,  308,32767,32767,32767,
+        32767,  529,32767,  137,32767,32767,32767,32767,32767,32767,
+        32767,32767,  525,32767,32767,32767,  542,32767,32767,32767,
+        32767,  314,  311,32767,32767,32767,32767,32767,32767,32767,
+        32767,32767,32767,32767,32767,32767,32767,32767,32767,  542,
+        32767,32767,32767,32767,32767,  291,32767,  308,32767,32767,
         32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
-        32767,32767,32767,  286,32767,32767,  381,  498,  294,  296,
-          297,32767,32767,32767,32767,  360,32767,32767,32767,32767,
-        32767,32767,32767,32767,32767,32767,32767,  153,  153,    3,
-            3,  341,  153,  153,  153,  341,  341,  153,  341,  341,
-          341,  153,  153,  153,  153,  153,  153,  280,  185,  262,
-          265,  247,  247,  153,  352,  153
+        32767,32767,32767,32767,  286,32767,32767,  381,  498,  294,
+          296,  297,32767,32767,32767,32767,  360,32767,32767,32767,
+        32767,32767,32767,32767,32767,32767,32767,32767,  153,  153,
+            3,    3,  341,  153,  153,  153,  341,  341,  153,  341,
+          341,  341,  153,  153,  153,  153,  153,  153,  280,  185,
+          262,  265,  247,  247,  153,  352,  153
     );
 
     protected $goto = array(
-          196,  196, 1031,  703,  694,  430,  658, 1062, 1334, 1334,
-          424,  313,  314,  335,  573,  319,  429,  336,  431,  635,
-          651,  652,  850,  669,  670,  671, 1334,  167,  167,  167,
+          196,  196, 1032,  704,  695,  431,  659, 1063, 1335, 1335,
+          425,  313,  314,  335,  574,  319,  430,  336,  432,  636,
+          652,  653,  851,  670,  671,  672, 1335,  167,  167,  167,
           167,  221,  197,  193,  193,  177,  179,  216,  193,  193,
           193,  193,  193,  194,  194,  194,  194,  194,  194,  188,
-          189,  190,  191,  192,  218,  216,  219,  534,  535,  420,
-          536,  538,  539,  540,  541,  542,  543,  544,  545, 1132,
+          189,  190,  191,  192,  218,  216,  219,  535,  536,  421,
+          537,  539,  540,  541,  542,  543,  544,  545,  546, 1133,
           168,  169,  170,  195,  171,  172,  173,  166,  174,  175,
           176,  178,  215,  217,  220,  238,  243,  244,  245,  257,
           258,  259,  260,  261,  262,  263,  264,  268,  269,  270,
-          271,  281,  282,  316,  317,  318,  425,  426,  427,  578,
+          271,  281,  282,  316,  317,  318,  426,  427,  428,  579,
           222,  223,  224,  225,  226,  227,  228,  229,  230,  231,
           232,  233,  234,  235,  236,  180,  237,  181,  198,  199,
-          200,  239,  188,  189,  190,  191,  192,  218, 1132,  201,
+          200,  239,  188,  189,  190,  191,  192,  218, 1133,  201,
           182,  183,  184,  202,  198,  185,  240,  203,  201,  165,
           204,  205,  186,  206,  207,  208,  187,  209,  210,  211,
-          212,  213,  214,  853,  851,  278,  278,  278,  278,  418,
-          620,  620,  350,  570,  597, 1265, 1265, 1265, 1265, 1265,
-         1265, 1265, 1265, 1265, 1265, 1283, 1283,  831,  618,  655,
-         1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283, 1283,
-          353,  353,  353,  353,  866,  557,  550,  858,  825,  907,
-          902,  903,  916,  859,  904,  856,  905,  906,  857,  878,
-          457,  910,  865,  884,  546,  546,  546,  546,  831,  601,
-          831, 1084, 1079, 1080, 1081,  341,  550,  557,  566,  567,
-          343,  576,  599,  613,  614,  407,  408,  972,  465,  465,
-          667,   15,  668, 1323,  411,  412,  413,  465,  681,  348,
-         1233,  414, 1233,  478,  569,  346,  439, 1031, 1031, 1233,
-          993,  480, 1031,  393, 1031, 1031, 1104, 1105, 1031, 1031,
-         1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1315,
-         1315, 1315, 1315, 1233,  657, 1333, 1333, 1055, 1233, 1233,
-         1233, 1233, 1037, 1036, 1233, 1233, 1233, 1034, 1034, 1181,
-          354,  678,  949, 1333,  437, 1026, 1042, 1043,  337,  691,
-          354,  354,  827,  923,  691, 1040, 1041,  924,  691,  663,
-         1336,  939,  871,  939,  354,  354, 1281, 1281,  354,  679,
-         1350, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281, 1281,
-         1281,  552,  537,  537,  911,  354,  912,  537,  537,  537,
-          537,  537,  537,  537,  537,  537,  537,  548,  564,  548,
-          574,  611,  730,  634,  636,  849,  548,  656,  475, 1308,
-         1309,  680,  684, 1007,  692,  701, 1003,  252,  252,  996,
-          970,  970,  968,  970,  729,  843,  549, 1005, 1000,  423,
-          455,  608, 1294,  846,  955,  966,  966,  966,  966,  325,
-          308,  455,  960,  967,  249,  249,  249,  249,  251,  253,
-          402,  351,  352,  683,  868,  551,  561,  449,  449,  449,
-          551, 1305,  561, 1305,  612,  396,  461, 1010, 1010, 1224,
-         1305,  395,  398,  558,  598,  602, 1015,  468,  577,  469,
-          470, 1310, 1311,  876,  552,  846, 1341, 1342,  964,  409,
-          702,  733,  324,  275,  324, 1317, 1317, 1317, 1317,  606,
-          621,  624,  625,  626,  627,  648,  649,  650,  705, 1068,
-          596, 1097,  874,  706,  476, 1228,  507,  697,  880, 1095,
-         1115,  432, 1301,  628,  630,  632,  432,  879,  867, 1067,
-         1071,    5, 1072,    6, 1038, 1038,  977,    0,  975,  662,
-         1049, 1045, 1046,    0,    0,    0,    0, 1226,  449,  449,
-          449,  449,  449,  449,  449,  449,  449,  449,  449,  928,
-         1120,  449,  965, 1070,    0,    0,  616, 1303, 1303, 1070,
-         1229, 1230, 1012,  499,    0,  500,    0,    0,  841,    0,
-          870,  506,  661,  991, 1113,  883, 1212,  941,  864,    0,
-         1213, 1216,  942, 1217,    0,    0, 1231, 1291, 1292,    0,
-         1223,    0,    0,    0,  846,    0,    0,    0,    0,    0,
+          212,  213,  214,  854,  619,  656,  278,  278,  278,  278,
+          852,  621,  621,  350,  419,  598, 1266, 1266, 1266, 1266,
+         1266, 1266, 1266, 1266, 1266, 1266, 1284, 1284,  832, 1105,
+         1106, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284, 1284,
+         1284,  353,  353,  353,  353,  826,  558,  551,  908,  903,
+          904,  917,  860,  905,  857,  906,  907,  858, 1035, 1035,
+          911,  864,  679,  950,  458,  863, 1027, 1043, 1044,  832,
+          885,  832, 1085, 1080, 1081, 1082,  341,  551,  558,  567,
+          568,  343,  577,  600,  614,  615,  547,  547,  547,  547,
+          973,  602,   15,  394,  397,  559,  599,  603, 1213,  942,
+         1234,  571, 1234, 1214, 1217,  943, 1218, 1032, 1032, 1234,
+          440,  912, 1032,  913, 1032, 1032, 1038, 1037, 1032, 1032,
+         1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1316,
+         1316, 1316, 1316, 1234,  476, 1309, 1310,  348, 1234, 1234,
+         1234, 1234,  407,  408, 1234, 1234, 1234,  668, 1324,  669,
+          354,  412,  413,  414,  867,  682,  466,  466,  415,  994,
+          354,  354,  346,  924,  424,  466,  609,  925,    5,  879,
+            6,  940,  866,  940,  354,  354, 1282, 1282,  354,  392,
+         1351, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282, 1282,
+         1282,  553,  538,  538,  570,  354,  658,  538,  538,  538,
+          538,  538,  538,  538,  538,  538,  538,  549,  565,  549,
+         1041, 1042,  731,  635,  637,  850,  549,  657,  965,  410,
+          703,  681,  685, 1008,  693,  702, 1004,  252,  252,  997,
+          971,  971,  969,  971,  730, 1056,  550, 1006, 1001, 1182,
+          456,  847, 1295, 1334, 1334,  967,  967,  967,  967,  325,
+          308,  456,  961,  968,  249,  249,  249,  249,  251,  253,
+          438, 1334,  351,  352,  684,  680,  552,  562,  450,  450,
+          450,  552, 1306,  562, 1306,  479,  395,  462, 1337, 1311,
+         1312, 1306,  664,  481,  500,  337,  501,  844,  469,  578,
+          470,  471,  507,  847,  877,  553,  872, 1342, 1343, 1011,
+         1011,  575,  612,  324,  275,  324, 1318, 1318, 1318, 1318,
+          607,  622,  625,  626,  627,  628,  649,  650,  651,  706,
+          956,  401,  692,  875, 1229,  828,  869,  692,  629,  631,
+          633,  692,  433, 1302, 1225,  734,  613,  433,  880,  868,
+         1068, 1072, 1069, 1016,  477, 1039, 1039,  881,    0,  976,
+          663, 1050, 1046, 1047, 1073, 1116,  978,    0, 1227,  450,
+          450,  450,  450,  450,  450,  450,  450,  450,  450,  450,
+          929, 1121,  450,  966, 1071,    0,    0,  617, 1304, 1304,
+         1071, 1230, 1231, 1013,    0,    0,    0,    0,    0,  842,
+            0,  871,    0,  662,  992, 1114,  884,  597, 1098,  865,
+          707,    0,    0,  508,  698,    0, 1096, 1232, 1292, 1293,
+            0, 1224,    0,  847,    0,    0,    0,    0,    0,    0,
             0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
             0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
             0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
@@ -779,48 +780,48 @@ class Php7 extends \PhpParser\ParserAbstract
            42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
            42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
            42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
-           42,   42,   42,   15,   27,   23,   23,   23,   23,   43,
-          107,  107,   96,  170,  129,  107,  107,  107,  107,  107,
-          107,  107,  107,  107,  107,  168,  168,   12,   55,   55,
-          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
-           24,   24,   24,   24,   35,   75,   75,   15,    6,   15,
-           15,   15,   15,   15,   15,   15,   15,   15,   15,   35,
-           82,   15,   35,   45,  106,  106,  106,  106,   12,  106,
-           12,   15,   15,   15,   15,   75,   75,   75,   75,   75,
-           75,   75,   75,   75,   75,   81,   81,   49,  148,  148,
-           81,   75,   81,  179,   81,   81,   81,  148,   81,  177,
-           72,   81,   72,   83,  103,   81,   82,   72,   72,   72,
-          102,   83,   72,   61,   72,   72,  143,  143,   72,   72,
+           42,   42,   42,   15,   55,   55,   23,   23,   23,   23,
+           27,  107,  107,   96,   43,  129,  107,  107,  107,  107,
+          107,  107,  107,  107,  107,  107,  168,  168,   12,  143,
+          143,  168,  168,  168,  168,  168,  168,  168,  168,  168,
+          168,   24,   24,   24,   24,    6,   75,   75,   15,   15,
+           15,   15,   15,   15,   15,   15,   15,   15,   88,   88,
+           15,   15,   88,   88,   82,   15,   88,   88,   88,   12,
+           45,   12,   15,   15,   15,   15,   75,   75,   75,   75,
+           75,   75,   75,   75,   75,   75,  106,  106,  106,  106,
+           49,  106,   75,   58,   58,   58,   58,   58,   78,   78,
+           72,  170,   72,   78,   78,   78,   78,   72,   72,   72,
+           82,   64,   72,   64,   72,   72,  117,  117,   72,   72,
            72,   72,   72,   72,   72,   72,   72,   72,   72,    9,
-            9,    9,    9,   72,   63,  180,  180,  113,   72,   72,
-           72,   72,  117,  117,   72,   72,   72,   88,   88,  150,
-           14,   88,   88,  180,  112,   88,   88,   88,   29,    7,
-           14,   14,    7,   72,    7,  118,  118,   72,    7,  119,
-          180,    9,   39,    9,   14,   14,  169,  169,   14,  115,
+            9,    9,    9,   72,  174,  174,  174,  177,   72,   72,
+           72,   72,   81,   81,   72,   72,   72,   81,  179,   81,
+           14,   81,   81,   81,   35,   81,  148,  148,   81,  102,
+           14,   14,   81,   72,   13,  148,   13,   72,   46,   35,
+           46,    9,   35,    9,   14,   14,  169,  169,   14,   61,
            14,  169,  169,  169,  169,  169,  169,  169,  169,  169,
-          169,   14,  171,  171,   64,   14,   64,  171,  171,  171,
+          169,   14,  171,  171,  103,   14,   63,  171,  171,  171,
           171,  171,  171,  171,  171,  171,  171,   19,   48,   19,
-            2,    2,   48,   48,   48,   25,   19,   48,  174,  174,
-          174,   48,   48,   48,   48,   48,   48,    5,    5,   25,
-           25,   25,   25,   25,   25,   18,   25,   25,   25,   13,
-           19,   13,   14,   22,   91,   19,   19,   19,   19,  167,
+          118,  118,   48,   48,   48,   25,   19,   48,   92,   92,
+           92,   48,   48,   48,   48,   48,   48,    5,    5,   25,
+           25,   25,   25,   25,   25,  113,   25,   25,   25,  150,
+           19,   22,   14,  180,  180,   19,   19,   19,   19,  167,
           167,   19,   19,   19,    5,    5,    5,    5,    5,    5,
-           28,   96,   96,   14,   37,    9,    9,   23,   23,   23,
-            9,  129,    9,  129,   79,    9,    9,  106,  106,  159,
-          129,   58,   58,   58,   58,   58,  109,    9,    9,    9,
-            9,  176,  176,    9,   14,   22,    9,    9,   92,   92,
-           92,   98,   24,   24,   24,  129,  129,  129,  129,   80,
-           80,   80,   80,   80,   80,   80,   80,   80,   80,  128,
-            8,    8,    9,    8,  156,   20,    8,    8,   41,    8,
-          146,  116,  129,   84,   84,   84,  116,   16,   16,   16,
-           16,   46,  131,   46,  116,  116,   95,   -1,   16,  116,
-          116,  116,  116,   -1,   -1,   -1,   -1,   14,   23,   23,
-           23,   23,   23,   23,   23,   23,   23,   23,   23,   17,
-           17,   23,   16,  129,   -1,   -1,   17,  129,  129,  129,
-           20,   20,   17,  154,   -1,  154,   -1,   -1,   20,   -1,
-           17,  154,   17,   17,   16,   16,   78,   78,   17,   -1,
-           78,   78,   78,   78,   -1,   -1,   20,   20,   20,   -1,
-           17,   -1,   -1,   -1,   22,   -1,   -1,   -1,   -1,   -1,
+          112,  180,   96,   96,   14,  115,    9,    9,   23,   23,
+           23,    9,  129,    9,  129,   83,    9,    9,  180,  176,
+          176,  129,  119,   83,  154,   29,  154,   18,    9,    9,
+            9,    9,  154,   22,    9,   14,   39,    9,    9,  106,
+          106,    2,    2,   24,   24,   24,  129,  129,  129,  129,
+           80,   80,   80,   80,   80,   80,   80,   80,   80,   80,
+           91,   28,    7,    9,   20,    7,   37,    7,   84,   84,
+           84,    7,  116,  129,  159,   98,   79,  116,   16,   16,
+           16,   16,  128,  109,  156,  116,  116,   41,   -1,   16,
+          116,  116,  116,  116,  131,  146,   95,   -1,   14,   23,
+           23,   23,   23,   23,   23,   23,   23,   23,   23,   23,
+           17,   17,   23,   16,  129,   -1,   -1,   17,  129,  129,
+          129,   20,   20,   17,   -1,   -1,   -1,   -1,   -1,   20,
+           -1,   17,   -1,   17,   17,   16,   16,    8,    8,   17,
+            8,   -1,   -1,    8,    8,   -1,    8,   20,   20,   20,
+           -1,   17,   -1,   22,   -1,   -1,   -1,   -1,   -1,   -1,
            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
            -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
@@ -829,47 +830,47 @@ class Php7 extends \PhpParser\ParserAbstract
     );
 
     protected $gotoBase = array(
-            0,    0, -339,    0,    0,  386,  195,  312,  472,  -10,
-            0,    0, -109,   62,   13, -184,   46,   65,   86,  102,
-           93,    0,  125,  162,  197,  371,   18,  160,   83,   22,
-            0,    0,    0,    0,    0, -166,    0,   85,    0,    9,
-            0,   48,   -1,  157,    0,  207, -232,    0, -340,  223,
-            0,    0,    0,    0,    0,  148,    0,    0,  396,    0,
-            0,  231,    0,   52,  334, -236,    0,    0,    0,    0,
-            0,    0,   -5,    0,    0, -139,    0,    0,  149,   91,
-          112, -245,  -58, -205,   15, -695,    0,    0,   28,    0,
-            0,   75,  154,    0,    0,   64, -310,    0,   55,    0,
-            0,    0,  235,  221,    0,    0,  196,  -71,    0,   77,
-            0,    0,   37,   24,    0,   56,  219,   23,   40,   39,
-            0,    0,    0,    0,    0,    0,    5,    0,  106,  166,
-            0,   61,    0,    0,    0,    0,    0,    0,    0,    0,
-            0,    0,    0,    1,    0,    0,   47,    0,  214,    0,
-           35,    0,    0,    0,   49,    0,   45,    0,    0,   71,
-            0,    0,    0,    0,    0,    0,    0,   88,  -56,   95,
-          144,  111,    0,    0,   78,    0,   80,  229,    0,  222,
-          -12, -299,    0,    0
+            0,    0, -249,    0,    0,  386,  192,  475,  549,  -10,
+            0,    0, -108,  -13,   13, -184,   46,   65,  138,  102,
+           93,    0,  123,  163,  198,  371,   18,  166,  144,  149,
+            0,    0,    0,    0,    0,  -56,    0,  147,    0,  133,
+            0,   66,   -1,  162,    0,  214, -406,    0, -341,  226,
+            0,    0,    0,    0,    0,  124,    0,    0,  208,    0,
+            0,  297,    0,  114,  251, -236,    0,    0,    0,    0,
+            0,    0,   -5,    0,    0, -138,    0,    0, -149,  153,
+          113, -189,  -54,  -34,    9, -696,    0,    0,  -61,    0,
+            0,  151,   74,    0,    0,   73, -310,    0,   89,    0,
+            0,    0,  284,  311,    0,    0,  218,  -70,    0,  134,
+            0,    0,  143,  122,    0,  142,  220,   -3,   85,  152,
+            0,    0,    0,    0,    0,    0,    5,    0,  129,  167,
+            0,   72,    0,    0,    0,    0,    0,    0,    0,    0,
+            0,    0,    0,  -86,    0,    0,   71,    0,  282,    0,
+          125,    0,    0,    0,  -51,    0,   64,    0,    0,  126,
+            0,    0,    0,    0,    0,    0,    0,   88,  -55,   95,
+          232,  111,    0,    0,   -6,    0,   68,  267,    0,  277,
+           96, -299,    0,    0
     );
 
     protected $gotoDefault = array(
-        -32768,  511,  737,    4,  738,  932,  814,  823,  594,  528,
-          704,  347,  622,  421, 1299,  909, 1119,  575,  842, 1242,
-         1250,  456,  845,  330,  727,  891,  892,  893,  399,  385,
-          391,  397,  646,  623,  493,  877,  452,  869,  485,  872,
-          451,  881,  164,  417,  509,  885,    3,  888,  554,  919,
-          386,  896,  387,  674,  898,  560,  900,  901,  394,  400,
-          401, 1124,  568,  619,  913,  256,  562,  914,  384,  915,
-          922,  389,  392,  685,  464,  504,  498,  410, 1099,  563,
-          605,  643,  446,  472,  617,  629,  615,  479,  433,  415,
-          329,  954,  962,  486,  462,  976,  349,  984,  735, 1131,
-          637,  488,  992,  638,  999, 1002,  529,  530,  477, 1014,
-          272, 1017,  489,   12,  664, 1028, 1029,  665,  639, 1051,
-          640,  666,  641, 1053,  471,  595, 1061,  453, 1069, 1287,
-          454, 1073,  266, 1076,  277,  416,  434, 1082, 1083,    9,
-         1089,  695,  696,   11,  276,  508, 1114,  686,  450, 1130,
-          438, 1200, 1202,  556,  490, 1220, 1219,  677,  505, 1225,
-          447, 1290,  448,  531,  473,  315,  532,  307,  333,  312,
-          547,  294,  334,  533,  474, 1296, 1304,  331,   31, 1324,
-         1335,  342,  572,  610
+        -32768,  512,  738,    4,  739,  933,  815,  824,  595,  529,
+          705,  347,  623,  422, 1300,  910, 1120,  576,  843, 1243,
+         1251,  457,  846,  330,  728,  892,  893,  894,  398,  385,
+          859,  396,  647,  624,  494,  878,  453,  870,  486,  873,
+          452,  882,  164,  418,  510,  886,    3,  889,  555,  920,
+          386,  897,  387,  675,  899,  561,  901,  902,  393,  399,
+          400, 1125,  569,  620,  914,  256,  563,  915,  384,  916,
+          923,  389,  391,  686,  465,  505,  499,  411, 1100,  564,
+          606,  644,  447,  473,  618,  630,  616,  480,  434,  416,
+          329,  955,  963,  487,  463,  977,  349,  985,  736, 1132,
+          638,  489,  993,  639, 1000, 1003,  530,  531,  478, 1015,
+          272, 1018,  490,   12,  665, 1029, 1030,  666,  640, 1052,
+          641,  667,  642, 1054,  472,  596, 1062,  454, 1070, 1288,
+          455, 1074,  266, 1077,  277,  417,  435, 1083, 1084,    9,
+         1090,  696,  697,   11,  276,  509, 1115,  687,  451, 1131,
+          439, 1201, 1203,  557,  491, 1221, 1220,  678,  506, 1226,
+          448, 1291,  449,  532,  474,  315,  533,  307,  333,  312,
+          548,  294,  334,  534,  475, 1297, 1305,  331,   31, 1325,
+         1336,  342,  573,  611
     );
 
     protected $ruleToNonTerminal = array(
@@ -950,7 +951,7 @@ class Php7 extends \PhpParser\ParserAbstract
             1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
             0,    1,    0,    1,    1,    2,    1,    3,    4,    1,
             2,    0,    1,    1,    1,    1,    1,    3,    5,    4,
-            3,    4,    2,    3,    1,    1,    7,    6,    2,    3,
+            3,    4,    1,    3,    1,    1,    8,    7,    2,    3,
             1,    2,    3,    1,    2,    3,    1,    1,    3,    1,
             3,    1,    2,    2,    3,    1,    3,    2,    3,    1,
             3,    3,    2,    0,    1,    1,    1,    1,    1,    3,
@@ -1378,7 +1379,7 @@ protected function initReduceCallbacks() {
                  $this->semValue = new Stmt\Use_($this->semStack[$stackPos-(4-3)], $this->semStack[$stackPos-(4-2)], $this->startAttributeStack[$stackPos-(4-1)] + $this->endAttributes);
             },
             122 => function ($stackPos) {
-                 $this->semValue = $this->semStack[$stackPos-(2-1)];
+                 $this->semValue = $this->semStack[$stackPos-(1-1)];
             },
             123 => function ($stackPos) {
                  $this->semValue = new Stmt\Const_($this->semStack[$stackPos-(3-2)], $this->startAttributeStack[$stackPos-(3-1)] + $this->endAttributes);
@@ -1390,10 +1391,10 @@ protected function initReduceCallbacks() {
                  $this->semValue = Stmt\Use_::TYPE_CONSTANT;
             },
             126 => function ($stackPos) {
-                 $this->semValue = new Stmt\GroupUse($this->semStack[$stackPos-(7-3)], $this->semStack[$stackPos-(7-6)], $this->semStack[$stackPos-(7-2)], $this->startAttributeStack[$stackPos-(7-1)] + $this->endAttributes);
+                 $this->semValue = new Stmt\GroupUse($this->semStack[$stackPos-(8-3)], $this->semStack[$stackPos-(8-6)], $this->semStack[$stackPos-(8-2)], $this->startAttributeStack[$stackPos-(8-1)] + $this->endAttributes);
             },
             127 => function ($stackPos) {
-                 $this->semValue = new Stmt\GroupUse($this->semStack[$stackPos-(6-2)], $this->semStack[$stackPos-(6-5)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos-(6-1)] + $this->endAttributes);
+                 $this->semValue = new Stmt\GroupUse($this->semStack[$stackPos-(7-2)], $this->semStack[$stackPos-(7-5)], Stmt\Use_::TYPE_UNKNOWN, $this->startAttributeStack[$stackPos-(7-1)] + $this->endAttributes);
             },
             128 => function ($stackPos) {
                  $this->semValue = $this->semStack[$stackPos-(2-1)];
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php b/app/vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php
index 9f9d00c76..567e09a97 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php
@@ -155,7 +155,7 @@ public function __construct(Lexer $lexer, array $options = []) {
      * @return Node\Stmt[]|null Array of statements (or null non-throwing error handler is used and
      *                          the parser was unable to recover from an error).
      */
-    public function parse(string $code, ErrorHandler $errorHandler = null) {
+    public function parse(string $code, ?ErrorHandler $errorHandler = null) {
         $this->errorHandler = $errorHandler ?: new ErrorHandler\Throwing;
 
         $this->lexer->startLexing($code, $this->errorHandler);
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/ParserFactory.php b/app/vendor/nikic/php-parser/lib/PhpParser/ParserFactory.php
index baba23bdb..98b0aee34 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/ParserFactory.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/ParserFactory.php
@@ -21,7 +21,7 @@ class ParserFactory
      *
      * @return Parser The parser instance
      */
-    public function create(int $kind, Lexer $lexer = null, array $parserOptions = []) : Parser {
+    public function create(int $kind, ?Lexer $lexer = null, array $parserOptions = []) : Parser {
         if (null === $lexer) {
             $lexer = new Lexer\Emulative();
         }
diff --git a/app/vendor/nikic/php-parser/lib/PhpParser/PrettyPrinterAbstract.php b/app/vendor/nikic/php-parser/lib/PhpParser/PrettyPrinterAbstract.php
index 770d50092..5d87e5ce8 100644
--- a/app/vendor/nikic/php-parser/lib/PhpParser/PrettyPrinterAbstract.php
+++ b/app/vendor/nikic/php-parser/lib/PhpParser/PrettyPrinterAbstract.php
@@ -658,7 +658,7 @@ protected function p(Node $node, $parentFormatPreserved = false) : string {
                 $result .= $extraLeft;
 
                 $origIndentLevel = $this->indentLevel;
-                $this->setIndentLevel($this->origTokens->getIndentationBefore($subStartPos) + $indentAdjustment);
+                $this->setIndentLevel(max($this->origTokens->getIndentationBefore($subStartPos) + $indentAdjustment, 0));
 
                 // If it's the same node that was previously in this position, it certainly doesn't
                 // need fixup. It's important to check this here, because our fixup checks are more
@@ -761,7 +761,7 @@ protected function pArray(
                 \assert($itemStartPos >= 0 && $itemEndPos >= 0 && $itemStartPos >= $pos);
 
                 $origIndentLevel = $this->indentLevel;
-                $lastElemIndentLevel = $this->origTokens->getIndentationBefore($itemStartPos) + $indentAdjustment;
+                $lastElemIndentLevel = max($this->origTokens->getIndentationBefore($itemStartPos) + $indentAdjustment, 0);
                 $this->setIndentLevel($lastElemIndentLevel);
 
                 $comments = $arrItem->getComments();
diff --git a/app/vendor/phpstan/phpdoc-parser/LICENSE b/app/vendor/phpstan/phpdoc-parser/LICENSE
index 98a854e4f..e5f34e607 100644
--- a/app/vendor/phpstan/phpdoc-parser/LICENSE
+++ b/app/vendor/phpstan/phpdoc-parser/LICENSE
@@ -1,6 +1,7 @@
 MIT License
 
 Copyright (c) 2016 Ondřej Mirtes
+Copyright (c) 2025 PHPStan s.r.o.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -18,4 +19,4 @@ 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.
\ No newline at end of file
+SOFTWARE.
diff --git a/app/vendor/phpstan/phpdoc-parser/README.md b/app/vendor/phpstan/phpdoc-parser/README.md
index 3b321b228..794b47db3 100644
--- a/app/vendor/phpstan/phpdoc-parser/README.md
+++ b/app/vendor/phpstan/phpdoc-parser/README.md
@@ -13,9 +13,9 @@ For the complete list of supported PHPDoc features check out PHPStan documentati
 
 * [PHPDoc Basics](https://phpstan.org/writing-php-code/phpdocs-basics) (list of PHPDoc tags)
 * [PHPDoc Types](https://phpstan.org/writing-php-code/phpdoc-types) (list of PHPDoc types)
-* [phpdoc-parser API Reference](https://phpstan.github.io/phpdoc-parser/namespace-PHPStan.PhpDocParser.html) with all the AST node types etc.
+* [phpdoc-parser API Reference](https://phpstan.github.io/phpdoc-parser/2.2.x/namespace-PHPStan.PhpDocParser.html) with all the AST node types etc.
 
-This parser also supports parsing [Doctrine Annotations](https://github.com/doctrine/annotations). The AST nodes live in the [PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine namespace](https://phpstan.github.io/phpdoc-parser/namespace-PHPStan.PhpDocParser.Ast.PhpDoc.Doctrine.html). The support needs to be turned on by setting `bool $parseDoctrineAnnotations` to `true` in `Lexer` and `PhpDocParser` class constructors.
+This parser also supports parsing [Doctrine Annotations](https://github.com/doctrine/annotations). The AST nodes live in the [PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine namespace](https://phpstan.github.io/phpdoc-parser/2.1.x/namespace-PHPStan.PhpDocParser.Ast.PhpDoc.Doctrine.html).
 
 ## Installation
 
@@ -34,6 +34,7 @@ use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode;
 use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
 use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
 use PHPStan\PhpDocParser\Lexer\Lexer;
+use PHPStan\PhpDocParser\ParserConfig;
 use PHPStan\PhpDocParser\Parser\ConstExprParser;
 use PHPStan\PhpDocParser\Parser\PhpDocParser;
 use PHPStan\PhpDocParser\Parser\TokenIterator;
@@ -41,10 +42,11 @@ use PHPStan\PhpDocParser\Parser\TypeParser;
 
 // basic setup
 
-$lexer = new Lexer();
-$constExprParser = new ConstExprParser();
-$typeParser = new TypeParser($constExprParser);
-$phpDocParser = new PhpDocParser($typeParser, $constExprParser);
+$config = new ParserConfig(usedAttributes: []);
+$lexer = new Lexer($config);
+$constExprParser = new ConstExprParser($config);
+$typeParser = new TypeParser($config, $constExprParser);
+$phpDocParser = new PhpDocParser($config, $typeParser, $constExprParser);
 
 // parsing and reading a PHPDoc string
 
@@ -72,6 +74,7 @@ use PHPStan\PhpDocParser\Ast\NodeVisitor\CloningVisitor;
 use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
 use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
 use PHPStan\PhpDocParser\Lexer\Lexer;
+use PHPStan\PhpDocParser\ParserConfig;
 use PHPStan\PhpDocParser\Parser\ConstExprParser;
 use PHPStan\PhpDocParser\Parser\PhpDocParser;
 use PHPStan\PhpDocParser\Parser\TokenIterator;
@@ -80,12 +83,11 @@ use PHPStan\PhpDocParser\Printer\Printer;
 
 // basic setup with enabled required lexer attributes
 
-$usedAttributes = ['lines' => true, 'indexes' => true];
-
-$lexer = new Lexer();
-$constExprParser = new ConstExprParser(true, true, $usedAttributes);
-$typeParser = new TypeParser($constExprParser, true, $usedAttributes);
-$phpDocParser = new PhpDocParser($typeParser, $constExprParser, true, true, $usedAttributes);
+$config = new ParserConfig(usedAttributes: ['lines' => true, 'indexes' => true, 'comments' => true]);
+$lexer = new Lexer($config);
+$constExprParser = new ConstExprParser($config);
+$typeParser = new TypeParser($config, $constExprParser);
+$phpDocParser = new PhpDocParser($config, $typeParser, $constExprParser);
 
 $tokens = new TokenIterator($lexer->tokenize('/** @param Lorem $a */'));
 $phpDocNode = $phpDocParser->parse($tokens); // PhpDocNode
diff --git a/app/vendor/phpstan/phpdoc-parser/UPGRADING.md b/app/vendor/phpstan/phpdoc-parser/UPGRADING.md
new file mode 100644
index 000000000..b673bccfb
--- /dev/null
+++ b/app/vendor/phpstan/phpdoc-parser/UPGRADING.md
@@ -0,0 +1,129 @@
+Upgrading from phpstan/phpdoc-parser 1.x to 2.0
+=================================
+
+### PHP version requirements
+
+phpstan/phpdoc-parser now requires PHP 7.4 or newer to run.
+
+### Changed constructors of parser classes
+
+Instead of different arrays and boolean values passed into class constructors during setup, parser classes now share a common ParserConfig object.
+
+Before:
+
+```php
+use PHPStan\PhpDocParser\Lexer\Lexer;
+use PHPStan\PhpDocParser\Parser\ConstExprParser;
+use PHPStan\PhpDocParser\Parser\TypeParser;
+use PHPStan\PhpDocParser\Parser\PhpDocParser;
+
+$usedAttributes = ['lines' => true, 'indexes' => true];
+
+$lexer = new Lexer();
+$constExprParser = new ConstExprParser(true, true, $usedAttributes);
+$typeParser = new TypeParser($constExprParser, true, $usedAttributes);
+$phpDocParser = new PhpDocParser($typeParser, $constExprParser, true, true, $usedAttributes);
+```
+
+After:
+
+```php
+use PHPStan\PhpDocParser\Lexer\Lexer;
+use PHPStan\PhpDocParser\ParserConfig;
+use PHPStan\PhpDocParser\Parser\ConstExprParser;
+use PHPStan\PhpDocParser\Parser\TypeParser;
+use PHPStan\PhpDocParser\Parser\PhpDocParser;
+
+$config = new ParserConfig(usedAttributes: ['lines' => true, 'indexes' => true]);
+$lexer = new Lexer($config);
+$constExprParser = new ConstExprParser($config);
+$typeParser = new TypeParser($config, $constExprParser);
+$phpDocParser = new PhpDocParser($config, $typeParser, $constExprParser);
+```
+
+The point of ParserConfig is that over the course of phpstan/phpdoc-parser 2.x development series it's most likely going to gain new optional parameters akin to PHPStan's [bleeding edge](https://phpstan.org/blog/what-is-bleeding-edge). These parameters will allow opting in to new behaviour which will become the default in 3.0.
+
+With ParserConfig object, it's now going to be impossible to configure parser classes inconsistently. Which [happened to users](https://github.com/phpstan/phpdoc-parser/issues/251#issuecomment-2333927959) when they were separate boolean values.
+
+### Support for parsing Doctrine annotations
+
+This parser now supports parsing [Doctrine Annotations](https://github.com/doctrine/annotations). The AST nodes representing Doctrine Annotations live in the [PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine namespace](https://phpstan.github.io/phpdoc-parser/2.0.x/namespace-PHPStan.PhpDocParser.Ast.PhpDoc.Doctrine.html).
+
+### Whitespace before description is required
+
+phpdoc-parser 1.x sometimes silently consumed invalid part of a PHPDoc type as description:
+
+```php
+/** @return \Closure(...int, string): string */
+```
+
+This became `IdentifierTypeNode` of `\Closure` and with `(...int, string): string` as description. (Valid callable syntax is: `\Closure(int ...$u, string): string`.)
+
+Another example:
+
+```php
+/** @return array{foo: int}} */
+```
+
+The extra `}` also became description.
+
+Both of these examples are now InvalidTagValueNode.
+
+If these parts are supposed to be PHPDoc descriptions, you need to put whitespace between the type and the description text:
+
+```php
+/** @return \Closure (...int, string): string */
+/** @return array{foo: int} } */
+```
+
+### Type aliases with invalid types are preserved
+
+In phpdoc-parser 1.x, invalid type alias syntax was represented as [`InvalidTagValueNode`](https://phpstan.github.io/phpdoc-parser/2.0.x/PHPStan.PhpDocParser.Ast.PhpDoc.InvalidTagValueNode.html), losing information about a type alias being present.
+
+```php
+/**
+ * @phpstan-type TypeAlias
+ */
+```
+
+This `@phpstan-type` is missing the actual type to alias. In phpdoc-parser 2.0 this is now represented as [`TypeAliasTagValueNode`](https://phpstan.github.io/phpdoc-parser/2.0.x/PHPStan.PhpDocParser.Ast.PhpDoc.TypeAliasTagValueNode.html) (instead of `InvalidTagValueNode`) with [`InvalidTypeNode`](https://phpstan.github.io/phpdoc-parser/2.0.x/PHPStan.PhpDocParser.Ast.Type.InvalidTypeNode.html) in place of the type.
+
+### Removal of QuoteAwareConstExprStringNode
+
+The class [QuoteAwareConstExprStringNode](https://phpstan.github.io/phpdoc-parser/1.23.x/PHPStan.PhpDocParser.Ast.ConstExpr.QuoteAwareConstExprStringNode.html) has been removed.
+
+Instead, [ConstExprStringNode](https://phpstan.github.io/phpdoc-parser/2.0.x/PHPStan.PhpDocParser.Ast.ConstExpr.ConstExprStringNode.html) gained information about the kind of quotes being used.
+
+### Removed 2nd parameter of `ConstExprParser::parse()` (`$trimStrings`)
+
+`ConstExprStringNode::$value` now contains unescaped values without surrounding `''` or `""` quotes.
+
+Use `ConstExprStringNode::__toString()` or [`Printer`](https://phpstan.github.io/phpdoc-parser/2.0.x/PHPStan.PhpDocParser.Printer.Printer.html) to get the escaped value along with surrounding quotes.
+
+### Text between tags always belongs to description
+
+Multi-line descriptions between tags were previously represented as separate [PhpDocTextNode](https://phpstan.github.io/phpdoc-parser/2.0.x/PHPStan.PhpDocParser.Ast.PhpDoc.PhpDocTextNode.html):
+
+```php
+/**
+ * @param Foo $foo 1st multi world description
+ * some text in the middle
+ * @param Bar $bar 2nd multi world description
+ */
+```
+
+The line with `some text in the middle` in phpdoc-parser 2.0 is now part of the description of the first `@param` tag.
+
+### `ArrayShapeNode` construction changes
+
+`ArrayShapeNode` constructor made private, added public static methods `createSealed()` and `createUnsealed()`.
+
+### Minor BC breaks
+
+* Constructor parameter `$isEquality` in `AssertTag*ValueNode` made required
+* Constructor parameter `$templateTypes` in `MethodTagValueNode` made required
+* Constructor parameter `$isReference` in `ParamTagValueNode` made required
+* Constructor parameter `$isReference` in `TypelessParamTagValueNode` made required
+* Constructor parameter `$templateTypes` in `CallableTypeNode` made required
+* Constructor parameters `$expectedTokenValue` and `$currentTokenLine` in `ParserException` made required
+* `ArrayShapeItemNode` and `ObjectShapeItemNode` are not standalone TypeNode, just Node
diff --git a/app/vendor/phpstan/phpdoc-parser/composer.json b/app/vendor/phpstan/phpdoc-parser/composer.json
index f1c648e51..8047c49e6 100644
--- a/app/vendor/phpstan/phpdoc-parser/composer.json
+++ b/app/vendor/phpstan/phpdoc-parser/composer.json
@@ -3,17 +3,17 @@
 	"description": "PHPDoc parser with support for nullable, intersection and generic types",
 	"license": "MIT",
 	"require": {
-		"php": "^7.2 || ^8.0"
+		"php": "^7.4 || ^8.0"
 	},
 	"require-dev": {
 		"doctrine/annotations": "^2.0",
-		"nikic/php-parser": "^4.15",
+		"nikic/php-parser": "^5.3.0",
 		"php-parallel-lint/php-parallel-lint": "^1.2",
 		"phpstan/extension-installer": "^1.0",
-		"phpstan/phpstan": "^1.5",
-		"phpstan/phpstan-phpunit": "^1.1",
-		"phpstan/phpstan-strict-rules": "^1.0",
-		"phpunit/phpunit": "^9.5",
+		"phpstan/phpstan": "^2.0",
+		"phpstan/phpstan-phpunit": "^2.0",
+		"phpstan/phpstan-strict-rules": "^2.0",
+		"phpunit/phpunit": "^9.6",
 		"symfony/process": "^5.2"
 	},
 	"config": {
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/Attribute.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/Attribute.php
index cd3a0a295..1f770dedc 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/Attribute.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/Attribute.php
@@ -13,4 +13,6 @@ final class Attribute
 
 	public const ORIGINAL_NODE = 'originalNode';
 
+	public const COMMENTS = 'comments';
+
 }
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/Comment.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/Comment.php
new file mode 100644
index 000000000..79e24ebb0
--- /dev/null
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/Comment.php
@@ -0,0 +1,28 @@
+text = $text;
+		$this->startLine = $startLine;
+		$this->startIndex = $startIndex;
+	}
+
+	public function getReformattedText(): string
+	{
+		return trim($this->text);
+	}
+
+}
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayItemNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayItemNode.php
index ef144521c..cd067cac3 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayItemNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayItemNode.php
@@ -10,11 +10,9 @@ class ConstExprArrayItemNode implements ConstExprNode
 
 	use NodeAttributes;
 
-	/** @var ConstExprNode|null */
-	public $key;
+	public ?ConstExprNode $key = null;
 
-	/** @var ConstExprNode */
-	public $value;
+	public ConstExprNode $value;
 
 	public function __construct(?ConstExprNode $key, ConstExprNode $value)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayNode.php
index 1f9def371..dc7ad4a92 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayNode.php
@@ -11,7 +11,7 @@ class ConstExprArrayNode implements ConstExprNode
 	use NodeAttributes;
 
 	/** @var ConstExprArrayItemNode[] */
-	public $items;
+	public array $items;
 
 	/**
 	 * @param ConstExprArrayItemNode[] $items
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFloatNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFloatNode.php
index a4192fba6..30ab41ded 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFloatNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFloatNode.php
@@ -9,8 +9,7 @@ class ConstExprFloatNode implements ConstExprNode
 
 	use NodeAttributes;
 
-	/** @var string */
-	public $value;
+	public string $value;
 
 	public function __construct(string $value)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprIntegerNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprIntegerNode.php
index 5339bb5ae..9f0285f35 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprIntegerNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprIntegerNode.php
@@ -9,8 +9,7 @@ class ConstExprIntegerNode implements ConstExprNode
 
 	use NodeAttributes;
 
-	/** @var string */
-	public $value;
+	public string $value;
 
 	public function __construct(string $value)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprStringNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprStringNode.php
index fa44c2622..26e5ef4a2 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprStringNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprStringNode.php
@@ -3,24 +3,78 @@
 namespace PHPStan\PhpDocParser\Ast\ConstExpr;
 
 use PHPStan\PhpDocParser\Ast\NodeAttributes;
+use function addcslashes;
+use function assert;
+use function dechex;
+use function ord;
+use function preg_replace_callback;
+use function sprintf;
+use function str_pad;
+use function strlen;
+use const STR_PAD_LEFT;
 
 class ConstExprStringNode implements ConstExprNode
 {
 
+	public const SINGLE_QUOTED = 1;
+	public const DOUBLE_QUOTED = 2;
+
 	use NodeAttributes;
 
-	/** @var string */
-	public $value;
+	public string $value;
+
+	/** @var self::SINGLE_QUOTED|self::DOUBLE_QUOTED */
+	public $quoteType;
 
-	public function __construct(string $value)
+	/**
+	 * @param self::SINGLE_QUOTED|self::DOUBLE_QUOTED $quoteType
+	 */
+	public function __construct(string $value, int $quoteType)
 	{
 		$this->value = $value;
+		$this->quoteType = $quoteType;
 	}
 
 
 	public function __toString(): string
 	{
-		return $this->value;
+		if ($this->quoteType === self::SINGLE_QUOTED) {
+			// from https://github.com/nikic/PHP-Parser/blob/0ffddce52d816f72d0efc4d9b02e276d3309ef01/lib/PhpParser/PrettyPrinter/Standard.php#L1007
+			return sprintf("'%s'", addcslashes($this->value, '\'\\'));
+		}
+
+		// from https://github.com/nikic/PHP-Parser/blob/0ffddce52d816f72d0efc4d9b02e276d3309ef01/lib/PhpParser/PrettyPrinter/Standard.php#L1010-L1040
+		return sprintf('"%s"', $this->escapeDoubleQuotedString());
+	}
+
+	private function escapeDoubleQuotedString(): string
+	{
+		$quote = '"';
+		$escaped = addcslashes($this->value, "\n\r\t\f\v$" . $quote . '\\');
+
+		// Escape control characters and non-UTF-8 characters.
+		// Regex based on https://stackoverflow.com/a/11709412/385378.
+		$regex = '/(
+              [\x00-\x08\x0E-\x1F] # Control characters
+            | [\xC0-\xC1] # Invalid UTF-8 Bytes
+            | [\xF5-\xFF] # Invalid UTF-8 Bytes
+            | \xE0(?=[\x80-\x9F]) # Overlong encoding of prior code point
+            | \xF0(?=[\x80-\x8F]) # Overlong encoding of prior code point
+            | [\xC2-\xDF](?![\x80-\xBF]) # Invalid UTF-8 Sequence Start
+            | [\xE0-\xEF](?![\x80-\xBF]{2}) # Invalid UTF-8 Sequence Start
+            | [\xF0-\xF4](?![\x80-\xBF]{3}) # Invalid UTF-8 Sequence Start
+            | (?<=[\x00-\x7F\xF5-\xFF])[\x80-\xBF] # Invalid UTF-8 Sequence Middle
+            | (?value = $value;
 	}
 
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/QuoteAwareConstExprStringNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/QuoteAwareConstExprStringNode.php
deleted file mode 100644
index f2792b1bf..000000000
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/QuoteAwareConstExprStringNode.php
+++ /dev/null
@@ -1,78 +0,0 @@
-quoteType = $quoteType;
-	}
-
-
-	public function __toString(): string
-	{
-		if ($this->quoteType === self::SINGLE_QUOTED) {
-			// from https://github.com/nikic/PHP-Parser/blob/0ffddce52d816f72d0efc4d9b02e276d3309ef01/lib/PhpParser/PrettyPrinter/Standard.php#L1007
-			return sprintf("'%s'", addcslashes($this->value, '\'\\'));
-		}
-
-		// from https://github.com/nikic/PHP-Parser/blob/0ffddce52d816f72d0efc4d9b02e276d3309ef01/lib/PhpParser/PrettyPrinter/Standard.php#L1010-L1040
-		return sprintf('"%s"', $this->escapeDoubleQuotedString());
-	}
-
-	private function escapeDoubleQuotedString(): string
-	{
-		$quote = '"';
-		$escaped = addcslashes($this->value, "\n\r\t\f\v$" . $quote . '\\');
-
-		// Escape control characters and non-UTF-8 characters.
-		// Regex based on https://stackoverflow.com/a/11709412/385378.
-		$regex = '/(
-              [\x00-\x08\x0E-\x1F] # Control characters
-            | [\xC0-\xC1] # Invalid UTF-8 Bytes
-            | [\xF5-\xFF] # Invalid UTF-8 Bytes
-            | \xE0(?=[\x80-\x9F]) # Overlong encoding of prior code point
-            | \xF0(?=[\x80-\x8F]) # Overlong encoding of prior code point
-            | [\xC2-\xDF](?![\x80-\xBF]) # Invalid UTF-8 Sequence Start
-            | [\xE0-\xEF](?![\x80-\xBF]{2}) # Invalid UTF-8 Sequence Start
-            | [\xF0-\xF4](?![\x80-\xBF]{3}) # Invalid UTF-8 Sequence Start
-            | (?<=[\x00-\x7F\xF5-\xFF])[\x80-\xBF] # Invalid UTF-8 Sequence Middle
-            | (? */
-	private $attributes = [];
+	private array $attributes = [];
 
 	/**
 	 * @param mixed $value
 	 */
 	public function setAttribute(string $key, $value): void
 	{
+		if ($value === null) {
+			unset($this->attributes[$key]);
+			return;
+		}
 		$this->attributes[$key] = $value;
 	}
 
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/NodeTraverser.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/NodeTraverser.php
index 63b25c375..76c88f0ce 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/NodeTraverser.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/NodeTraverser.php
@@ -62,10 +62,10 @@ final class NodeTraverser
 	public const DONT_TRAVERSE_CURRENT_AND_CHILDREN = 4;
 
 	/** @var list Visitors */
-	private $visitors = [];
+	private array $visitors = [];
 
 	/** @var bool Whether traversal should be stopped */
-	private $stopTraversal;
+	private bool $stopTraversal;
 
 	/**
 	 * @param list $visitors
@@ -151,7 +151,7 @@ private function traverseNode(Node $node): Node
 						break 2;
 					} else {
 						throw new LogicException(
-							'enterNode() returned invalid value of type ' . gettype($return)
+							'enterNode() returned invalid value of type ' . gettype($return),
 						);
 					}
 				}
@@ -176,11 +176,11 @@ private function traverseNode(Node $node): Node
 						} elseif (is_array($return)) {
 							throw new LogicException(
 								'leaveNode() may only return an array ' .
-								'if the parent structure is an array'
+								'if the parent structure is an array',
 							);
 						} else {
 							throw new LogicException(
-								'leaveNode() returned invalid value of type ' . gettype($return)
+								'leaveNode() returned invalid value of type ' . gettype($return),
 							);
 						}
 					}
@@ -237,7 +237,7 @@ private function traverseArray(array $nodes): array
 						break 2;
 					} else {
 						throw new LogicException(
-							'enterNode() returned invalid value of type ' . gettype($return)
+							'enterNode() returned invalid value of type ' . gettype($return),
 						);
 					}
 				}
@@ -267,7 +267,7 @@ private function traverseArray(array $nodes): array
 							break 2;
 						} else {
 							throw new LogicException(
-								'leaveNode() returned invalid value of type ' . gettype($return)
+								'leaveNode() returned invalid value of type ' . gettype($return),
 							);
 						}
 					}
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor/CloningVisitor.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor/CloningVisitor.php
index 7200f3af4..486e2aaef 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor/CloningVisitor.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor/CloningVisitor.php
@@ -9,7 +9,7 @@
 final class CloningVisitor extends AbstractNodeVisitor
 {
 
-	public function enterNode(Node $originalNode)
+	public function enterNode(Node $originalNode): Node
 	{
 		$node = clone $originalNode;
 		$node->setAttribute(Attribute::ORIGINAL_NODE, $originalNode);
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagMethodValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagMethodValueNode.php
index cf4f55631..0dfee3141 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagMethodValueNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagMethodValueNode.php
@@ -11,25 +11,20 @@ class AssertTagMethodValueNode implements PhpDocTagValueNode
 
 	use NodeAttributes;
 
-	/** @var TypeNode */
-	public $type;
+	public TypeNode $type;
 
-	/** @var string */
-	public $parameter;
+	public string $parameter;
 
-	/** @var string */
-	public $method;
+	public string $method;
 
-	/** @var bool */
-	public $isNegated;
+	public bool $isNegated;
 
-	/** @var bool */
-	public $isEquality;
+	public bool $isEquality;
 
 	/** @var string (may be empty) */
-	public $description;
+	public string $description;
 
-	public function __construct(TypeNode $type, string $parameter, string $method, bool $isNegated, string $description, bool $isEquality = false)
+	public function __construct(TypeNode $type, string $parameter, string $method, bool $isNegated, string $description, bool $isEquality)
 	{
 		$this->type = $type;
 		$this->parameter = $parameter;
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagPropertyValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagPropertyValueNode.php
index 4fb31807f..8bfd1d0e5 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagPropertyValueNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagPropertyValueNode.php
@@ -11,25 +11,20 @@ class AssertTagPropertyValueNode implements PhpDocTagValueNode
 
 	use NodeAttributes;
 
-	/** @var TypeNode */
-	public $type;
+	public TypeNode $type;
 
-	/** @var string */
-	public $parameter;
+	public string $parameter;
 
-	/** @var string */
-	public $property;
+	public string $property;
 
-	/** @var bool */
-	public $isNegated;
+	public bool $isNegated;
 
-	/** @var bool */
-	public $isEquality;
+	public bool $isEquality;
 
 	/** @var string (may be empty) */
-	public $description;
+	public string $description;
 
-	public function __construct(TypeNode $type, string $parameter, string $property, bool $isNegated, string $description, bool $isEquality = false)
+	public function __construct(TypeNode $type, string $parameter, string $property, bool $isNegated, string $description, bool $isEquality)
 	{
 		$this->type = $type;
 		$this->parameter = $parameter;
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagValueNode.php
index d6423f50d..5dc9e8c3c 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagValueNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagValueNode.php
@@ -11,22 +11,18 @@ class AssertTagValueNode implements PhpDocTagValueNode
 
 	use NodeAttributes;
 
-	/** @var TypeNode */
-	public $type;
+	public TypeNode $type;
 
-	/** @var string */
-	public $parameter;
+	public string $parameter;
 
-	/** @var bool */
-	public $isNegated;
+	public bool $isNegated;
 
-	/** @var bool */
-	public $isEquality;
+	public bool $isEquality;
 
 	/** @var string (may be empty) */
-	public $description;
+	public string $description;
 
-	public function __construct(TypeNode $type, string $parameter, bool $isNegated, string $description, bool $isEquality = false)
+	public function __construct(TypeNode $type, string $parameter, bool $isNegated, string $description, bool $isEquality)
 	{
 		$this->type = $type;
 		$this->parameter = $parameter;
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/DeprecatedTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/DeprecatedTagValueNode.php
index abf2f1a64..facdd2b42 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/DeprecatedTagValueNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/DeprecatedTagValueNode.php
@@ -11,7 +11,7 @@ class DeprecatedTagValueNode implements PhpDocTagValueNode
 	use NodeAttributes;
 
 	/** @var string (may be empty) */
-	public $description;
+	public string $description;
 
 	public function __construct(string $description)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineAnnotation.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineAnnotation.php
index 3a93f5aab..778b21fa0 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineAnnotation.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineAnnotation.php
@@ -11,11 +11,10 @@ class DoctrineAnnotation implements Node
 
 	use NodeAttributes;
 
-	/** @var string */
-	public $name;
+	public string $name;
 
 	/** @var list */
-	public $arguments;
+	public array $arguments;
 
 	/**
 	 * @param list $arguments
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArgument.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArgument.php
index f30812cff..30fe98796 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArgument.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArgument.php
@@ -15,8 +15,7 @@ class DoctrineArgument implements Node
 
 	use NodeAttributes;
 
-	/** @var IdentifierTypeNode|null */
-	public $key;
+	public ?IdentifierTypeNode $key = null;
 
 	/** @var ValueType */
 	public $value;
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArray.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArray.php
index e740567d2..06686a521 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArray.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArray.php
@@ -12,7 +12,7 @@ class DoctrineArray implements Node
 	use NodeAttributes;
 
 	/** @var list */
-	public $items;
+	public array $items;
 
 	/**
 	 * @param list $items
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineTagValueNode.php
index 84f7b18b4..3940e24fb 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineTagValueNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineTagValueNode.php
@@ -11,11 +11,10 @@ class DoctrineTagValueNode implements PhpDocTagValueNode
 
 	use NodeAttributes;
 
-	/** @var DoctrineAnnotation */
-	public $annotation;
+	public DoctrineAnnotation $annotation;
 
 	/** @var string (may be empty) */
-	public $description;
+	public string $description;
 
 
 	public function __construct(
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ExtendsTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ExtendsTagValueNode.php
index 3bf53e13c..d9bbeec56 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ExtendsTagValueNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ExtendsTagValueNode.php
@@ -11,11 +11,10 @@ class ExtendsTagValueNode implements PhpDocTagValueNode
 
 	use NodeAttributes;
 
-	/** @var GenericTypeNode */
-	public $type;
+	public GenericTypeNode $type;
 
 	/** @var string (may be empty) */
-	public $description;
+	public string $description;
 
 	public function __construct(GenericTypeNode $type, string $description)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/GenericTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/GenericTagValueNode.php
index 026aa1537..de77051a0 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/GenericTagValueNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/GenericTagValueNode.php
@@ -10,7 +10,7 @@ class GenericTagValueNode implements PhpDocTagValueNode
 	use NodeAttributes;
 
 	/** @var string (may be empty) */
-	public $value;
+	public string $value;
 
 	public function __construct(string $value)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ImplementsTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ImplementsTagValueNode.php
index 99043d912..34a30b0d3 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ImplementsTagValueNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ImplementsTagValueNode.php
@@ -11,11 +11,10 @@ class ImplementsTagValueNode implements PhpDocTagValueNode
 
 	use NodeAttributes;
 
-	/** @var GenericTypeNode */
-	public $type;
+	public GenericTypeNode $type;
 
 	/** @var string (may be empty) */
-	public $description;
+	public string $description;
 
 	public function __construct(GenericTypeNode $type, string $description)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/InvalidTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/InvalidTagValueNode.php
index ca7b4f20a..7bb20b222 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/InvalidTagValueNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/InvalidTagValueNode.php
@@ -17,10 +17,10 @@ class InvalidTagValueNode implements PhpDocTagValueNode
 	use NodeAttributes;
 
 	/** @var string (may be empty) */
-	public $value;
+	public string $value;
 
 	/** @var mixed[] */
-	private $exceptionArgs;
+	private array $exceptionArgs;
 
 	public function __construct(string $value, ParserException $exception)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueNode.php
index 211510bee..223d6e476 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueNode.php
@@ -12,29 +12,26 @@ class MethodTagValueNode implements PhpDocTagValueNode
 
 	use NodeAttributes;
 
-	/** @var bool */
-	public $isStatic;
+	public bool $isStatic;
 
-	/** @var TypeNode|null */
-	public $returnType;
+	public ?TypeNode $returnType = null;
 
-	/** @var string */
-	public $methodName;
+	public string $methodName;
 
 	/** @var TemplateTagValueNode[] */
-	public $templateTypes;
+	public array $templateTypes;
 
 	/** @var MethodTagValueParameterNode[] */
-	public $parameters;
+	public array $parameters;
 
 	/** @var string (may be empty) */
-	public $description;
+	public string $description;
 
 	/**
 	 * @param MethodTagValueParameterNode[] $parameters
 	 * @param TemplateTagValueNode[] $templateTypes
 	 */
-	public function __construct(bool $isStatic, ?TypeNode $returnType, string $methodName, array $parameters, string $description, array $templateTypes = [])
+	public function __construct(bool $isStatic, ?TypeNode $returnType, string $methodName, array $parameters, string $description, array $templateTypes)
 	{
 		$this->isStatic = $isStatic;
 		$this->returnType = $returnType;
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueParameterNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueParameterNode.php
index 7c17e44c9..ebf33e324 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueParameterNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueParameterNode.php
@@ -12,20 +12,15 @@ class MethodTagValueParameterNode implements Node
 
 	use NodeAttributes;
 
-	/** @var TypeNode|null */
-	public $type;
+	public ?TypeNode $type = null;
 
-	/** @var bool */
-	public $isReference;
+	public bool $isReference;
 
-	/** @var bool */
-	public $isVariadic;
+	public bool $isVariadic;
 
-	/** @var string */
-	public $parameterName;
+	public string $parameterName;
 
-	/** @var ConstExprNode|null */
-	public $defaultValue;
+	public ?ConstExprNode $defaultValue = null;
 
 	public function __construct(?TypeNode $type, bool $isReference, bool $isVariadic, string $parameterName, ?ConstExprNode $defaultValue)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MixinTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MixinTagValueNode.php
index d9b7d78a4..7a4e43ead 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MixinTagValueNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MixinTagValueNode.php
@@ -11,11 +11,10 @@ class MixinTagValueNode implements PhpDocTagValueNode
 
 	use NodeAttributes;
 
-	/** @var TypeNode */
-	public $type;
+	public TypeNode $type;
 
 	/** @var string (may be empty) */
-	public $description;
+	public string $description;
 
 	public function __construct(TypeNode $type, string $description)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamClosureThisTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamClosureThisTagValueNode.php
new file mode 100644
index 000000000..54feff9e8
--- /dev/null
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamClosureThisTagValueNode.php
@@ -0,0 +1,33 @@
+type = $type;
+		$this->parameterName = $parameterName;
+		$this->description = $description;
+	}
+
+	public function __toString(): string
+	{
+		return trim("{$this->type} {$this->parameterName} {$this->description}");
+	}
+
+}
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamImmediatelyInvokedCallableTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamImmediatelyInvokedCallableTagValueNode.php
new file mode 100644
index 000000000..9a6761f7d
--- /dev/null
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamImmediatelyInvokedCallableTagValueNode.php
@@ -0,0 +1,29 @@
+parameterName = $parameterName;
+		$this->description = $description;
+	}
+
+	public function __toString(): string
+	{
+		return trim("{$this->parameterName} {$this->description}");
+	}
+
+}
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamLaterInvokedCallableTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamLaterInvokedCallableTagValueNode.php
new file mode 100644
index 000000000..84db67a9c
--- /dev/null
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamLaterInvokedCallableTagValueNode.php
@@ -0,0 +1,29 @@
+parameterName = $parameterName;
+		$this->description = $description;
+	}
+
+	public function __toString(): string
+	{
+		return trim("{$this->parameterName} {$this->description}");
+	}
+
+}
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamOutTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamOutTagValueNode.php
index 9f374bf18..3e89f9d7f 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamOutTagValueNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamOutTagValueNode.php
@@ -11,14 +11,12 @@ class ParamOutTagValueNode implements PhpDocTagValueNode
 
 	use NodeAttributes;
 
-	/** @var TypeNode */
-	public $type;
+	public TypeNode $type;
 
-	/** @var string */
-	public $parameterName;
+	public string $parameterName;
 
 	/** @var string (may be empty) */
-	public $description;
+	public string $description;
 
 	public function __construct(TypeNode $type, string $parameterName, string $description)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamTagValueNode.php
index f93af0ea1..8d1ef27a8 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamTagValueNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamTagValueNode.php
@@ -11,22 +11,18 @@ class ParamTagValueNode implements PhpDocTagValueNode
 
 	use NodeAttributes;
 
-	/** @var TypeNode */
-	public $type;
+	public TypeNode $type;
 
-	/** @var bool */
-	public $isReference;
+	public bool $isReference;
 
-	/** @var bool */
-	public $isVariadic;
+	public bool $isVariadic;
 
-	/** @var string */
-	public $parameterName;
+	public string $parameterName;
 
 	/** @var string (may be empty) */
-	public $description;
+	public string $description;
 
-	public function __construct(TypeNode $type, bool $isVariadic, string $parameterName, string $description, bool $isReference = false)
+	public function __construct(TypeNode $type, bool $isVariadic, string $parameterName, string $description, bool $isReference)
 	{
 		$this->type = $type;
 		$this->isReference = $isReference;
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocNode.php
index 4c509f41b..a3dd3e4cd 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocNode.php
@@ -15,7 +15,7 @@ class PhpDocNode implements Node
 	use NodeAttributes;
 
 	/** @var PhpDocChildNode[] */
-	public $children;
+	public array $children;
 
 	/**
 	 * @param PhpDocChildNode[] $children
@@ -31,9 +31,7 @@ public function __construct(array $children)
 	 */
 	public function getTags(): array
 	{
-		return array_filter($this->children, static function (PhpDocChildNode $child): bool {
-			return $child instanceof PhpDocTagNode;
-		});
+		return array_filter($this->children, static fn (PhpDocChildNode $child): bool => $child instanceof PhpDocTagNode);
 	}
 
 
@@ -42,9 +40,7 @@ public function getTags(): array
 	 */
 	public function getTagsByName(string $tagName): array
 	{
-		return array_filter($this->getTags(), static function (PhpDocTagNode $tag) use ($tagName): bool {
-			return $tag->name === $tagName;
-		});
+		return array_filter($this->getTags(), static fn (PhpDocTagNode $tag): bool => $tag->name === $tagName);
 	}
 
 
@@ -55,9 +51,7 @@ public function getVarTagValues(string $tagName = '@var'): array
 	{
 		return array_filter(
 			array_column($this->getTagsByName($tagName), 'value'),
-			static function (PhpDocTagValueNode $value): bool {
-				return $value instanceof VarTagValueNode;
-			}
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof VarTagValueNode,
 		);
 	}
 
@@ -69,9 +63,7 @@ public function getParamTagValues(string $tagName = '@param'): array
 	{
 		return array_filter(
 			array_column($this->getTagsByName($tagName), 'value'),
-			static function (PhpDocTagValueNode $value): bool {
-				return $value instanceof ParamTagValueNode;
-			}
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof ParamTagValueNode,
 		);
 	}
 
@@ -83,13 +75,57 @@ public function getTypelessParamTagValues(string $tagName = '@param'): array
 	{
 		return array_filter(
 			array_column($this->getTagsByName($tagName), 'value'),
-			static function (PhpDocTagValueNode $value): bool {
-				return $value instanceof TypelessParamTagValueNode;
-			}
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof TypelessParamTagValueNode,
 		);
 	}
 
 
+	/**
+	 * @return ParamImmediatelyInvokedCallableTagValueNode[]
+	 */
+	public function getParamImmediatelyInvokedCallableTagValues(string $tagName = '@param-immediately-invoked-callable'): array
+	{
+		return array_filter(
+			array_column($this->getTagsByName($tagName), 'value'),
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof ParamImmediatelyInvokedCallableTagValueNode,
+		);
+	}
+
+
+	/**
+	 * @return ParamLaterInvokedCallableTagValueNode[]
+	 */
+	public function getParamLaterInvokedCallableTagValues(string $tagName = '@param-later-invoked-callable'): array
+	{
+		return array_filter(
+			array_column($this->getTagsByName($tagName), 'value'),
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof ParamLaterInvokedCallableTagValueNode,
+		);
+	}
+
+
+	/**
+	 * @return ParamClosureThisTagValueNode[]
+	 */
+	public function getParamClosureThisTagValues(string $tagName = '@param-closure-this'): array
+	{
+		return array_filter(
+			array_column($this->getTagsByName($tagName), 'value'),
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof ParamClosureThisTagValueNode,
+		);
+	}
+
+	/**
+	 * @return PureUnlessCallableIsImpureTagValueNode[]
+	 */
+	public function getPureUnlessCallableIsImpureTagValues(string $tagName = '@pure-unless-callable-is-impure'): array
+	{
+		return array_filter(
+			array_column($this->getTagsByName($tagName), 'value'),
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof PureUnlessCallableIsImpureTagValueNode,
+		);
+	}
+
 	/**
 	 * @return TemplateTagValueNode[]
 	 */
@@ -97,9 +133,7 @@ public function getTemplateTagValues(string $tagName = '@template'): array
 	{
 		return array_filter(
 			array_column($this->getTagsByName($tagName), 'value'),
-			static function (PhpDocTagValueNode $value): bool {
-				return $value instanceof TemplateTagValueNode;
-			}
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof TemplateTagValueNode,
 		);
 	}
 
@@ -111,9 +145,7 @@ public function getExtendsTagValues(string $tagName = '@extends'): array
 	{
 		return array_filter(
 			array_column($this->getTagsByName($tagName), 'value'),
-			static function (PhpDocTagValueNode $value): bool {
-				return $value instanceof ExtendsTagValueNode;
-			}
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof ExtendsTagValueNode,
 		);
 	}
 
@@ -125,9 +157,7 @@ public function getImplementsTagValues(string $tagName = '@implements'): array
 	{
 		return array_filter(
 			array_column($this->getTagsByName($tagName), 'value'),
-			static function (PhpDocTagValueNode $value): bool {
-				return $value instanceof ImplementsTagValueNode;
-			}
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof ImplementsTagValueNode,
 		);
 	}
 
@@ -139,9 +169,7 @@ public function getUsesTagValues(string $tagName = '@use'): array
 	{
 		return array_filter(
 			array_column($this->getTagsByName($tagName), 'value'),
-			static function (PhpDocTagValueNode $value): bool {
-				return $value instanceof UsesTagValueNode;
-			}
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof UsesTagValueNode,
 		);
 	}
 
@@ -153,9 +181,7 @@ public function getReturnTagValues(string $tagName = '@return'): array
 	{
 		return array_filter(
 			array_column($this->getTagsByName($tagName), 'value'),
-			static function (PhpDocTagValueNode $value): bool {
-				return $value instanceof ReturnTagValueNode;
-			}
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof ReturnTagValueNode,
 		);
 	}
 
@@ -167,9 +193,7 @@ public function getThrowsTagValues(string $tagName = '@throws'): array
 	{
 		return array_filter(
 			array_column($this->getTagsByName($tagName), 'value'),
-			static function (PhpDocTagValueNode $value): bool {
-				return $value instanceof ThrowsTagValueNode;
-			}
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof ThrowsTagValueNode,
 		);
 	}
 
@@ -181,9 +205,7 @@ public function getMixinTagValues(string $tagName = '@mixin'): array
 	{
 		return array_filter(
 			array_column($this->getTagsByName($tagName), 'value'),
-			static function (PhpDocTagValueNode $value): bool {
-				return $value instanceof MixinTagValueNode;
-			}
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof MixinTagValueNode,
 		);
 	}
 
@@ -194,9 +216,7 @@ public function getRequireExtendsTagValues(string $tagName = '@phpstan-require-e
 	{
 		return array_filter(
 			array_column($this->getTagsByName($tagName), 'value'),
-			static function (PhpDocTagValueNode $value): bool {
-				return $value instanceof RequireExtendsTagValueNode;
-			}
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof RequireExtendsTagValueNode,
 		);
 	}
 
@@ -207,9 +227,18 @@ public function getRequireImplementsTagValues(string $tagName = '@phpstan-requir
 	{
 		return array_filter(
 			array_column($this->getTagsByName($tagName), 'value'),
-			static function (PhpDocTagValueNode $value): bool {
-				return $value instanceof RequireImplementsTagValueNode;
-			}
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof RequireImplementsTagValueNode,
+		);
+	}
+
+	/**
+	 * @return SealedTagValueNode[]
+	 */
+	public function getSealedTagValues(string $tagName = '@phpstan-sealed'): array
+	{
+		return array_filter(
+			array_column($this->getTagsByName($tagName), 'value'),
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof SealedTagValueNode,
 		);
 	}
 
@@ -220,9 +249,7 @@ public function getDeprecatedTagValues(): array
 	{
 		return array_filter(
 			array_column($this->getTagsByName('@deprecated'), 'value'),
-			static function (PhpDocTagValueNode $value): bool {
-				return $value instanceof DeprecatedTagValueNode;
-			}
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof DeprecatedTagValueNode,
 		);
 	}
 
@@ -234,9 +261,7 @@ public function getPropertyTagValues(string $tagName = '@property'): array
 	{
 		return array_filter(
 			array_column($this->getTagsByName($tagName), 'value'),
-			static function (PhpDocTagValueNode $value): bool {
-				return $value instanceof PropertyTagValueNode;
-			}
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof PropertyTagValueNode,
 		);
 	}
 
@@ -248,9 +273,7 @@ public function getPropertyReadTagValues(string $tagName = '@property-read'): ar
 	{
 		return array_filter(
 			array_column($this->getTagsByName($tagName), 'value'),
-			static function (PhpDocTagValueNode $value): bool {
-				return $value instanceof PropertyTagValueNode;
-			}
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof PropertyTagValueNode,
 		);
 	}
 
@@ -262,9 +285,7 @@ public function getPropertyWriteTagValues(string $tagName = '@property-write'):
 	{
 		return array_filter(
 			array_column($this->getTagsByName($tagName), 'value'),
-			static function (PhpDocTagValueNode $value): bool {
-				return $value instanceof PropertyTagValueNode;
-			}
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof PropertyTagValueNode,
 		);
 	}
 
@@ -276,9 +297,7 @@ public function getMethodTagValues(string $tagName = '@method'): array
 	{
 		return array_filter(
 			array_column($this->getTagsByName($tagName), 'value'),
-			static function (PhpDocTagValueNode $value): bool {
-				return $value instanceof MethodTagValueNode;
-			}
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof MethodTagValueNode,
 		);
 	}
 
@@ -290,9 +309,7 @@ public function getTypeAliasTagValues(string $tagName = '@phpstan-type'): array
 	{
 		return array_filter(
 			array_column($this->getTagsByName($tagName), 'value'),
-			static function (PhpDocTagValueNode $value): bool {
-				return $value instanceof TypeAliasTagValueNode;
-			}
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof TypeAliasTagValueNode,
 		);
 	}
 
@@ -304,9 +321,7 @@ public function getTypeAliasImportTagValues(string $tagName = '@phpstan-import-t
 	{
 		return array_filter(
 			array_column($this->getTagsByName($tagName), 'value'),
-			static function (PhpDocTagValueNode $value): bool {
-				return $value instanceof TypeAliasImportTagValueNode;
-			}
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof TypeAliasImportTagValueNode,
 		);
 	}
 
@@ -318,9 +333,7 @@ public function getAssertTagValues(string $tagName = '@phpstan-assert'): array
 	{
 		return array_filter(
 			array_column($this->getTagsByName($tagName), 'value'),
-			static function (PhpDocTagValueNode $value): bool {
-				return $value instanceof AssertTagValueNode;
-			}
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof AssertTagValueNode,
 		);
 	}
 
@@ -332,9 +345,7 @@ public function getAssertPropertyTagValues(string $tagName = '@phpstan-assert'):
 	{
 		return array_filter(
 			array_column($this->getTagsByName($tagName), 'value'),
-			static function (PhpDocTagValueNode $value): bool {
-				return $value instanceof AssertTagPropertyValueNode;
-			}
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof AssertTagPropertyValueNode,
 		);
 	}
 
@@ -346,9 +357,7 @@ public function getAssertMethodTagValues(string $tagName = '@phpstan-assert'): a
 	{
 		return array_filter(
 			array_column($this->getTagsByName($tagName), 'value'),
-			static function (PhpDocTagValueNode $value): bool {
-				return $value instanceof AssertTagMethodValueNode;
-			}
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof AssertTagMethodValueNode,
 		);
 	}
 
@@ -360,9 +369,7 @@ public function getSelfOutTypeTagValues(string $tagName = '@phpstan-this-out'):
 	{
 		return array_filter(
 			array_column($this->getTagsByName($tagName), 'value'),
-			static function (PhpDocTagValueNode $value): bool {
-				return $value instanceof SelfOutTagValueNode;
-			}
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof SelfOutTagValueNode,
 		);
 	}
 
@@ -374,9 +381,7 @@ public function getParamOutTypeTagValues(string $tagName = '@param-out'): array
 	{
 		return array_filter(
 			array_column($this->getTagsByName($tagName), 'value'),
-			static function (PhpDocTagValueNode $value): bool {
-				return $value instanceof ParamOutTagValueNode;
-			}
+			static fn (PhpDocTagValueNode $value): bool => $value instanceof ParamOutTagValueNode,
 		);
 	}
 
@@ -388,7 +393,7 @@ static function (PhpDocChildNode $child): string {
 				$s = (string) $child;
 				return $s === '' ? '' : ' ' . $s;
 			},
-			$this->children
+			$this->children,
 		);
 		return "/**\n *" . implode("\n *", $children) . "\n */";
 	}
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagNode.php
index d20746fcf..cac2feeb9 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagNode.php
@@ -11,11 +11,9 @@ class PhpDocTagNode implements PhpDocChildNode
 
 	use NodeAttributes;
 
-	/** @var string */
-	public $name;
+	public string $name;
 
-	/** @var PhpDocTagValueNode */
-	public $value;
+	public PhpDocTagValueNode $value;
 
 	public function __construct(string $name, PhpDocTagValueNode $value)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTextNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTextNode.php
index 0bca3c99c..97a96894d 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTextNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTextNode.php
@@ -9,8 +9,7 @@ class PhpDocTextNode implements PhpDocChildNode
 
 	use NodeAttributes;
 
-	/** @var string */
-	public $text;
+	public string $text;
 
 	public function __construct(string $text)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PropertyTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PropertyTagValueNode.php
index 046003d18..cbf622f8d 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PropertyTagValueNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PropertyTagValueNode.php
@@ -11,14 +11,12 @@ class PropertyTagValueNode implements PhpDocTagValueNode
 
 	use NodeAttributes;
 
-	/** @var TypeNode */
-	public $type;
+	public TypeNode $type;
 
-	/** @var string */
-	public $propertyName;
+	public string $propertyName;
 
 	/** @var string (may be empty) */
-	public $description;
+	public string $description;
 
 	public function __construct(TypeNode $type, string $propertyName, string $description)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PureUnlessCallableIsImpureTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PureUnlessCallableIsImpureTagValueNode.php
new file mode 100644
index 000000000..1a0cff89a
--- /dev/null
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PureUnlessCallableIsImpureTagValueNode.php
@@ -0,0 +1,29 @@
+parameterName = $parameterName;
+		$this->description = $description;
+	}
+
+	public function __toString(): string
+	{
+		return trim("{$this->parameterName} {$this->description}");
+	}
+
+}
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireExtendsTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireExtendsTagValueNode.php
index 91c268928..5d8e1d22a 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireExtendsTagValueNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireExtendsTagValueNode.php
@@ -11,11 +11,10 @@ class RequireExtendsTagValueNode implements PhpDocTagValueNode
 
 	use NodeAttributes;
 
-	/** @var TypeNode */
-	public $type;
+	public TypeNode $type;
 
 	/** @var string (may be empty) */
-	public $description;
+	public string $description;
 
 	public function __construct(TypeNode $type, string $description)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireImplementsTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireImplementsTagValueNode.php
index 65c9213f8..6b7f7baed 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireImplementsTagValueNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireImplementsTagValueNode.php
@@ -11,11 +11,10 @@ class RequireImplementsTagValueNode implements PhpDocTagValueNode
 
 	use NodeAttributes;
 
-	/** @var TypeNode */
-	public $type;
+	public TypeNode $type;
 
 	/** @var string (may be empty) */
-	public $description;
+	public string $description;
 
 	public function __construct(TypeNode $type, string $description)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ReturnTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ReturnTagValueNode.php
index d53c8c755..c063bf480 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ReturnTagValueNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ReturnTagValueNode.php
@@ -11,11 +11,10 @@ class ReturnTagValueNode implements PhpDocTagValueNode
 
 	use NodeAttributes;
 
-	/** @var TypeNode */
-	public $type;
+	public TypeNode $type;
 
 	/** @var string (may be empty) */
-	public $description;
+	public string $description;
 
 	public function __construct(TypeNode $type, string $description)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/SealedTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/SealedTagValueNode.php
new file mode 100644
index 000000000..230cf3e8d
--- /dev/null
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/SealedTagValueNode.php
@@ -0,0 +1,31 @@
+type = $type;
+		$this->description = $description;
+	}
+
+
+	public function __toString(): string
+	{
+		return trim("{$this->type} {$this->description}");
+	}
+
+}
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/SelfOutTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/SelfOutTagValueNode.php
index 83169aff7..d2377620b 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/SelfOutTagValueNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/SelfOutTagValueNode.php
@@ -11,11 +11,10 @@ class SelfOutTagValueNode implements PhpDocTagValueNode
 
 	use NodeAttributes;
 
-	/** @var TypeNode */
-	public $type;
+	public TypeNode $type;
 
 	/** @var string (may be empty) */
-	public $description;
+	public string $description;
 
 	public function __construct(TypeNode $type, string $description)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TemplateTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TemplateTagValueNode.php
index 1d3c70e4d..ba1068255 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TemplateTagValueNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TemplateTagValueNode.php
@@ -11,22 +11,26 @@ class TemplateTagValueNode implements PhpDocTagValueNode
 
 	use NodeAttributes;
 
-	/** @var string */
-	public $name;
+	/** @var non-empty-string */
+	public string $name;
 
-	/** @var TypeNode|null */
-	public $bound;
+	public ?TypeNode $bound;
 
-	/** @var TypeNode|null */
-	public $default;
+	public ?TypeNode $default;
+
+	public ?TypeNode $lowerBound;
 
 	/** @var string (may be empty) */
-	public $description;
+	public string $description;
 
-	public function __construct(string $name, ?TypeNode $bound, string $description, ?TypeNode $default = null)
+	/**
+	 * @param non-empty-string $name
+	 */
+	public function __construct(string $name, ?TypeNode $bound, string $description, ?TypeNode $default = null, ?TypeNode $lowerBound = null)
 	{
 		$this->name = $name;
 		$this->bound = $bound;
+		$this->lowerBound = $lowerBound;
 		$this->default = $default;
 		$this->description = $description;
 	}
@@ -34,9 +38,10 @@ public function __construct(string $name, ?TypeNode $bound, string $description,
 
 	public function __toString(): string
 	{
-		$bound = $this->bound !== null ? " of {$this->bound}" : '';
+		$upperBound = $this->bound !== null ? " of {$this->bound}" : '';
+		$lowerBound = $this->lowerBound !== null ? " super {$this->lowerBound}" : '';
 		$default = $this->default !== null ? " = {$this->default}" : '';
-		return trim("{$this->name}{$bound}{$default} {$this->description}");
+		return trim("{$this->name}{$upperBound}{$lowerBound}{$default} {$this->description}");
 	}
 
 }
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ThrowsTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ThrowsTagValueNode.php
index 62d2aed3b..dc5521b49 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ThrowsTagValueNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ThrowsTagValueNode.php
@@ -11,11 +11,10 @@ class ThrowsTagValueNode implements PhpDocTagValueNode
 
 	use NodeAttributes;
 
-	/** @var TypeNode */
-	public $type;
+	public TypeNode $type;
 
 	/** @var string (may be empty) */
-	public $description;
+	public string $description;
 
 	public function __construct(TypeNode $type, string $description)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasImportTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasImportTagValueNode.php
index ad6b85a57..d0f945d24 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasImportTagValueNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasImportTagValueNode.php
@@ -11,14 +11,11 @@ class TypeAliasImportTagValueNode implements PhpDocTagValueNode
 
 	use NodeAttributes;
 
-	/** @var string */
-	public $importedAlias;
+	public string $importedAlias;
 
-	/** @var IdentifierTypeNode */
-	public $importedFrom;
+	public IdentifierTypeNode $importedFrom;
 
-	/** @var string|null */
-	public $importedAs;
+	public ?string $importedAs = null;
 
 	public function __construct(string $importedAlias, IdentifierTypeNode $importedFrom, ?string $importedAs)
 	{
@@ -31,7 +28,7 @@ public function __toString(): string
 	{
 		return trim(
 			"{$this->importedAlias} from {$this->importedFrom}"
-			. ($this->importedAs !== null ? " as {$this->importedAs}" : '')
+			. ($this->importedAs !== null ? " as {$this->importedAs}" : ''),
 		);
 	}
 
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasTagValueNode.php
index 4ccaaac4b..ae366b50d 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasTagValueNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasTagValueNode.php
@@ -11,11 +11,9 @@ class TypeAliasTagValueNode implements PhpDocTagValueNode
 
 	use NodeAttributes;
 
-	/** @var string */
-	public $alias;
+	public string $alias;
 
-	/** @var TypeNode */
-	public $type;
+	public TypeNode $type;
 
 	public function __construct(string $alias, TypeNode $type)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypelessParamTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypelessParamTagValueNode.php
index 8b9829549..bb99e7819 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypelessParamTagValueNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypelessParamTagValueNode.php
@@ -10,19 +10,16 @@ class TypelessParamTagValueNode implements PhpDocTagValueNode
 
 	use NodeAttributes;
 
-	/** @var bool */
-	public $isReference;
+	public bool $isReference;
 
-	/** @var bool */
-	public $isVariadic;
+	public bool $isVariadic;
 
-	/** @var string */
-	public $parameterName;
+	public string $parameterName;
 
 	/** @var string (may be empty) */
-	public $description;
+	public string $description;
 
-	public function __construct(bool $isVariadic, string $parameterName, string $description, bool $isReference = false)
+	public function __construct(bool $isVariadic, string $parameterName, string $description, bool $isReference)
 	{
 		$this->isReference = $isReference;
 		$this->isVariadic = $isVariadic;
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/UsesTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/UsesTagValueNode.php
index cd573d975..b33fff607 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/UsesTagValueNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/UsesTagValueNode.php
@@ -11,11 +11,10 @@ class UsesTagValueNode implements PhpDocTagValueNode
 
 	use NodeAttributes;
 
-	/** @var GenericTypeNode */
-	public $type;
+	public GenericTypeNode $type;
 
 	/** @var string (may be empty) */
-	public $description;
+	public string $description;
 
 	public function __construct(GenericTypeNode $type, string $description)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/VarTagValueNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/VarTagValueNode.php
index afb941a83..5b0538c8a 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/VarTagValueNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/VarTagValueNode.php
@@ -11,14 +11,13 @@ class VarTagValueNode implements PhpDocTagValueNode
 
 	use NodeAttributes;
 
-	/** @var TypeNode */
-	public $type;
+	public TypeNode $type;
 
 	/** @var string (may be empty) */
-	public $variableName;
+	public string $variableName;
 
 	/** @var string (may be empty) */
-	public $description;
+	public string $description;
 
 	public function __construct(TypeNode $type, string $variableName, string $description)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeItemNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeItemNode.php
index 660c6c9d2..bed62381d 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeItemNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeItemNode.php
@@ -4,10 +4,11 @@
 
 use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprIntegerNode;
 use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode;
+use PHPStan\PhpDocParser\Ast\Node;
 use PHPStan\PhpDocParser\Ast\NodeAttributes;
 use function sprintf;
 
-class ArrayShapeItemNode implements TypeNode
+class ArrayShapeItemNode implements Node
 {
 
 	use NodeAttributes;
@@ -15,11 +16,9 @@ class ArrayShapeItemNode implements TypeNode
 	/** @var ConstExprIntegerNode|ConstExprStringNode|IdentifierTypeNode|null */
 	public $keyName;
 
-	/** @var bool */
-	public $optional;
+	public bool $optional;
 
-	/** @var TypeNode */
-	public $valueType;
+	public TypeNode $valueType;
 
 	/**
 	 * @param ConstExprIntegerNode|ConstExprStringNode|IdentifierTypeNode|null $keyName
@@ -39,7 +38,7 @@ public function __toString(): string
 				'%s%s: %s',
 				(string) $this->keyName,
 				$this->optional ? '?' : '',
-				(string) $this->valueType
+				(string) $this->valueType,
 			);
 		}
 
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeNode.php
index 806783f98..1d9cf850e 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeNode.php
@@ -10,36 +10,64 @@ class ArrayShapeNode implements TypeNode
 
 	public const KIND_ARRAY = 'array';
 	public const KIND_LIST = 'list';
+	public const KIND_NON_EMPTY_ARRAY = 'non-empty-array';
+	public const KIND_NON_EMPTY_LIST = 'non-empty-list';
 
 	use NodeAttributes;
 
 	/** @var ArrayShapeItemNode[] */
-	public $items;
+	public array $items;
 
-	/** @var bool */
-	public $sealed;
+	public bool $sealed;
 
 	/** @var self::KIND_* */
 	public $kind;
 
+	public ?ArrayShapeUnsealedTypeNode $unsealedType = null;
+
 	/**
 	 * @param ArrayShapeItemNode[] $items
 	 * @param self::KIND_* $kind
 	 */
-	public function __construct(array $items, bool $sealed = true, string $kind = self::KIND_ARRAY)
+	private function __construct(
+		array $items,
+		bool $sealed = true,
+		?ArrayShapeUnsealedTypeNode $unsealedType = null,
+		string $kind = self::KIND_ARRAY
+	)
 	{
 		$this->items = $items;
 		$this->sealed = $sealed;
+		$this->unsealedType = $unsealedType;
 		$this->kind = $kind;
 	}
 
 
+	/**
+	 * @param ArrayShapeItemNode[] $items
+	 * @param self::KIND_* $kind
+	 */
+	public static function createSealed(array $items, string $kind = self::KIND_ARRAY): self
+	{
+		return new self($items, true, null, $kind);
+	}
+
+	/**
+	 * @param ArrayShapeItemNode[] $items
+	 * @param self::KIND_* $kind
+	 */
+	public static function createUnsealed(array $items, ?ArrayShapeUnsealedTypeNode $unsealedType, string $kind = self::KIND_ARRAY): self
+	{
+		return new self($items, false, $unsealedType, $kind);
+	}
+
+
 	public function __toString(): string
 	{
 		$items = $this->items;
 
 		if (! $this->sealed) {
-			$items[] = '...';
+			$items[] = '...' . $this->unsealedType;
 		}
 
 		return $this->kind . '{' . implode(', ', $items) . '}';
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeUnsealedTypeNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeUnsealedTypeNode.php
new file mode 100644
index 000000000..68d6b36fb
--- /dev/null
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeUnsealedTypeNode.php
@@ -0,0 +1,32 @@
+valueType = $valueType;
+		$this->keyType = $keyType;
+	}
+
+	public function __toString(): string
+	{
+		if ($this->keyType !== null) {
+			return sprintf('<%s, %s>', $this->keyType, $this->valueType);
+		}
+		return sprintf('<%s>', $this->valueType);
+	}
+
+}
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayTypeNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayTypeNode.php
index d2031032f..95c020d88 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayTypeNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayTypeNode.php
@@ -9,8 +9,7 @@ class ArrayTypeNode implements TypeNode
 
 	use NodeAttributes;
 
-	/** @var TypeNode */
-	public $type;
+	public TypeNode $type;
 
 	public function __construct(TypeNode $type)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeNode.php
index 4c9131985..0a9e3442a 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeNode.php
@@ -11,23 +11,21 @@ class CallableTypeNode implements TypeNode
 
 	use NodeAttributes;
 
-	/** @var IdentifierTypeNode */
-	public $identifier;
+	public IdentifierTypeNode $identifier;
 
 	/** @var TemplateTagValueNode[] */
-	public $templateTypes;
+	public array $templateTypes;
 
 	/** @var CallableTypeParameterNode[] */
-	public $parameters;
+	public array $parameters;
 
-	/** @var TypeNode */
-	public $returnType;
+	public TypeNode $returnType;
 
 	/**
 	 * @param CallableTypeParameterNode[] $parameters
 	 * @param TemplateTagValueNode[]  $templateTypes
 	 */
-	public function __construct(IdentifierTypeNode $identifier, array $parameters, TypeNode $returnType, array $templateTypes = [])
+	public function __construct(IdentifierTypeNode $identifier, array $parameters, TypeNode $returnType, array $templateTypes)
 	{
 		$this->identifier = $identifier;
 		$this->parameters = $parameters;
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeParameterNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeParameterNode.php
index c78d4c7b9..08119670c 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeParameterNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeParameterNode.php
@@ -11,20 +11,16 @@ class CallableTypeParameterNode implements Node
 
 	use NodeAttributes;
 
-	/** @var TypeNode */
-	public $type;
+	public TypeNode $type;
 
-	/** @var bool */
-	public $isReference;
+	public bool $isReference;
 
-	/** @var bool */
-	public $isVariadic;
+	public bool $isVariadic;
 
 	/** @var string (may be empty) */
-	public $parameterName;
+	public string $parameterName;
 
-	/** @var bool */
-	public $isOptional;
+	public bool $isOptional;
 
 	public function __construct(TypeNode $type, bool $isReference, bool $isVariadic, string $parameterName, bool $isOptional)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeForParameterNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeForParameterNode.php
index fbfcae95d..4c120d225 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeForParameterNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeForParameterNode.php
@@ -10,20 +10,15 @@ class ConditionalTypeForParameterNode implements TypeNode
 
 	use NodeAttributes;
 
-	/** @var string */
-	public $parameterName;
+	public string $parameterName;
 
-	/** @var TypeNode */
-	public $targetType;
+	public TypeNode $targetType;
 
-	/** @var TypeNode */
-	public $if;
+	public TypeNode $if;
 
-	/** @var TypeNode */
-	public $else;
+	public TypeNode $else;
 
-	/** @var bool */
-	public $negated;
+	public bool $negated;
 
 	public function __construct(string $parameterName, TypeNode $targetType, TypeNode $if, TypeNode $else, bool $negated)
 	{
@@ -42,7 +37,7 @@ public function __toString(): string
 			$this->negated ? 'is not' : 'is',
 			$this->targetType,
 			$this->if,
-			$this->else
+			$this->else,
 		);
 	}
 
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeNode.php
index bfdb0db1a..89c1c63f5 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeNode.php
@@ -10,20 +10,15 @@ class ConditionalTypeNode implements TypeNode
 
 	use NodeAttributes;
 
-	/** @var TypeNode */
-	public $subjectType;
+	public TypeNode $subjectType;
 
-	/** @var TypeNode */
-	public $targetType;
+	public TypeNode $targetType;
 
-	/** @var TypeNode */
-	public $if;
+	public TypeNode $if;
 
-	/** @var TypeNode */
-	public $else;
+	public TypeNode $else;
 
-	/** @var bool */
-	public $negated;
+	public bool $negated;
 
 	public function __construct(TypeNode $subjectType, TypeNode $targetType, TypeNode $if, TypeNode $else, bool $negated)
 	{
@@ -42,7 +37,7 @@ public function __toString(): string
 			$this->negated ? 'is not' : 'is',
 			$this->targetType,
 			$this->if,
-			$this->else
+			$this->else,
 		);
 	}
 
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ConstTypeNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ConstTypeNode.php
index 0096055b4..22823e5b1 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ConstTypeNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ConstTypeNode.php
@@ -10,8 +10,7 @@ class ConstTypeNode implements TypeNode
 
 	use NodeAttributes;
 
-	/** @var ConstExprNode */
-	public $constExpr;
+	public ConstExprNode $constExpr;
 
 	public function __construct(ConstExprNode $constExpr)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/GenericTypeNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/GenericTypeNode.php
index 44e1d16df..4e52c00a5 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/GenericTypeNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/GenericTypeNode.php
@@ -16,14 +16,13 @@ class GenericTypeNode implements TypeNode
 
 	use NodeAttributes;
 
-	/** @var IdentifierTypeNode */
-	public $type;
+	public IdentifierTypeNode $type;
 
 	/** @var TypeNode[] */
-	public $genericTypes;
+	public array $genericTypes;
 
 	/** @var (self::VARIANCE_*)[] */
-	public $variances;
+	public array $variances;
 
 	/**
 	 * @param TypeNode[] $genericTypes
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/IdentifierTypeNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/IdentifierTypeNode.php
index 29bac308e..df93fa869 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/IdentifierTypeNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/IdentifierTypeNode.php
@@ -9,8 +9,7 @@ class IdentifierTypeNode implements TypeNode
 
 	use NodeAttributes;
 
-	/** @var string */
-	public $name;
+	public string $name;
 
 	public function __construct(string $name)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/IntersectionTypeNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/IntersectionTypeNode.php
index fd761cf78..b3059cf5c 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/IntersectionTypeNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/IntersectionTypeNode.php
@@ -12,7 +12,7 @@ class IntersectionTypeNode implements TypeNode
 	use NodeAttributes;
 
 	/** @var TypeNode[] */
-	public $types;
+	public array $types;
 
 	/**
 	 * @param TypeNode[] $types
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/InvalidTypeNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/InvalidTypeNode.php
index 1ec47cf6c..318176e71 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/InvalidTypeNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/InvalidTypeNode.php
@@ -11,7 +11,7 @@ class InvalidTypeNode implements TypeNode
 	use NodeAttributes;
 
 	/** @var mixed[] */
-	private $exceptionArgs;
+	private array $exceptionArgs;
 
 	public function __construct(ParserException $exception)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/NullableTypeNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/NullableTypeNode.php
index 73f438cd2..080a13f21 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/NullableTypeNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/NullableTypeNode.php
@@ -9,8 +9,7 @@ class NullableTypeNode implements TypeNode
 
 	use NodeAttributes;
 
-	/** @var TypeNode */
-	public $type;
+	public TypeNode $type;
 
 	public function __construct(TypeNode $type)
 	{
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeItemNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeItemNode.php
index 2f0124066..f7aa9efbe 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeItemNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeItemNode.php
@@ -3,10 +3,11 @@
 namespace PHPStan\PhpDocParser\Ast\Type;
 
 use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprStringNode;
+use PHPStan\PhpDocParser\Ast\Node;
 use PHPStan\PhpDocParser\Ast\NodeAttributes;
 use function sprintf;
 
-class ObjectShapeItemNode implements TypeNode
+class ObjectShapeItemNode implements Node
 {
 
 	use NodeAttributes;
@@ -14,11 +15,9 @@ class ObjectShapeItemNode implements TypeNode
 	/** @var ConstExprStringNode|IdentifierTypeNode */
 	public $keyName;
 
-	/** @var bool */
-	public $optional;
+	public bool $optional;
 
-	/** @var TypeNode */
-	public $valueType;
+	public TypeNode $valueType;
 
 	/**
 	 * @param ConstExprStringNode|IdentifierTypeNode $keyName
@@ -38,7 +37,7 @@ public function __toString(): string
 				'%s%s: %s',
 				(string) $this->keyName,
 				$this->optional ? '?' : '',
-				(string) $this->valueType
+				(string) $this->valueType,
 			);
 		}
 
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeNode.php
index f418bc30b..41dc68c3a 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeNode.php
@@ -11,7 +11,7 @@ class ObjectShapeNode implements TypeNode
 	use NodeAttributes;
 
 	/** @var ObjectShapeItemNode[] */
-	public $items;
+	public array $items;
 
 	/**
 	 * @param ObjectShapeItemNode[] $items
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/OffsetAccessTypeNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/OffsetAccessTypeNode.php
index 39e83dfec..4bd67d8d7 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/OffsetAccessTypeNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/OffsetAccessTypeNode.php
@@ -9,11 +9,9 @@ class OffsetAccessTypeNode implements TypeNode
 
 	use NodeAttributes;
 
-	/** @var TypeNode */
-	public $type;
+	public TypeNode $type;
 
-	/** @var TypeNode */
-	public $offset;
+	public TypeNode $offset;
 
 	public function __construct(TypeNode $type, TypeNode $offset)
 	{
@@ -25,7 +23,6 @@ public function __toString(): string
 	{
 		if (
 			$this->type instanceof CallableTypeNode
-			|| $this->type instanceof ConstTypeNode
 			|| $this->type instanceof NullableTypeNode
 		) {
 			return '(' . $this->type . ')[' . $this->offset . ']';
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/UnionTypeNode.php b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/UnionTypeNode.php
index c552dab5f..602cb3dd2 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/UnionTypeNode.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Ast/Type/UnionTypeNode.php
@@ -12,7 +12,7 @@ class UnionTypeNode implements TypeNode
 	use NodeAttributes;
 
 	/** @var TypeNode[] */
-	public $types;
+	public array $types;
 
 	/**
 	 * @param TypeNode[] $types
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Lexer/Lexer.php b/app/vendor/phpstan/phpdoc-parser/src/Lexer/Lexer.php
index 32539faf6..b26691317 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Lexer/Lexer.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Lexer/Lexer.php
@@ -2,6 +2,7 @@
 
 namespace PHPStan\PhpDocParser\Lexer;
 
+use PHPStan\PhpDocParser\ParserConfig;
 use function implode;
 use function preg_match_all;
 use const PREG_SET_ORDER;
@@ -50,6 +51,8 @@ class Lexer
 	public const TOKEN_NEGATED = 35;
 	public const TOKEN_ARROW = 36;
 
+	public const TOKEN_COMMENT = 37;
+
 	public const TOKEN_LABELS = [
 		self::TOKEN_REFERENCE => '\'&\'',
 		self::TOKEN_UNION => '\'|\'',
@@ -65,6 +68,7 @@ class Lexer
 		self::TOKEN_OPEN_CURLY_BRACKET => '\'{\'',
 		self::TOKEN_CLOSE_CURLY_BRACKET => '\'}\'',
 		self::TOKEN_COMMA => '\',\'',
+		self::TOKEN_COMMENT => '\'//\'',
 		self::TOKEN_COLON => '\':\'',
 		self::TOKEN_VARIADIC => '\'...\'',
 		self::TOKEN_DOUBLE_COLON => '\'::\'',
@@ -94,17 +98,16 @@ class Lexer
 	public const TYPE_OFFSET = 1;
 	public const LINE_OFFSET = 2;
 
-	/** @var bool */
-	private $parseDoctrineAnnotations;
+	private ParserConfig $config; // @phpstan-ignore property.onlyWritten
 
-	/** @var string|null */
-	private $regexp;
+	private ?string $regexp = null;
 
-	public function __construct(bool $parseDoctrineAnnotations = false)
+	public function __construct(ParserConfig $config)
 	{
-		$this->parseDoctrineAnnotations = $parseDoctrineAnnotations;
+		$this->config = $config;
 	}
 
+
 	/**
 	 * @return list
 	 */
@@ -160,6 +163,7 @@ private function generateRegexp(): string
 			self::TOKEN_CLOSE_CURLY_BRACKET => '\\}',
 
 			self::TOKEN_COMMA => ',',
+			self::TOKEN_COMMENT => '\/\/[^\\r\\n]*(?=\n|\r|\*/)',
 			self::TOKEN_VARIADIC => '\\.\\.\\.',
 			self::TOKEN_DOUBLE_COLON => '::',
 			self::TOKEN_DOUBLE_ARROW => '=>',
@@ -170,23 +174,20 @@ private function generateRegexp(): string
 			self::TOKEN_OPEN_PHPDOC => '/\\*\\*(?=\\s)\\x20?+',
 			self::TOKEN_CLOSE_PHPDOC => '\\*/',
 			self::TOKEN_PHPDOC_TAG => '@(?:[a-z][a-z0-9-\\\\]+:)?[a-z][a-z0-9-\\\\]*+',
+			self::TOKEN_DOCTRINE_TAG => '@[a-z_\\\\][a-z0-9_\:\\\\]*[a-z_][a-z0-9_]*',
 			self::TOKEN_PHPDOC_EOL => '\\r?+\\n[\\x09\\x20]*+(?:\\*(?!/)\\x20?+)?',
 
 			self::TOKEN_FLOAT => '[+\-]?(?:(?:[0-9]++(_[0-9]++)*\\.[0-9]*+(_[0-9]++)*(?:e[+\-]?[0-9]++(_[0-9]++)*)?)|(?:[0-9]*+(_[0-9]++)*\\.[0-9]++(_[0-9]++)*(?:e[+\-]?[0-9]++(_[0-9]++)*)?)|(?:[0-9]++(_[0-9]++)*e[+\-]?[0-9]++(_[0-9]++)*))',
 			self::TOKEN_INTEGER => '[+\-]?(?:(?:0b[0-1]++(_[0-1]++)*)|(?:0o[0-7]++(_[0-7]++)*)|(?:0x[0-9a-f]++(_[0-9a-f]++)*)|(?:[0-9]++(_[0-9]++)*))',
 			self::TOKEN_SINGLE_QUOTED_STRING => '\'(?:\\\\[^\\r\\n]|[^\'\\r\\n\\\\])*+\'',
 			self::TOKEN_DOUBLE_QUOTED_STRING => '"(?:\\\\[^\\r\\n]|[^"\\r\\n\\\\])*+"',
+			self::TOKEN_DOCTRINE_ANNOTATION_STRING => '"(?:""|[^"])*+"',
 
 			self::TOKEN_WILDCARD => '\\*',
-		];
 
-		if ($this->parseDoctrineAnnotations) {
-			$patterns[self::TOKEN_DOCTRINE_TAG] = '@[a-z_\\\\][a-z0-9_\:\\\\]*[a-z_][a-z0-9_]*';
-			$patterns[self::TOKEN_DOCTRINE_ANNOTATION_STRING] = '"(?:""|[^"])*+"';
-		}
-
-		// anything but TOKEN_CLOSE_PHPDOC or TOKEN_HORIZONTAL_WS or TOKEN_EOL
-		$patterns[self::TOKEN_OTHER] = '(?:(?!\\*/)[^\\s])++';
+			// anything but TOKEN_CLOSE_PHPDOC or TOKEN_HORIZONTAL_WS or TOKEN_EOL
+			self::TOKEN_OTHER => '(?:(?!\\*/)[^\\s])++',
+		];
 
 		foreach ($patterns as $type => &$pattern) {
 			$pattern = '(?:' . $pattern . ')(*MARK:' . $type . ')';
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Parser/ConstExprParser.php b/app/vendor/phpstan/phpdoc-parser/src/Parser/ConstExprParser.php
index f6a7306e8..396b8d7c7 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Parser/ConstExprParser.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Parser/ConstExprParser.php
@@ -4,41 +4,22 @@
 
 use PHPStan\PhpDocParser\Ast;
 use PHPStan\PhpDocParser\Lexer\Lexer;
+use PHPStan\PhpDocParser\ParserConfig;
 use function str_replace;
 use function strtolower;
-use function substr;
 
 class ConstExprParser
 {
 
-	/** @var bool */
-	private $unescapeStrings;
+	private ParserConfig $config;
 
-	/** @var bool */
-	private $quoteAwareConstExprString;
+	private bool $parseDoctrineStrings;
 
-	/** @var bool */
-	private $useLinesAttributes;
-
-	/** @var bool */
-	private $useIndexAttributes;
-
-	/** @var bool */
-	private $parseDoctrineStrings;
-
-	/**
-	 * @param array{lines?: bool, indexes?: bool} $usedAttributes
-	 */
 	public function __construct(
-		bool $unescapeStrings = false,
-		bool $quoteAwareConstExprString = false,
-		array $usedAttributes = []
+		ParserConfig $config
 	)
 	{
-		$this->unescapeStrings = $unescapeStrings;
-		$this->quoteAwareConstExprString = $quoteAwareConstExprString;
-		$this->useLinesAttributes = $usedAttributes['lines'] ?? false;
-		$this->useIndexAttributes = $usedAttributes['indexes'] ?? false;
+		$this->config = $config;
 		$this->parseDoctrineStrings = false;
 	}
 
@@ -47,19 +28,12 @@ public function __construct(
 	 */
 	public function toDoctrine(): self
 	{
-		$self = new self(
-			$this->unescapeStrings,
-			$this->quoteAwareConstExprString,
-			[
-				'lines' => $this->useLinesAttributes,
-				'indexes' => $this->useIndexAttributes,
-			]
-		);
+		$self = new self($this->config);
 		$self->parseDoctrineStrings = true;
 		return $self;
 	}
 
-	public function parse(TokenIterator $tokens, bool $trimStrings = false): Ast\ConstExpr\ConstExprNode
+	public function parse(TokenIterator $tokens): Ast\ConstExpr\ConstExprNode
 	{
 		$startLine = $tokens->currentTokenLine();
 		$startIndex = $tokens->currentTokenIndex();
@@ -71,7 +45,7 @@ public function parse(TokenIterator $tokens, bool $trimStrings = false): Ast\Con
 				$tokens,
 				new Ast\ConstExpr\ConstExprFloatNode(str_replace('_', '', $value)),
 				$startLine,
-				$startIndex
+				$startIndex,
 			);
 		}
 
@@ -83,7 +57,7 @@ public function parse(TokenIterator $tokens, bool $trimStrings = false): Ast\Con
 				$tokens,
 				new Ast\ConstExpr\ConstExprIntegerNode(str_replace('_', '', $value)),
 				$startLine,
-				$startIndex
+				$startIndex,
 			);
 		}
 
@@ -95,7 +69,7 @@ public function parse(TokenIterator $tokens, bool $trimStrings = false): Ast\Con
 				$tokens,
 				new Ast\ConstExpr\DoctrineConstExprStringNode(Ast\ConstExpr\DoctrineConstExprStringNode::unescape($value)),
 				$startLine,
-				$startIndex
+				$startIndex,
 			);
 		}
 
@@ -108,7 +82,7 @@ public function parse(TokenIterator $tokens, bool $trimStrings = false): Ast\Con
 						$tokens->currentTokenOffset(),
 						Lexer::TOKEN_DOUBLE_QUOTED_STRING,
 						null,
-						$tokens->currentTokenLine()
+						$tokens->currentTokenLine(),
 					);
 				}
 
@@ -119,39 +93,24 @@ public function parse(TokenIterator $tokens, bool $trimStrings = false): Ast\Con
 					$tokens,
 					$this->parseDoctrineString($value, $tokens),
 					$startLine,
-					$startIndex
+					$startIndex,
 				);
 			}
-			$value = $tokens->currentTokenValue();
+
+			$value = StringUnescaper::unescapeString($tokens->currentTokenValue());
 			$type = $tokens->currentTokenType();
-			if ($trimStrings) {
-				if ($this->unescapeStrings) {
-					$value = StringUnescaper::unescapeString($value);
-				} else {
-					$value = substr($value, 1, -1);
-				}
-			}
 			$tokens->next();
 
-			if ($this->quoteAwareConstExprString) {
-				return $this->enrichWithAttributes(
-					$tokens,
-					new Ast\ConstExpr\QuoteAwareConstExprStringNode(
-						$value,
-						$type === Lexer::TOKEN_SINGLE_QUOTED_STRING
-							? Ast\ConstExpr\QuoteAwareConstExprStringNode::SINGLE_QUOTED
-							: Ast\ConstExpr\QuoteAwareConstExprStringNode::DOUBLE_QUOTED
-					),
-					$startLine,
-					$startIndex
-				);
-			}
-
 			return $this->enrichWithAttributes(
 				$tokens,
-				new Ast\ConstExpr\ConstExprStringNode($value),
+				new Ast\ConstExpr\ConstExprStringNode(
+					$value,
+					$type === Lexer::TOKEN_SINGLE_QUOTED_STRING
+						? Ast\ConstExpr\ConstExprStringNode::SINGLE_QUOTED
+						: Ast\ConstExpr\ConstExprStringNode::DOUBLE_QUOTED,
+				),
 				$startLine,
-				$startIndex
+				$startIndex,
 			);
 
 		} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) {
@@ -164,21 +123,21 @@ public function parse(TokenIterator $tokens, bool $trimStrings = false): Ast\Con
 						$tokens,
 						new Ast\ConstExpr\ConstExprTrueNode(),
 						$startLine,
-						$startIndex
+						$startIndex,
 					);
 				case 'false':
 					return $this->enrichWithAttributes(
 						$tokens,
 						new Ast\ConstExpr\ConstExprFalseNode(),
 						$startLine,
-						$startIndex
+						$startIndex,
 					);
 				case 'null':
 					return $this->enrichWithAttributes(
 						$tokens,
 						new Ast\ConstExpr\ConstExprNullNode(),
 						$startLine,
-						$startIndex
+						$startIndex,
 					);
 				case 'array':
 					$tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES);
@@ -220,7 +179,7 @@ public function parse(TokenIterator $tokens, bool $trimStrings = false): Ast\Con
 					$tokens,
 					new Ast\ConstExpr\ConstFetchNode($identifier, $classConstantName),
 					$startLine,
-					$startIndex
+					$startIndex,
 				);
 
 			}
@@ -229,7 +188,7 @@ public function parse(TokenIterator $tokens, bool $trimStrings = false): Ast\Con
 				$tokens,
 				new Ast\ConstExpr\ConstFetchNode('', $identifier),
 				$startLine,
-				$startIndex
+				$startIndex,
 			);
 
 		} elseif ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
@@ -242,7 +201,7 @@ public function parse(TokenIterator $tokens, bool $trimStrings = false): Ast\Con
 			$tokens->currentTokenOffset(),
 			Lexer::TOKEN_IDENTIFIER,
 			null,
-			$tokens->currentTokenLine()
+			$tokens->currentTokenLine(),
 		);
 	}
 
@@ -264,7 +223,7 @@ private function parseArray(TokenIterator $tokens, int $endToken, int $startInde
 			$tokens,
 			new Ast\ConstExpr\ConstExprArrayNode($items),
 			$startLine,
-			$startIndex
+			$startIndex,
 		);
 	}
 
@@ -306,7 +265,7 @@ private function parseArrayItem(TokenIterator $tokens): Ast\ConstExpr\ConstExprA
 			$tokens,
 			new Ast\ConstExpr\ConstExprArrayItemNode($key, $value),
 			$startLine,
-			$startIndex
+			$startIndex,
 		);
 	}
 
@@ -317,12 +276,12 @@ private function parseArrayItem(TokenIterator $tokens): Ast\ConstExpr\ConstExprA
 	 */
 	private function enrichWithAttributes(TokenIterator $tokens, Ast\ConstExpr\ConstExprNode $node, int $startLine, int $startIndex): Ast\ConstExpr\ConstExprNode
 	{
-		if ($this->useLinesAttributes) {
+		if ($this->config->useLinesAttributes) {
 			$node->setAttribute(Ast\Attribute::START_LINE, $startLine);
 			$node->setAttribute(Ast\Attribute::END_LINE, $tokens->currentTokenLine());
 		}
 
-		if ($this->useIndexAttributes) {
+		if ($this->config->useIndexAttributes) {
 			$node->setAttribute(Ast\Attribute::START_INDEX, $startIndex);
 			$node->setAttribute(Ast\Attribute::END_INDEX, $tokens->endIndexOfLastRelevantToken());
 		}
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Parser/ParserException.php b/app/vendor/phpstan/phpdoc-parser/src/Parser/ParserException.php
index 6ab5cc076..ae72fd9c4 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Parser/ParserException.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Parser/ParserException.php
@@ -14,31 +14,25 @@
 class ParserException extends Exception
 {
 
-	/** @var string */
-	private $currentTokenValue;
+	private string $currentTokenValue;
 
-	/** @var int */
-	private $currentTokenType;
+	private int $currentTokenType;
 
-	/** @var int */
-	private $currentOffset;
+	private int $currentOffset;
 
-	/** @var int */
-	private $expectedTokenType;
+	private int $expectedTokenType;
 
-	/** @var string|null */
-	private $expectedTokenValue;
+	private ?string $expectedTokenValue;
 
-	/** @var int|null */
-	private $currentTokenLine;
+	private ?int $currentTokenLine;
 
 	public function __construct(
 		string $currentTokenValue,
 		int $currentTokenType,
 		int $currentOffset,
 		int $expectedTokenType,
-		?string $expectedTokenValue = null,
-		?int $currentTokenLine = null
+		?string $expectedTokenValue,
+		?int $currentTokenLine
 	)
 	{
 		$this->currentTokenValue = $currentTokenValue;
@@ -54,7 +48,7 @@ public function __construct(
 			Lexer::TOKEN_LABELS[$expectedTokenType],
 			$expectedTokenValue !== null ? sprintf(' (%s)', $this->formatValue($expectedTokenValue)) : '',
 			$currentOffset,
-			$currentTokenLine === null ? '' : sprintf(' on line %d', $currentTokenLine)
+			$currentTokenLine === null ? '' : sprintf(' on line %d', $currentTokenLine),
 		));
 	}
 
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Parser/PhpDocParser.php b/app/vendor/phpstan/phpdoc-parser/src/Parser/PhpDocParser.php
index 475dd5ba5..f36b91364 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Parser/PhpDocParser.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Parser/PhpDocParser.php
@@ -10,9 +10,9 @@
 use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine;
 use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
 use PHPStan\PhpDocParser\Lexer\Lexer;
+use PHPStan\PhpDocParser\ParserConfig;
 use PHPStan\ShouldNotHappenException;
 use function array_key_exists;
-use function array_values;
 use function count;
 use function rtrim;
 use function str_replace;
@@ -29,55 +29,24 @@ class PhpDocParser
 		Lexer::TOKEN_INTERSECTION,
 	];
 
-	/** @var TypeParser */
-	private $typeParser;
+	private ParserConfig $config;
 
-	/** @var ConstExprParser */
-	private $constantExprParser;
+	private TypeParser $typeParser;
 
-	/** @var ConstExprParser */
-	private $doctrineConstantExprParser;
+	private ConstExprParser $constantExprParser;
 
-	/** @var bool */
-	private $requireWhitespaceBeforeDescription;
+	private ConstExprParser $doctrineConstantExprParser;
 
-	/** @var bool */
-	private $preserveTypeAliasesWithInvalidTypes;
-
-	/** @var bool */
-	private $parseDoctrineAnnotations;
-
-	/** @var bool */
-	private $useLinesAttributes;
-
-	/** @var bool */
-	private $useIndexAttributes;
-
-	/** @var bool */
-	private $textBetweenTagsBelongsToDescription;
-
-	/**
-	 * @param array{lines?: bool, indexes?: bool} $usedAttributes
-	 */
 	public function __construct(
+		ParserConfig $config,
 		TypeParser $typeParser,
-		ConstExprParser $constantExprParser,
-		bool $requireWhitespaceBeforeDescription = false,
-		bool $preserveTypeAliasesWithInvalidTypes = false,
-		array $usedAttributes = [],
-		bool $parseDoctrineAnnotations = false,
-		bool $textBetweenTagsBelongsToDescription = false
+		ConstExprParser $constantExprParser
 	)
 	{
+		$this->config = $config;
 		$this->typeParser = $typeParser;
 		$this->constantExprParser = $constantExprParser;
 		$this->doctrineConstantExprParser = $constantExprParser->toDoctrine();
-		$this->requireWhitespaceBeforeDescription = $requireWhitespaceBeforeDescription;
-		$this->preserveTypeAliasesWithInvalidTypes = $preserveTypeAliasesWithInvalidTypes;
-		$this->parseDoctrineAnnotations = $parseDoctrineAnnotations;
-		$this->useLinesAttributes = $usedAttributes['lines'] ?? false;
-		$this->useIndexAttributes = $usedAttributes['indexes'] ?? false;
-		$this->textBetweenTagsBelongsToDescription = $textBetweenTagsBelongsToDescription;
 	}
 
 
@@ -88,44 +57,35 @@ public function parse(TokenIterator $tokens): Ast\PhpDoc\PhpDocNode
 
 		$children = [];
 
-		if ($this->parseDoctrineAnnotations) {
-			if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
-				$lastChild = $this->parseChild($tokens);
-				$children[] = $lastChild;
-				while (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
-					if (
-						$lastChild instanceof Ast\PhpDoc\PhpDocTagNode
-						&& (
-							$lastChild->value instanceof Doctrine\DoctrineTagValueNode
-							|| $lastChild->value instanceof Ast\PhpDoc\GenericTagValueNode
-						)
-					) {
-						$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
-						if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
-							break;
-						}
-						$lastChild = $this->parseChild($tokens);
-						$children[] = $lastChild;
-						continue;
-					}
-
-					if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
-						break;
-					}
+		if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
+			$lastChild = $this->parseChild($tokens);
+			$children[] = $lastChild;
+			while (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
+				if (
+					$lastChild instanceof Ast\PhpDoc\PhpDocTagNode
+					&& (
+						$lastChild->value instanceof Doctrine\DoctrineTagValueNode
+						|| $lastChild->value instanceof Ast\PhpDoc\GenericTagValueNode
+					)
+				) {
+					$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
 					if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
 						break;
 					}
-
 					$lastChild = $this->parseChild($tokens);
 					$children[] = $lastChild;
+					continue;
 				}
-			}
-		} else {
-			if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
-				$children[] = $this->parseChild($tokens);
-				while ($tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL) && !$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
-					$children[] = $this->parseChild($tokens);
+
+				if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
+					break;
+				}
+				if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
+					break;
 				}
+
+				$lastChild = $this->parseChild($tokens);
+				$children[] = $lastChild;
 			}
 		}
 
@@ -150,16 +110,26 @@ public function parse(TokenIterator $tokens): Ast\PhpDoc\PhpDocNode
 					$tokens,
 					new Ast\PhpDoc\InvalidTagValueNode($e->getMessage(), $e),
 					$startLine,
-					$startIndex
-				)
+					$startIndex,
+				),
 			);
 
 			$tokens->forwardToTheEnd();
 
+			$comments = $tokens->flushComments();
+			if ($comments !== []) {
+				throw new LogicException('Comments should already be flushed');
+			}
+
 			return $this->enrichWithAttributes($tokens, new Ast\PhpDoc\PhpDocNode([$this->enrichWithAttributes($tokens, $tag, $startLine, $startIndex)]), 1, 0);
 		}
 
-		return $this->enrichWithAttributes($tokens, new Ast\PhpDoc\PhpDocNode(array_values($children)), 1, 0);
+		$comments = $tokens->flushComments();
+		if ($comments !== []) {
+			throw new LogicException('Comments should already be flushed');
+		}
+
+		return $this->enrichWithAttributes($tokens, new Ast\PhpDoc\PhpDocNode($children), 1, 0);
 	}
 
 
@@ -187,8 +157,8 @@ private function parseChild(TokenIterator $tokens): Ast\PhpDoc\PhpDocChildNode
 					$tokens,
 					$this->parseDoctrineTagValue($tokens, $tag),
 					$tagStartLine,
-					$tagStartIndex
-				)
+					$tagStartIndex,
+				),
 			), $startLine, $startIndex);
 		}
 
@@ -206,12 +176,12 @@ private function parseChild(TokenIterator $tokens): Ast\PhpDoc\PhpDocChildNode
 	 */
 	private function enrichWithAttributes(TokenIterator $tokens, Ast\Node $tag, int $startLine, int $startIndex): Ast\Node
 	{
-		if ($this->useLinesAttributes) {
+		if ($this->config->useLinesAttributes) {
 			$tag->setAttribute(Ast\Attribute::START_LINE, $startLine);
 			$tag->setAttribute(Ast\Attribute::END_LINE, $tokens->currentTokenLine());
 		}
 
-		if ($this->useIndexAttributes) {
+		if ($this->config->useIndexAttributes) {
 			$tag->setAttribute(Ast\Attribute::START_INDEX, $startIndex);
 			$tag->setAttribute(Ast\Attribute::END_INDEX, $tokens->endIndexOfLastRelevantToken());
 		}
@@ -224,31 +194,26 @@ private function parseText(TokenIterator $tokens): Ast\PhpDoc\PhpDocTextNode
 	{
 		$text = '';
 
-		$endTokens = [Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END];
-		if ($this->textBetweenTagsBelongsToDescription) {
-			$endTokens = [Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END];
-		}
+		$endTokens = [Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END];
 
 		$savepoint = false;
 
 		// if the next token is EOL, everything below is skipped and empty string is returned
-		while ($this->textBetweenTagsBelongsToDescription || !$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
+		while (true) {
 			$tmpText = $tokens->getSkippedHorizontalWhiteSpaceIfAny() . $tokens->joinUntil(Lexer::TOKEN_PHPDOC_EOL, ...$endTokens);
 			$text .= $tmpText;
 
 			// stop if we're not at EOL - meaning it's the end of PHPDoc
-			if (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
+			if (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC)) {
 				break;
 			}
 
-			if ($this->textBetweenTagsBelongsToDescription) {
-				if (!$savepoint) {
-					$tokens->pushSavePoint();
-					$savepoint = true;
-				} elseif ($tmpText !== '') {
-					$tokens->dropSavePoint();
-					$tokens->pushSavePoint();
-				}
+			if (!$savepoint) {
+				$tokens->pushSavePoint();
+				$savepoint = true;
+			} elseif ($tmpText !== '') {
+				$tokens->dropSavePoint();
+				$tokens->pushSavePoint();
 			}
 
 			$tokens->pushSavePoint();
@@ -280,20 +245,17 @@ private function parseOptionalDescriptionAfterDoctrineTag(TokenIterator $tokens)
 	{
 		$text = '';
 
-		$endTokens = [Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END];
-		if ($this->textBetweenTagsBelongsToDescription) {
-			$endTokens = [Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END];
-		}
+		$endTokens = [Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END];
 
 		$savepoint = false;
 
 		// if the next token is EOL, everything below is skipped and empty string is returned
-		while ($this->textBetweenTagsBelongsToDescription || !$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
+		while (true) {
 			$tmpText = $tokens->getSkippedHorizontalWhiteSpaceIfAny() . $tokens->joinUntil(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_DOCTRINE_TAG, Lexer::TOKEN_PHPDOC_EOL, ...$endTokens);
 			$text .= $tmpText;
 
 			// stop if we're not at EOL - meaning it's the end of PHPDoc
-			if (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
+			if (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC)) {
 				if (!$tokens->isPrecededByHorizontalWhitespace()) {
 					return trim($text . $this->parseText($tokens)->text, " \t");
 				}
@@ -327,14 +289,12 @@ private function parseOptionalDescriptionAfterDoctrineTag(TokenIterator $tokens)
 				break;
 			}
 
-			if ($this->textBetweenTagsBelongsToDescription) {
-				if (!$savepoint) {
-					$tokens->pushSavePoint();
-					$savepoint = true;
-				} elseif ($tmpText !== '') {
-					$tokens->dropSavePoint();
-					$tokens->pushSavePoint();
-				}
+			if (!$savepoint) {
+				$tokens->pushSavePoint();
+				$savepoint = true;
+			} elseif ($tmpText !== '') {
+				$tokens->dropSavePoint();
+				$tokens->pushSavePoint();
 			}
 
 			$tokens->pushSavePoint();
@@ -384,18 +344,42 @@ public function parseTagValue(TokenIterator $tokens, string $tag): Ast\PhpDoc\Ph
 				case '@param':
 				case '@phpstan-param':
 				case '@psalm-param':
+				case '@phan-param':
 					$tagValue = $this->parseParamTagValue($tokens);
 					break;
 
+				case '@param-immediately-invoked-callable':
+				case '@phpstan-param-immediately-invoked-callable':
+					$tagValue = $this->parseParamImmediatelyInvokedCallableTagValue($tokens);
+					break;
+
+				case '@param-later-invoked-callable':
+				case '@phpstan-param-later-invoked-callable':
+					$tagValue = $this->parseParamLaterInvokedCallableTagValue($tokens);
+					break;
+
+				case '@param-closure-this':
+				case '@phpstan-param-closure-this':
+					$tagValue = $this->parseParamClosureThisTagValue($tokens);
+					break;
+
+				case '@pure-unless-callable-is-impure':
+				case '@phpstan-pure-unless-callable-is-impure':
+					$tagValue = $this->parsePureUnlessCallableIsImpureTagValue($tokens);
+					break;
+
 				case '@var':
 				case '@phpstan-var':
 				case '@psalm-var':
+				case '@phan-var':
 					$tagValue = $this->parseVarTagValue($tokens);
 					break;
 
 				case '@return':
 				case '@phpstan-return':
 				case '@psalm-return':
+				case '@phan-return':
+				case '@phan-real-return':
 					$tagValue = $this->parseReturnTagValue($tokens);
 					break;
 
@@ -405,6 +389,7 @@ public function parseTagValue(TokenIterator $tokens, string $tag): Ast\PhpDoc\Ph
 					break;
 
 				case '@mixin':
+				case '@phan-mixin':
 					$tagValue = $this->parseMixinTagValue($tokens);
 					break;
 
@@ -418,6 +403,11 @@ public function parseTagValue(TokenIterator $tokens, string $tag): Ast\PhpDoc\Ph
 					$tagValue = $this->parseRequireImplementsTagValue($tokens);
 					break;
 
+				case '@psalm-inheritors':
+				case '@phpstan-sealed':
+					$tagValue = $this->parseSealedTagValue($tokens);
+					break;
+
 				case '@deprecated':
 					$tagValue = $this->parseDeprecatedTagValue($tokens);
 					break;
@@ -431,18 +421,23 @@ public function parseTagValue(TokenIterator $tokens, string $tag): Ast\PhpDoc\Ph
 				case '@psalm-property':
 				case '@psalm-property-read':
 				case '@psalm-property-write':
+				case '@phan-property':
+				case '@phan-property-read':
+				case '@phan-property-write':
 					$tagValue = $this->parsePropertyTagValue($tokens);
 					break;
 
 				case '@method':
 				case '@phpstan-method':
 				case '@psalm-method':
+				case '@phan-method':
 					$tagValue = $this->parseMethodTagValue($tokens);
 					break;
 
 				case '@template':
 				case '@phpstan-template':
 				case '@psalm-template':
+				case '@phan-template':
 				case '@template-covariant':
 				case '@phpstan-template-covariant':
 				case '@psalm-template-covariant':
@@ -451,14 +446,14 @@ public function parseTagValue(TokenIterator $tokens, string $tag): Ast\PhpDoc\Ph
 				case '@psalm-template-contravariant':
 					$tagValue = $this->typeParser->parseTemplateTagValue(
 						$tokens,
-						function ($tokens) {
-							return $this->parseOptionalDescription($tokens);
-						}
+						fn ($tokens) => $this->parseOptionalDescription($tokens, true),
 					);
 					break;
 
 				case '@extends':
 				case '@phpstan-extends':
+				case '@phan-extends':
+				case '@phan-inherits':
 				case '@template-extends':
 					$tagValue = $this->parseExtendsTagValue('@extends', $tokens);
 					break;
@@ -477,6 +472,7 @@ function ($tokens) {
 
 				case '@phpstan-type':
 				case '@psalm-type':
+				case '@phan-type':
 					$tagValue = $this->parseTypeAliasTagValue($tokens);
 					break;
 
@@ -491,6 +487,9 @@ function ($tokens) {
 				case '@psalm-assert':
 				case '@psalm-assert-if-true':
 				case '@psalm-assert-if-false':
+				case '@phan-assert':
+				case '@phan-assert-if-true':
+				case '@phan-assert-if-false':
 					$tagValue = $this->parseAssertTagValue($tokens);
 					break;
 
@@ -508,17 +507,11 @@ function ($tokens) {
 					break;
 
 				default:
-					if ($this->parseDoctrineAnnotations) {
-						if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
-							$tagValue = $this->parseDoctrineTagValue($tokens, $tag);
-						} else {
-							$tagValue = new Ast\PhpDoc\GenericTagValueNode($this->parseOptionalDescriptionAfterDoctrineTag($tokens));
-						}
-						break;
+					if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
+						$tagValue = $this->parseDoctrineTagValue($tokens, $tag);
+					} else {
+						$tagValue = new Ast\PhpDoc\GenericTagValueNode($this->parseOptionalDescriptionAfterDoctrineTag($tokens));
 					}
-
-					$tagValue = new Ast\PhpDoc\GenericTagValueNode($this->parseOptionalDescription($tokens));
-
 					break;
 			}
 
@@ -526,7 +519,7 @@ function ($tokens) {
 
 		} catch (ParserException $e) {
 			$tokens->rollback();
-			$tagValue = new Ast\PhpDoc\InvalidTagValueNode($this->parseOptionalDescription($tokens), $e);
+			$tagValue = new Ast\PhpDoc\InvalidTagValueNode($this->parseOptionalDescription($tokens, false), $e);
 		}
 
 		return $this->enrichWithAttributes($tokens, $tagValue, $startLine, $startIndex);
@@ -543,9 +536,9 @@ private function parseDoctrineTagValue(TokenIterator $tokens, string $tag): Ast\
 				$tokens,
 				new Doctrine\DoctrineAnnotation($tag, $this->parseDoctrineArguments($tokens, false)),
 				$startLine,
-				$startIndex
+				$startIndex,
 			),
-			$this->parseOptionalDescriptionAfterDoctrineTag($tokens)
+			$this->parseOptionalDescriptionAfterDoctrineTag($tokens),
 		);
 	}
 
@@ -596,7 +589,7 @@ private function parseDoctrineArgument(TokenIterator $tokens): Doctrine\Doctrine
 				$tokens,
 				new Doctrine\DoctrineArgument(null, $this->parseDoctrineArgumentValue($tokens)),
 				$startLine,
-				$startIndex
+				$startIndex,
 			);
 		}
 
@@ -612,7 +605,7 @@ private function parseDoctrineArgument(TokenIterator $tokens): Doctrine\Doctrine
 				$tokens,
 				new IdentifierTypeNode($currentValue),
 				$startLine,
-				$startIndex
+				$startIndex,
 			);
 			$tokens->consumeTokenType(Lexer::TOKEN_EQUAL);
 
@@ -624,7 +617,7 @@ private function parseDoctrineArgument(TokenIterator $tokens): Doctrine\Doctrine
 				$tokens,
 				new Doctrine\DoctrineArgument($key, $value),
 				$startLine,
-				$startIndex
+				$startIndex,
 			);
 		} catch (ParserException $e) {
 			$tokens->rollback();
@@ -633,7 +626,7 @@ private function parseDoctrineArgument(TokenIterator $tokens): Doctrine\Doctrine
 				$tokens,
 				new Doctrine\DoctrineArgument(null, $this->parseDoctrineArgumentValue($tokens)),
 				$startLine,
-				$startIndex
+				$startIndex,
 			);
 		}
 	}
@@ -655,7 +648,7 @@ private function parseDoctrineArgumentValue(TokenIterator $tokens)
 				$tokens,
 				new Doctrine\DoctrineAnnotation($name, $this->parseDoctrineArguments($tokens, true)),
 				$startLine,
-				$startIndex
+				$startIndex,
 			);
 		}
 
@@ -674,7 +667,7 @@ private function parseDoctrineArgumentValue(TokenIterator $tokens)
 				$tokens,
 				new Doctrine\DoctrineArray($items),
 				$startLine,
-				$startIndex
+				$startIndex,
 			);
 		}
 
@@ -685,7 +678,7 @@ private function parseDoctrineArgumentValue(TokenIterator $tokens)
 				$tokens,
 				new Ast\Type\IdentifierTypeNode($currentTokenValue),
 				$startLine,
-				$startIndex
+				$startIndex,
 			);
 			if (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) {
 				$tokens->dropSavePoint();
@@ -703,7 +696,7 @@ private function parseDoctrineArgumentValue(TokenIterator $tokens)
 		$currentTokenLine = $tokens->currentTokenLine();
 
 		try {
-			$constExpr = $this->doctrineConstantExprParser->parse($tokens, true);
+			$constExpr = $this->doctrineConstantExprParser->parse($tokens);
 			if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) {
 				throw new ParserException(
 					$currentTokenValue,
@@ -711,7 +704,7 @@ private function parseDoctrineArgumentValue(TokenIterator $tokens)
 					$currentTokenOffset,
 					Lexer::TOKEN_IDENTIFIER,
 					null,
-					$currentTokenLine
+					$currentTokenLine,
 				);
 			}
 
@@ -723,7 +716,7 @@ private function parseDoctrineArgumentValue(TokenIterator $tokens)
 				$currentTokenOffset,
 				Lexer::TOKEN_IDENTIFIER,
 				null,
-				$currentTokenLine
+				$currentTokenLine,
 			);
 		}
 	}
@@ -752,7 +745,7 @@ private function parseDoctrineArrayItem(TokenIterator $tokens): Doctrine\Doctrin
 				$tokens,
 				new Doctrine\DoctrineArrayItem($key, $value),
 				$startLine,
-				$startIndex
+				$startIndex,
 			);
 		} catch (ParserException $e) {
 			$tokens->rollback();
@@ -761,7 +754,7 @@ private function parseDoctrineArrayItem(TokenIterator $tokens): Doctrine\Doctrin
 				$tokens,
 				new Doctrine\DoctrineArrayItem(null, $this->parseDoctrineArgumentValue($tokens)),
 				$startLine,
-				$startIndex
+				$startIndex,
 			);
 		}
 	}
@@ -780,10 +773,14 @@ private function parseDoctrineArrayKey(TokenIterator $tokens)
 			$tokens->next();
 
 		} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOCTRINE_ANNOTATION_STRING)) {
-			$key = new Ast\ConstExpr\DoctrineConstExprStringNode(Ast\ConstExpr\DoctrineConstExprStringNode::unescape($tokens->currentTokenValue()));
+			$key = $this->doctrineConstantExprParser->parseDoctrineString($tokens->currentTokenValue(), $tokens);
 
 			$tokens->next();
 
+		} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING)) {
+			$key = new Ast\ConstExpr\ConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\ConstExprStringNode::SINGLE_QUOTED);
+			$tokens->next();
+
 		} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING)) {
 			$value = $tokens->currentTokenValue();
 			$tokens->next();
@@ -800,7 +797,7 @@ private function parseDoctrineArrayKey(TokenIterator $tokens)
 					$tokens->currentTokenOffset(),
 					Lexer::TOKEN_IDENTIFIER,
 					null,
-					$tokens->currentTokenLine()
+					$tokens->currentTokenLine(),
 				);
 			}
 
@@ -811,12 +808,12 @@ private function parseDoctrineArrayKey(TokenIterator $tokens)
 					$tokens,
 					new IdentifierTypeNode($currentTokenValue),
 					$startLine,
-					$startIndex
+					$startIndex,
 				);
 			}
 
 			$tokens->rollback();
-			$constExpr = $this->doctrineConstantExprParser->parse($tokens, true);
+			$constExpr = $this->doctrineConstantExprParser->parse($tokens);
 			if (!$constExpr instanceof Ast\ConstExpr\ConstFetchNode) {
 				throw new ParserException(
 					$tokens->currentTokenValue(),
@@ -824,7 +821,7 @@ private function parseDoctrineArrayKey(TokenIterator $tokens)
 					$tokens->currentTokenOffset(),
 					Lexer::TOKEN_IDENTIFIER,
 					null,
-					$tokens->currentTokenLine()
+					$tokens->currentTokenLine(),
 				);
 			}
 
@@ -851,7 +848,7 @@ private function parseParamTagValue(TokenIterator $tokens): Ast\PhpDoc\PhpDocTag
 		$isReference = $tokens->tryConsumeTokenType(Lexer::TOKEN_REFERENCE);
 		$isVariadic = $tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC);
 		$parameterName = $this->parseRequiredVariableName($tokens);
-		$description = $this->parseOptionalDescription($tokens);
+		$description = $this->parseOptionalDescription($tokens, false);
 
 		if ($type !== null) {
 			return new Ast\PhpDoc\ParamTagValueNode($type, $isVariadic, $parameterName, $description, $isReference);
@@ -861,6 +858,41 @@ private function parseParamTagValue(TokenIterator $tokens): Ast\PhpDoc\PhpDocTag
 	}
 
 
+	private function parseParamImmediatelyInvokedCallableTagValue(TokenIterator $tokens): Ast\PhpDoc\ParamImmediatelyInvokedCallableTagValueNode
+	{
+		$parameterName = $this->parseRequiredVariableName($tokens);
+		$description = $this->parseOptionalDescription($tokens, false);
+
+		return new Ast\PhpDoc\ParamImmediatelyInvokedCallableTagValueNode($parameterName, $description);
+	}
+
+
+	private function parseParamLaterInvokedCallableTagValue(TokenIterator $tokens): Ast\PhpDoc\ParamLaterInvokedCallableTagValueNode
+	{
+		$parameterName = $this->parseRequiredVariableName($tokens);
+		$description = $this->parseOptionalDescription($tokens, false);
+
+		return new Ast\PhpDoc\ParamLaterInvokedCallableTagValueNode($parameterName, $description);
+	}
+
+
+	private function parseParamClosureThisTagValue(TokenIterator $tokens): Ast\PhpDoc\ParamClosureThisTagValueNode
+	{
+		$type = $this->typeParser->parse($tokens);
+		$parameterName = $this->parseRequiredVariableName($tokens);
+		$description = $this->parseOptionalDescription($tokens, false);
+
+		return new Ast\PhpDoc\ParamClosureThisTagValueNode($type, $parameterName, $description);
+	}
+
+	private function parsePureUnlessCallableIsImpureTagValue(TokenIterator $tokens): Ast\PhpDoc\PureUnlessCallableIsImpureTagValueNode
+	{
+		$parameterName = $this->parseRequiredVariableName($tokens);
+		$description = $this->parseOptionalDescription($tokens, false);
+
+		return new Ast\PhpDoc\PureUnlessCallableIsImpureTagValueNode($parameterName, $description);
+	}
+
 	private function parseVarTagValue(TokenIterator $tokens): Ast\PhpDoc\VarTagValueNode
 	{
 		$type = $this->typeParser->parse($tokens);
@@ -906,9 +938,16 @@ private function parseRequireImplementsTagValue(TokenIterator $tokens): Ast\PhpD
 		return new Ast\PhpDoc\RequireImplementsTagValueNode($type, $description);
 	}
 
+	private function parseSealedTagValue(TokenIterator $tokens): Ast\PhpDoc\SealedTagValueNode
+	{
+		$type = $this->typeParser->parse($tokens);
+		$description = $this->parseOptionalDescription($tokens, true);
+		return new Ast\PhpDoc\SealedTagValueNode($type, $description);
+	}
+
 	private function parseDeprecatedTagValue(TokenIterator $tokens): Ast\PhpDoc\DeprecatedTagValueNode
 	{
-		$description = $this->parseOptionalDescription($tokens);
+		$description = $this->parseOptionalDescription($tokens, false);
 		return new Ast\PhpDoc\DeprecatedTagValueNode($description);
 	}
 
@@ -917,7 +956,7 @@ private function parsePropertyTagValue(TokenIterator $tokens): Ast\PhpDoc\Proper
 	{
 		$type = $this->typeParser->parse($tokens);
 		$parameterName = $this->parseRequiredVariableName($tokens);
-		$description = $this->parseOptionalDescription($tokens);
+		$description = $this->parseOptionalDescription($tokens, false);
 		return new Ast\PhpDoc\PropertyTagValueNode($type, $parameterName, $description);
 	}
 
@@ -960,7 +999,7 @@ private function parseMethodTagValue(TokenIterator $tokens): Ast\PhpDoc\MethodTa
 					$tokens,
 					$this->typeParser->parseTemplateTagValue($tokens),
 					$startLine,
-					$startIndex
+					$startIndex,
 				);
 			} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA));
 			$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);
@@ -976,7 +1015,7 @@ private function parseMethodTagValue(TokenIterator $tokens): Ast\PhpDoc\MethodTa
 		}
 		$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);
 
-		$description = $this->parseOptionalDescription($tokens);
+		$description = $this->parseOptionalDescription($tokens, false);
 		return new Ast\PhpDoc\MethodTagValueNode($isStatic, $returnType, $methodName, $parameters, $description, $templateTypes);
 	}
 
@@ -1013,7 +1052,7 @@ private function parseMethodTagValueParameter(TokenIterator $tokens): Ast\PhpDoc
 			$tokens,
 			new Ast\PhpDoc\MethodTagValueParameterNode($parameterType, $isReference, $isVariadic, $parameterName, $defaultValue),
 			$startLine,
-			$startIndex
+			$startIndex,
 		);
 	}
 
@@ -1026,10 +1065,10 @@ private function parseExtendsTagValue(string $tagName, TokenIterator $tokens): A
 
 		$type = $this->typeParser->parseGeneric(
 			$tokens,
-			$this->typeParser->enrichWithAttributes($tokens, $baseType, $startLine, $startIndex)
+			$this->typeParser->enrichWithAttributes($tokens, $baseType, $startLine, $startIndex),
 		);
 
-		$description = $this->parseOptionalDescription($tokens);
+		$description = $this->parseOptionalDescription($tokens, true);
 
 		switch ($tagName) {
 			case '@extends':
@@ -1048,40 +1087,34 @@ private function parseTypeAliasTagValue(TokenIterator $tokens): Ast\PhpDoc\TypeA
 		$alias = $tokens->currentTokenValue();
 		$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
 
-		// support psalm-type syntax
+		// support phan-type/psalm-type syntax
 		$tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL);
 
-		if ($this->preserveTypeAliasesWithInvalidTypes) {
-			$startLine = $tokens->currentTokenLine();
-			$startIndex = $tokens->currentTokenIndex();
-			try {
-				$type = $this->typeParser->parse($tokens);
-				if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
-					if (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
-						throw new ParserException(
-							$tokens->currentTokenValue(),
-							$tokens->currentTokenType(),
-							$tokens->currentTokenOffset(),
-							Lexer::TOKEN_PHPDOC_EOL,
-							null,
-							$tokens->currentTokenLine()
-						);
-					}
+		$startLine = $tokens->currentTokenLine();
+		$startIndex = $tokens->currentTokenIndex();
+		try {
+			$type = $this->typeParser->parse($tokens);
+			if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {
+				if (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
+					throw new ParserException(
+						$tokens->currentTokenValue(),
+						$tokens->currentTokenType(),
+						$tokens->currentTokenOffset(),
+						Lexer::TOKEN_PHPDOC_EOL,
+						null,
+						$tokens->currentTokenLine(),
+					);
 				}
-
-				return new Ast\PhpDoc\TypeAliasTagValueNode($alias, $type);
-			} catch (ParserException $e) {
-				$this->parseOptionalDescription($tokens);
-				return new Ast\PhpDoc\TypeAliasTagValueNode(
-					$alias,
-					$this->enrichWithAttributes($tokens, new Ast\Type\InvalidTypeNode($e), $startLine, $startIndex)
-				);
 			}
-		}
-
-		$type = $this->typeParser->parse($tokens);
 
-		return new Ast\PhpDoc\TypeAliasTagValueNode($alias, $type);
+			return new Ast\PhpDoc\TypeAliasTagValueNode($alias, $type);
+		} catch (ParserException $e) {
+			$this->parseOptionalDescription($tokens, false);
+			return new Ast\PhpDoc\TypeAliasTagValueNode(
+				$alias,
+				$this->enrichWithAttributes($tokens, new Ast\Type\InvalidTypeNode($e), $startLine, $startIndex),
+			);
+		}
 	}
 
 	private function parseTypeAliasImportTagValue(TokenIterator $tokens): Ast\PhpDoc\TypeAliasImportTagValueNode
@@ -1099,7 +1132,7 @@ private function parseTypeAliasImportTagValue(TokenIterator $tokens): Ast\PhpDoc
 			$tokens,
 			new IdentifierTypeNode($importedFrom),
 			$identifierStartLine,
-			$identifierStartIndex
+			$identifierStartIndex,
 		);
 
 		$importedAs = null;
@@ -1120,7 +1153,7 @@ private function parseAssertTagValue(TokenIterator $tokens): Ast\PhpDoc\PhpDocTa
 		$isEquality = $tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL);
 		$type = $this->typeParser->parse($tokens);
 		$parameter = $this->parseAssertParameter($tokens);
-		$description = $this->parseOptionalDescription($tokens);
+		$description = $this->parseOptionalDescription($tokens, false);
 
 		if (array_key_exists('method', $parameter)) {
 			return new Ast\PhpDoc\AssertTagMethodValueNode($type, $parameter['parameter'], $parameter['method'], $isNegated, $description, $isEquality);
@@ -1165,7 +1198,7 @@ private function parseAssertParameter(TokenIterator $tokens): array
 	private function parseSelfOutTagValue(TokenIterator $tokens): Ast\PhpDoc\SelfOutTagValueNode
 	{
 		$type = $this->typeParser->parse($tokens);
-		$description = $this->parseOptionalDescription($tokens);
+		$description = $this->parseOptionalDescription($tokens, true);
 
 		return new Ast\PhpDoc\SelfOutTagValueNode($type, $description);
 	}
@@ -1174,7 +1207,7 @@ private function parseParamOutTagValue(TokenIterator $tokens): Ast\PhpDoc\ParamO
 	{
 		$type = $this->typeParser->parse($tokens);
 		$parameterName = $this->parseRequiredVariableName($tokens);
-		$description = $this->parseOptionalDescription($tokens);
+		$description = $this->parseOptionalDescription($tokens, false);
 
 		return new Ast\PhpDoc\ParamOutTagValueNode($type, $parameterName, $description);
 	}
@@ -1204,7 +1237,10 @@ private function parseRequiredVariableName(TokenIterator $tokens): string
 		return $parameterName;
 	}
 
-	private function parseOptionalDescription(TokenIterator $tokens, bool $limitStartToken = false): string
+	/**
+	 * @param bool $limitStartToken true should be used when the description immediately follows a parsed type
+	 */
+	private function parseOptionalDescription(TokenIterator $tokens, bool $limitStartToken): string
 	{
 		if ($limitStartToken) {
 			foreach (self::DISALLOWED_DESCRIPTION_START_TOKENS as $disallowedStartToken) {
@@ -1216,8 +1252,7 @@ private function parseOptionalDescription(TokenIterator $tokens, bool $limitStar
 			}
 
 			if (
-				$this->requireWhitespaceBeforeDescription
-				&& !$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END)
+				!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END)
 				&& !$tokens->isPrecededByHorizontalWhitespace()
 			) {
 				$tokens->consumeTokenType(Lexer::TOKEN_HORIZONTAL_WS); // will throw exception
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Parser/StringUnescaper.php b/app/vendor/phpstan/phpdoc-parser/src/Parser/StringUnescaper.php
index 705240551..e8e0a3d60 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Parser/StringUnescaper.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Parser/StringUnescaper.php
@@ -2,6 +2,7 @@
 
 namespace PHPStan\PhpDocParser\Parser;
 
+use PHPStan\ShouldNotHappenException;
 use function chr;
 use function hexdec;
 use function octdec;
@@ -30,7 +31,7 @@ public static function unescapeString(string $string): string
 			return str_replace(
 				['\\\\', '\\\''],
 				['\\', '\''],
-				substr($string, 1, -1)
+				substr($string, 1, -1),
 			);
 		}
 
@@ -56,12 +57,15 @@ static function ($matches) {
 					return chr((int) hexdec(substr($str, 1)));
 				}
 				if ($str[0] === 'u') {
+					if (!isset($matches[2])) {
+						throw new ShouldNotHappenException();
+					}
 					return self::codePointToUtf8((int) hexdec($matches[2]));
 				}
 
 				return chr((int) octdec($str));
 			},
-			$str
+			$str,
 		);
 	}
 
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Parser/TokenIterator.php b/app/vendor/phpstan/phpdoc-parser/src/Parser/TokenIterator.php
index 9be7593d3..f2be3da4a 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Parser/TokenIterator.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Parser/TokenIterator.php
@@ -3,6 +3,7 @@
 namespace PHPStan\PhpDocParser\Parser;
 
 use LogicException;
+use PHPStan\PhpDocParser\Ast\Comment;
 use PHPStan\PhpDocParser\Lexer\Lexer;
 use function array_pop;
 use function assert;
@@ -15,19 +16,20 @@ class TokenIterator
 {
 
 	/** @var list */
-	private $tokens;
+	private array $tokens;
 
-	/** @var int */
-	private $index;
+	private int $index;
 
-	/** @var int[] */
-	private $savePoints = [];
+	/** @var list */
+	private array $comments = [];
+
+	/** @var list}> */
+	private array $savePoints = [];
 
 	/** @var list */
-	private $skippedTokenTypes = [Lexer::TOKEN_HORIZONTAL_WS];
+	private array $skippedTokenTypes = [Lexer::TOKEN_HORIZONTAL_WS];
 
-	/** @var string|null */
-	private $newline = null;
+	private ?string $newline = null;
 
 	/**
 	 * @param list $tokens
@@ -154,8 +156,7 @@ public function consumeTokenType(int $tokenType): void
 			}
 		}
 
-		$this->index++;
-		$this->skipIrrelevantTokens();
+		$this->next();
 	}
 
 
@@ -168,8 +169,7 @@ public function consumeTokenValue(int $tokenType, string $tokenValue): void
 			$this->throwError($tokenType, $tokenValue);
 		}
 
-		$this->index++;
-		$this->skipIrrelevantTokens();
+		$this->next();
 	}
 
 
@@ -180,12 +180,20 @@ public function tryConsumeTokenValue(string $tokenValue): bool
 			return false;
 		}
 
-		$this->index++;
-		$this->skipIrrelevantTokens();
+		$this->next();
 
 		return true;
 	}
 
+	/**
+	 * @return list
+	 */
+	public function flushComments(): array
+	{
+		$res = $this->comments;
+		$this->comments = [];
+		return $res;
+	}
 
 	/** @phpstan-impure */
 	public function tryConsumeTokenType(int $tokenType): bool
@@ -200,13 +208,50 @@ public function tryConsumeTokenType(int $tokenType): bool
 			}
 		}
 
-		$this->index++;
-		$this->skipIrrelevantTokens();
+		$this->next();
 
 		return true;
 	}
 
 
+	/**
+	 * @deprecated Use skipNewLineTokensAndConsumeComments instead (when parsing a type)
+	 */
+	public function skipNewLineTokens(): void
+	{
+		if (!$this->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
+			return;
+		}
+
+		do {
+			$foundNewLine = $this->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+		} while ($foundNewLine === true);
+	}
+
+
+	public function skipNewLineTokensAndConsumeComments(): void
+	{
+		if ($this->currentTokenType() === Lexer::TOKEN_COMMENT) {
+			$this->comments[] = new Comment($this->currentTokenValue(), $this->currentTokenLine(), $this->currentTokenIndex());
+			$this->next();
+		}
+
+		if (!$this->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
+			return;
+		}
+
+		do {
+			$foundNewLine = $this->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+			if ($this->currentTokenType() !== Lexer::TOKEN_COMMENT) {
+				continue;
+			}
+
+			$this->comments[] = new Comment($this->currentTokenValue(), $this->currentTokenLine(), $this->currentTokenIndex());
+			$this->next();
+		} while ($foundNewLine === true);
+	}
+
+
 	private function detectNewline(): void
 	{
 		$value = $this->currentTokenValue();
@@ -282,7 +327,7 @@ public function forwardToTheEnd(): void
 
 	public function pushSavePoint(): void
 	{
-		$this->savePoints[] = $this->index;
+		$this->savePoints[] = [$this->index, $this->comments];
 	}
 
 
@@ -294,9 +339,9 @@ public function dropSavePoint(): void
 
 	public function rollback(): void
 	{
-		$index = array_pop($this->savePoints);
-		assert($index !== null);
-		$this->index = $index;
+		$savepoint = array_pop($this->savePoints);
+		assert($savepoint !== null);
+		[$this->index, $this->comments] = $savepoint;
 	}
 
 
@@ -311,7 +356,7 @@ private function throwError(int $expectedTokenType, ?string $expectedTokenValue
 			$this->currentTokenOffset(),
 			$expectedTokenType,
 			$expectedTokenValue,
-			$this->currentTokenLine()
+			$this->currentTokenLine(),
 		);
 	}
 
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Parser/TypeParser.php b/app/vendor/phpstan/phpdoc-parser/src/Parser/TypeParser.php
index ebc2fbab4..fc225854d 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Parser/TypeParser.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Parser/TypeParser.php
@@ -6,41 +6,27 @@
 use PHPStan\PhpDocParser\Ast;
 use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode;
 use PHPStan\PhpDocParser\Lexer\Lexer;
+use PHPStan\PhpDocParser\ParserConfig;
 use function in_array;
 use function str_replace;
 use function strlen;
 use function strpos;
 use function substr_compare;
-use function trim;
 
 class TypeParser
 {
 
-	/** @var ConstExprParser|null */
-	private $constExprParser;
+	private ParserConfig $config;
 
-	/** @var bool */
-	private $quoteAwareConstExprString;
+	private ConstExprParser $constExprParser;
 
-	/** @var bool */
-	private $useLinesAttributes;
-
-	/** @var bool */
-	private $useIndexAttributes;
-
-	/**
-	 * @param array{lines?: bool, indexes?: bool} $usedAttributes
-	 */
 	public function __construct(
-		?ConstExprParser $constExprParser = null,
-		bool $quoteAwareConstExprString = false,
-		array $usedAttributes = []
+		ParserConfig $config,
+		ConstExprParser $constExprParser
 	)
 	{
+		$this->config = $config;
 		$this->constExprParser = $constExprParser;
-		$this->quoteAwareConstExprString = $quoteAwareConstExprString;
-		$this->useLinesAttributes = $usedAttributes['lines'] ?? false;
-		$this->useIndexAttributes = $usedAttributes['indexes'] ?? false;
 	}
 
 	/** @phpstan-impure */
@@ -54,17 +40,44 @@ public function parse(TokenIterator $tokens): Ast\Type\TypeNode
 		} else {
 			$type = $this->parseAtomic($tokens);
 
-			if ($tokens->isCurrentTokenType(Lexer::TOKEN_UNION)) {
-				$type = $this->parseUnion($tokens, $type);
+			$tokens->pushSavePoint();
+			$tokens->skipNewLineTokensAndConsumeComments();
+
+			try {
+				$enrichedType = $this->enrichTypeOnUnionOrIntersection($tokens, $type);
+
+			} catch (ParserException $parserException) {
+				$enrichedType = null;
+			}
+
+			if ($enrichedType !== null) {
+				$type = $enrichedType;
+				$tokens->dropSavePoint();
 
-			} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_INTERSECTION)) {
-				$type = $this->parseIntersection($tokens, $type);
+			} else {
+				$tokens->rollback();
+				$type = $this->enrichTypeOnUnionOrIntersection($tokens, $type) ?? $type;
 			}
 		}
 
 		return $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex);
 	}
 
+	/** @phpstan-impure */
+	private function enrichTypeOnUnionOrIntersection(TokenIterator $tokens, Ast\Type\TypeNode $type): ?Ast\Type\TypeNode
+	{
+		if ($tokens->isCurrentTokenType(Lexer::TOKEN_UNION)) {
+			return $this->parseUnion($tokens, $type);
+
+		}
+
+		if ($tokens->isCurrentTokenType(Lexer::TOKEN_INTERSECTION)) {
+			return $this->parseIntersection($tokens, $type);
+		}
+
+		return null;
+	}
+
 	/**
 	 * @internal
 	 * @template T of Ast\Node
@@ -73,12 +86,17 @@ public function parse(TokenIterator $tokens): Ast\Type\TypeNode
 	 */
 	public function enrichWithAttributes(TokenIterator $tokens, Ast\Node $type, int $startLine, int $startIndex): Ast\Node
 	{
-		if ($this->useLinesAttributes) {
+		if ($this->config->useLinesAttributes) {
 			$type->setAttribute(Ast\Attribute::START_LINE, $startLine);
 			$type->setAttribute(Ast\Attribute::END_LINE, $tokens->currentTokenLine());
 		}
 
-		if ($this->useIndexAttributes) {
+		$comments = $tokens->flushComments();
+		if ($this->config->useCommentsAttributes) {
+			$type->setAttribute(Ast\Attribute::COMMENTS, $comments);
+		}
+
+		if ($this->config->useIndexAttributes) {
 			$type->setAttribute(Ast\Attribute::START_INDEX, $startIndex);
 			$type->setAttribute(Ast\Attribute::END_INDEX, $tokens->endIndexOfLastRelevantToken());
 		}
@@ -104,7 +122,7 @@ private function subParse(TokenIterator $tokens): Ast\Type\TypeNode
 			if ($tokens->isCurrentTokenValue('is')) {
 				$type = $this->parseConditional($tokens, $type);
 			} else {
-				$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+				$tokens->skipNewLineTokensAndConsumeComments();
 
 				if ($tokens->isCurrentTokenType(Lexer::TOKEN_UNION)) {
 					$type = $this->subParseUnion($tokens, $type);
@@ -126,9 +144,9 @@ private function parseAtomic(TokenIterator $tokens): Ast\Type\TypeNode
 		$startIndex = $tokens->currentTokenIndex();
 
 		if ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {
-			$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+			$tokens->skipNewLineTokensAndConsumeComments();
 			$type = $this->subParse($tokens);
-			$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+			$tokens->skipNewLineTokensAndConsumeComments();
 
 			$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);
 
@@ -180,7 +198,13 @@ private function parseAtomic(TokenIterator $tokens): Ast\Type\TypeNode
 				} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
 					$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);
 
-				} elseif (in_array($type->name, ['array', 'list', 'object'], true) && $tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET) && !$tokens->isPrecededByHorizontalWhitespace()) {
+				} elseif (in_array($type->name, [
+					Ast\Type\ArrayShapeNode::KIND_ARRAY,
+					Ast\Type\ArrayShapeNode::KIND_LIST,
+					Ast\Type\ArrayShapeNode::KIND_NON_EMPTY_ARRAY,
+					Ast\Type\ArrayShapeNode::KIND_NON_EMPTY_LIST,
+					'object',
+				], true) && $tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET) && !$tokens->isPrecededByHorizontalWhitespace()) {
 					if ($type->name === 'object') {
 						$type = $this->parseObjectShape($tokens);
 					} else {
@@ -190,7 +214,7 @@ private function parseAtomic(TokenIterator $tokens): Ast\Type\TypeNode
 					if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
 						$type = $this->tryParseArrayOrOffsetAccess(
 							$tokens,
-							$this->enrichWithAttributes($tokens, $type, $startLine, $startIndex)
+							$this->enrichWithAttributes($tokens, $type, $startLine, $startIndex),
 						);
 					}
 				}
@@ -208,19 +232,8 @@ private function parseAtomic(TokenIterator $tokens): Ast\Type\TypeNode
 		$currentTokenOffset = $tokens->currentTokenOffset();
 		$currentTokenLine = $tokens->currentTokenLine();
 
-		if ($this->constExprParser === null) {
-			throw new ParserException(
-				$currentTokenValue,
-				$currentTokenType,
-				$currentTokenOffset,
-				Lexer::TOKEN_IDENTIFIER,
-				null,
-				$currentTokenLine
-			);
-		}
-
 		try {
-			$constExpr = $this->constExprParser->parse($tokens, true);
+			$constExpr = $this->constExprParser->parse($tokens);
 			if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) {
 				throw new ParserException(
 					$currentTokenValue,
@@ -228,11 +241,21 @@ private function parseAtomic(TokenIterator $tokens): Ast\Type\TypeNode
 					$currentTokenOffset,
 					Lexer::TOKEN_IDENTIFIER,
 					null,
-					$currentTokenLine
+					$currentTokenLine,
 				);
 			}
 
-			return $this->enrichWithAttributes($tokens, new Ast\Type\ConstTypeNode($constExpr), $startLine, $startIndex);
+			$type = $this->enrichWithAttributes(
+				$tokens,
+				new Ast\Type\ConstTypeNode($constExpr),
+				$startLine,
+				$startIndex,
+			);
+			if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
+				$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);
+			}
+
+			return $type;
 		} catch (LogicException $e) {
 			throw new ParserException(
 				$currentTokenValue,
@@ -240,7 +263,7 @@ private function parseAtomic(TokenIterator $tokens): Ast\Type\TypeNode
 				$currentTokenOffset,
 				Lexer::TOKEN_IDENTIFIER,
 				null,
-				$currentTokenLine
+				$currentTokenLine,
 			);
 		}
 	}
@@ -253,6 +276,14 @@ private function parseUnion(TokenIterator $tokens, Ast\Type\TypeNode $type): Ast
 
 		while ($tokens->tryConsumeTokenType(Lexer::TOKEN_UNION)) {
 			$types[] = $this->parseAtomic($tokens);
+			$tokens->pushSavePoint();
+			$tokens->skipNewLineTokensAndConsumeComments();
+			if (!$tokens->isCurrentTokenType(Lexer::TOKEN_UNION)) {
+				$tokens->rollback();
+				break;
+			}
+
+			$tokens->dropSavePoint();
 		}
 
 		return new Ast\Type\UnionTypeNode($types);
@@ -265,9 +296,9 @@ private function subParseUnion(TokenIterator $tokens, Ast\Type\TypeNode $type):
 		$types = [$type];
 
 		while ($tokens->tryConsumeTokenType(Lexer::TOKEN_UNION)) {
-			$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+			$tokens->skipNewLineTokensAndConsumeComments();
 			$types[] = $this->parseAtomic($tokens);
-			$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+			$tokens->skipNewLineTokensAndConsumeComments();
 		}
 
 		return new Ast\Type\UnionTypeNode($types);
@@ -281,6 +312,14 @@ private function parseIntersection(TokenIterator $tokens, Ast\Type\TypeNode $typ
 
 		while ($tokens->tryConsumeTokenType(Lexer::TOKEN_INTERSECTION)) {
 			$types[] = $this->parseAtomic($tokens);
+			$tokens->pushSavePoint();
+			$tokens->skipNewLineTokensAndConsumeComments();
+			if (!$tokens->isCurrentTokenType(Lexer::TOKEN_INTERSECTION)) {
+				$tokens->rollback();
+				break;
+			}
+
+			$tokens->dropSavePoint();
 		}
 
 		return new Ast\Type\IntersectionTypeNode($types);
@@ -293,9 +332,9 @@ private function subParseIntersection(TokenIterator $tokens, Ast\Type\TypeNode $
 		$types = [$type];
 
 		while ($tokens->tryConsumeTokenType(Lexer::TOKEN_INTERSECTION)) {
-			$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+			$tokens->skipNewLineTokensAndConsumeComments();
 			$types[] = $this->parseAtomic($tokens);
-			$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+			$tokens->skipNewLineTokensAndConsumeComments();
 		}
 
 		return new Ast\Type\IntersectionTypeNode($types);
@@ -315,15 +354,15 @@ private function parseConditional(TokenIterator $tokens, Ast\Type\TypeNode $subj
 
 		$targetType = $this->parse($tokens);
 
-		$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+		$tokens->skipNewLineTokensAndConsumeComments();
 		$tokens->consumeTokenType(Lexer::TOKEN_NULLABLE);
-		$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+		$tokens->skipNewLineTokensAndConsumeComments();
 
 		$ifType = $this->parse($tokens);
 
-		$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+		$tokens->skipNewLineTokensAndConsumeComments();
 		$tokens->consumeTokenType(Lexer::TOKEN_COLON);
-		$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+		$tokens->skipNewLineTokensAndConsumeComments();
 
 		$elseType = $this->subParse($tokens);
 
@@ -344,15 +383,15 @@ private function parseConditionalForParameter(TokenIterator $tokens, string $par
 
 		$targetType = $this->parse($tokens);
 
-		$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+		$tokens->skipNewLineTokensAndConsumeComments();
 		$tokens->consumeTokenType(Lexer::TOKEN_NULLABLE);
-		$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+		$tokens->skipNewLineTokensAndConsumeComments();
 
 		$ifType = $this->parse($tokens);
 
-		$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+		$tokens->skipNewLineTokensAndConsumeComments();
 		$tokens->consumeTokenType(Lexer::TOKEN_COLON);
-		$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+		$tokens->skipNewLineTokensAndConsumeComments();
 
 		$elseType = $this->subParse($tokens);
 
@@ -411,6 +450,7 @@ public function isHtml(TokenIterator $tokens): bool
 	public function parseGeneric(TokenIterator $tokens, Ast\Type\IdentifierTypeNode $baseType): Ast\Type\GenericTypeNode
 	{
 		$tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET);
+		$tokens->skipNewLineTokensAndConsumeComments();
 
 		$startLine = $baseType->getAttribute(Ast\Attribute::START_LINE);
 		$startIndex = $baseType->getAttribute(Ast\Attribute::START_INDEX);
@@ -418,8 +458,11 @@ public function parseGeneric(TokenIterator $tokens, Ast\Type\IdentifierTypeNode
 		$variances = [];
 
 		$isFirst = true;
-		while ($isFirst || $tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {
-			$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+		while (
+			$isFirst
+			|| $tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)
+		) {
+			$tokens->skipNewLineTokensAndConsumeComments();
 
 			// trailing comma case
 			if (!$isFirst && $tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET)) {
@@ -428,7 +471,7 @@ public function parseGeneric(TokenIterator $tokens, Ast\Type\IdentifierTypeNode
 			$isFirst = false;
 
 			[$genericTypes[], $variances[]] = $this->parseGenericTypeArgument($tokens);
-			$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+			$tokens->skipNewLineTokensAndConsumeComments();
 		}
 
 		$type = new Ast\Type\GenericTypeNode($baseType, $genericTypes, $variances);
@@ -481,11 +524,14 @@ public function parseTemplateTagValue(
 		$name = $tokens->currentTokenValue();
 		$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);
 
+		$upperBound = $lowerBound = null;
+
 		if ($tokens->tryConsumeTokenValue('of') || $tokens->tryConsumeTokenValue('as')) {
-			$bound = $this->parse($tokens);
+			$upperBound = $this->parse($tokens);
+		}
 
-		} else {
-			$bound = null;
+		if ($tokens->tryConsumeTokenValue('super')) {
+			$lowerBound = $this->parse($tokens);
 		}
 
 		if ($tokens->tryConsumeTokenValue('=')) {
@@ -500,7 +546,11 @@ public function parseTemplateTagValue(
 			$description = '';
 		}
 
-		return new Ast\PhpDoc\TemplateTagValueNode($name, $bound, $description, $default);
+		if ($name === '') {
+			throw new LogicException('Template tag name cannot be empty.');
+		}
+
+		return new Ast\PhpDoc\TemplateTagValueNode($name, $upperBound, $description, $default, $lowerBound);
 	}
 
 
@@ -512,19 +562,19 @@ private function parseCallable(TokenIterator $tokens, Ast\Type\IdentifierTypeNod
 			: [];
 
 		$tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES);
-		$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+		$tokens->skipNewLineTokensAndConsumeComments();
 
 		$parameters = [];
 		if (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) {
 			$parameters[] = $this->parseCallableParameter($tokens);
-			$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+			$tokens->skipNewLineTokensAndConsumeComments();
 			while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {
-				$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+				$tokens->skipNewLineTokensAndConsumeComments();
 				if ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) {
 					break;
 				}
 				$parameters[] = $this->parseCallableParameter($tokens);
-				$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+				$tokens->skipNewLineTokensAndConsumeComments();
 			}
 		}
 
@@ -552,7 +602,7 @@ private function parseCallableTemplates(TokenIterator $tokens): array
 
 		$isFirst = true;
 		while ($isFirst || $tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {
-			$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+			$tokens->skipNewLineTokensAndConsumeComments();
 
 			// trailing comma case
 			if (!$isFirst && $tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET)) {
@@ -561,7 +611,7 @@ private function parseCallableTemplates(TokenIterator $tokens): array
 			$isFirst = false;
 
 			$templates[] = $this->parseCallableTemplateArgument($tokens);
-			$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+			$tokens->skipNewLineTokensAndConsumeComments();
 		}
 
 		$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);
@@ -579,7 +629,7 @@ private function parseCallableTemplateArgument(TokenIterator $tokens): Ast\PhpDo
 			$tokens,
 			$this->parseTemplateTagValue($tokens),
 			$startLine,
-			$startIndex
+			$startIndex,
 		);
 	}
 
@@ -606,7 +656,7 @@ private function parseCallableParameter(TokenIterator $tokens): Ast\Type\Callabl
 			$tokens,
 			new Ast\Type\CallableTypeParameterNode($type, $isReference, $isVariadic, $parameterName, $isOptional),
 			$startLine,
-			$startIndex
+			$startIndex,
 		);
 	}
 
@@ -634,7 +684,7 @@ private function parseCallableReturnType(TokenIterator $tokens): Ast\Type\TypeNo
 					$tokens,
 					$type,
 					$startLine,
-					$startIndex
+					$startIndex,
 				));
 			}
 
@@ -653,15 +703,15 @@ private function parseCallableReturnType(TokenIterator $tokens): Ast\Type\TypeNo
 								$tokens,
 								$type,
 								$startLine,
-								$startIndex
-							)
+								$startIndex,
+							),
 						);
 						if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
 							$type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes(
 								$tokens,
 								$type,
 								$startLine,
-								$startIndex
+								$startIndex,
 							));
 						}
 
@@ -670,10 +720,16 @@ private function parseCallableReturnType(TokenIterator $tokens): Ast\Type\TypeNo
 							$tokens,
 							$type,
 							$startLine,
-							$startIndex
+							$startIndex,
 						));
 
-					} elseif (in_array($type->name, ['array', 'list', 'object'], true) && $tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET) && !$tokens->isPrecededByHorizontalWhitespace()) {
+					} elseif (in_array($type->name, [
+						Ast\Type\ArrayShapeNode::KIND_ARRAY,
+						Ast\Type\ArrayShapeNode::KIND_LIST,
+						Ast\Type\ArrayShapeNode::KIND_NON_EMPTY_ARRAY,
+						Ast\Type\ArrayShapeNode::KIND_NON_EMPTY_LIST,
+						'object',
+					], true) && $tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET) && !$tokens->isPrecededByHorizontalWhitespace()) {
 						if ($type->name === 'object') {
 							$type = $this->parseObjectShape($tokens);
 						} else {
@@ -681,7 +737,7 @@ private function parseCallableReturnType(TokenIterator $tokens): Ast\Type\TypeNo
 								$tokens,
 								$type,
 								$startLine,
-								$startIndex
+								$startIndex,
 							), $type->name);
 						}
 
@@ -690,7 +746,7 @@ private function parseCallableReturnType(TokenIterator $tokens): Ast\Type\TypeNo
 								$tokens,
 								$type,
 								$startLine,
-								$startIndex
+								$startIndex,
 							));
 						}
 					}
@@ -709,19 +765,8 @@ private function parseCallableReturnType(TokenIterator $tokens): Ast\Type\TypeNo
 		$currentTokenOffset = $tokens->currentTokenOffset();
 		$currentTokenLine = $tokens->currentTokenLine();
 
-		if ($this->constExprParser === null) {
-			throw new ParserException(
-				$currentTokenValue,
-				$currentTokenType,
-				$currentTokenOffset,
-				Lexer::TOKEN_IDENTIFIER,
-				null,
-				$currentTokenLine
-			);
-		}
-
 		try {
-			$constExpr = $this->constExprParser->parse($tokens, true);
+			$constExpr = $this->constExprParser->parse($tokens);
 			if ($constExpr instanceof Ast\ConstExpr\ConstExprArrayNode) {
 				throw new ParserException(
 					$currentTokenValue,
@@ -729,18 +774,18 @@ private function parseCallableReturnType(TokenIterator $tokens): Ast\Type\TypeNo
 					$currentTokenOffset,
 					Lexer::TOKEN_IDENTIFIER,
 					null,
-					$currentTokenLine
+					$currentTokenLine,
 				);
 			}
 
-			$type = new Ast\Type\ConstTypeNode($constExpr);
+			$type = $this->enrichWithAttributes(
+				$tokens,
+				new Ast\Type\ConstTypeNode($constExpr),
+				$startLine,
+				$startIndex,
+			);
 			if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
-				$type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes(
-					$tokens,
-					$type,
-					$startLine,
-					$startIndex
-				));
+				$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);
 			}
 
 			return $type;
@@ -751,7 +796,7 @@ private function parseCallableReturnType(TokenIterator $tokens): Ast\Type\TypeNo
 				$currentTokenOffset,
 				Lexer::TOKEN_IDENTIFIER,
 				null,
-				$currentTokenLine
+				$currentTokenLine,
 			);
 		}
 	}
@@ -797,7 +842,7 @@ private function tryParseArrayOrOffsetAccess(TokenIterator $tokens, Ast\Type\Typ
 							$tokens,
 							$type,
 							$startLine,
-							$startIndex
+							$startIndex,
 						);
 					}
 				} else {
@@ -810,7 +855,7 @@ private function tryParseArrayOrOffsetAccess(TokenIterator $tokens, Ast\Type\Typ
 							$tokens,
 							$type,
 							$startLine,
-							$startIndex
+							$startIndex,
 						);
 					}
 				}
@@ -834,29 +879,55 @@ private function parseArrayShape(TokenIterator $tokens, Ast\Type\TypeNode $type,
 
 		$items = [];
 		$sealed = true;
+		$unsealedType = null;
+
+		$done = false;
 
 		do {
-			$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+			$tokens->skipNewLineTokensAndConsumeComments();
 
 			if ($tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) {
-				return new Ast\Type\ArrayShapeNode($items, true, $kind);
+				return Ast\Type\ArrayShapeNode::createSealed($items, $kind);
 			}
 
 			if ($tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC)) {
 				$sealed = false;
+
+				$tokens->skipNewLineTokensAndConsumeComments();
+				if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) {
+					if ($kind === Ast\Type\ArrayShapeNode::KIND_ARRAY) {
+						$unsealedType = $this->parseArrayShapeUnsealedType($tokens);
+					} else {
+						$unsealedType = $this->parseListShapeUnsealedType($tokens);
+					}
+					$tokens->skipNewLineTokensAndConsumeComments();
+				}
+
 				$tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA);
 				break;
 			}
 
 			$items[] = $this->parseArrayShapeItem($tokens);
+			$tokens->skipNewLineTokensAndConsumeComments();
+			if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {
+				$done = true;
+			}
+			if ($tokens->currentTokenType() !== Lexer::TOKEN_COMMENT) {
+				continue;
+			}
 
-			$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
-		} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA));
+			$tokens->next();
 
-		$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+		} while (!$done);
+
+		$tokens->skipNewLineTokensAndConsumeComments();
 		$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET);
 
-		return new Ast\Type\ArrayShapeNode($items, $sealed, $kind);
+		if ($sealed) {
+			return Ast\Type\ArrayShapeNode::createSealed($items, $kind);
+		}
+
+		return Ast\Type\ArrayShapeNode::createUnsealed($items, $unsealedType, $kind);
 	}
 
 
@@ -865,19 +936,24 @@ private function parseArrayShapeItem(TokenIterator $tokens): Ast\Type\ArrayShape
 	{
 		$startLine = $tokens->currentTokenLine();
 		$startIndex = $tokens->currentTokenIndex();
+
+		// parse any comments above the item
+		$tokens->skipNewLineTokensAndConsumeComments();
+
 		try {
 			$tokens->pushSavePoint();
 			$key = $this->parseArrayShapeKey($tokens);
 			$optional = $tokens->tryConsumeTokenType(Lexer::TOKEN_NULLABLE);
 			$tokens->consumeTokenType(Lexer::TOKEN_COLON);
 			$value = $this->parse($tokens);
+
 			$tokens->dropSavePoint();
 
 			return $this->enrichWithAttributes(
 				$tokens,
 				new Ast\Type\ArrayShapeItemNode($key, $optional, $value),
 				$startLine,
-				$startIndex
+				$startIndex,
 			);
 		} catch (ParserException $e) {
 			$tokens->rollback();
@@ -887,7 +963,7 @@ private function parseArrayShapeItem(TokenIterator $tokens): Ast\Type\ArrayShape
 				$tokens,
 				new Ast\Type\ArrayShapeItemNode(null, false, $value),
 				$startLine,
-				$startIndex
+				$startIndex,
 			);
 		}
 	}
@@ -906,19 +982,11 @@ private function parseArrayShapeKey(TokenIterator $tokens)
 			$tokens->next();
 
 		} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING)) {
-			if ($this->quoteAwareConstExprString) {
-				$key = new Ast\ConstExpr\QuoteAwareConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\QuoteAwareConstExprStringNode::SINGLE_QUOTED);
-			} else {
-				$key = new Ast\ConstExpr\ConstExprStringNode(trim($tokens->currentTokenValue(), "'"));
-			}
+			$key = new Ast\ConstExpr\ConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\ConstExprStringNode::SINGLE_QUOTED);
 			$tokens->next();
 
 		} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING)) {
-			if ($this->quoteAwareConstExprString) {
-				$key = new Ast\ConstExpr\QuoteAwareConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\QuoteAwareConstExprStringNode::DOUBLE_QUOTED);
-			} else {
-				$key = new Ast\ConstExpr\ConstExprStringNode(trim($tokens->currentTokenValue(), '"'));
-			}
+			$key = new Ast\ConstExpr\ConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\ConstExprStringNode::DOUBLE_QUOTED);
 
 			$tokens->next();
 
@@ -931,7 +999,64 @@ private function parseArrayShapeKey(TokenIterator $tokens)
 			$tokens,
 			$key,
 			$startLine,
-			$startIndex
+			$startIndex,
+		);
+	}
+
+	/**
+	 * @phpstan-impure
+	 */
+	private function parseArrayShapeUnsealedType(TokenIterator $tokens): Ast\Type\ArrayShapeUnsealedTypeNode
+	{
+		$startLine = $tokens->currentTokenLine();
+		$startIndex = $tokens->currentTokenIndex();
+
+		$tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET);
+		$tokens->skipNewLineTokensAndConsumeComments();
+
+		$valueType = $this->parse($tokens);
+		$tokens->skipNewLineTokensAndConsumeComments();
+
+		$keyType = null;
+		if ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {
+			$tokens->skipNewLineTokensAndConsumeComments();
+
+			$keyType = $valueType;
+			$valueType = $this->parse($tokens);
+			$tokens->skipNewLineTokensAndConsumeComments();
+		}
+
+		$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);
+
+		return $this->enrichWithAttributes(
+			$tokens,
+			new Ast\Type\ArrayShapeUnsealedTypeNode($valueType, $keyType),
+			$startLine,
+			$startIndex,
+		);
+	}
+
+	/**
+	 * @phpstan-impure
+	 */
+	private function parseListShapeUnsealedType(TokenIterator $tokens): Ast\Type\ArrayShapeUnsealedTypeNode
+	{
+		$startLine = $tokens->currentTokenLine();
+		$startIndex = $tokens->currentTokenIndex();
+
+		$tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET);
+		$tokens->skipNewLineTokensAndConsumeComments();
+
+		$valueType = $this->parse($tokens);
+		$tokens->skipNewLineTokensAndConsumeComments();
+
+		$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);
+
+		return $this->enrichWithAttributes(
+			$tokens,
+			new Ast\Type\ArrayShapeUnsealedTypeNode($valueType, null),
+			$startLine,
+			$startIndex,
 		);
 	}
 
@@ -945,7 +1070,7 @@ private function parseObjectShape(TokenIterator $tokens): Ast\Type\ObjectShapeNo
 		$items = [];
 
 		do {
-			$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+			$tokens->skipNewLineTokensAndConsumeComments();
 
 			if ($tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) {
 				return new Ast\Type\ObjectShapeNode($items);
@@ -953,10 +1078,10 @@ private function parseObjectShape(TokenIterator $tokens): Ast\Type\ObjectShapeNo
 
 			$items[] = $this->parseObjectShapeItem($tokens);
 
-			$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+			$tokens->skipNewLineTokensAndConsumeComments();
 		} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA));
 
-		$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);
+		$tokens->skipNewLineTokensAndConsumeComments();
 		$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET);
 
 		return new Ast\Type\ObjectShapeNode($items);
@@ -968,12 +1093,19 @@ private function parseObjectShapeItem(TokenIterator $tokens): Ast\Type\ObjectSha
 		$startLine = $tokens->currentTokenLine();
 		$startIndex = $tokens->currentTokenIndex();
 
+		$tokens->skipNewLineTokensAndConsumeComments();
+
 		$key = $this->parseObjectShapeKey($tokens);
 		$optional = $tokens->tryConsumeTokenType(Lexer::TOKEN_NULLABLE);
 		$tokens->consumeTokenType(Lexer::TOKEN_COLON);
 		$value = $this->parse($tokens);
 
-		return $this->enrichWithAttributes($tokens, new Ast\Type\ObjectShapeItemNode($key, $optional, $value), $startLine, $startIndex);
+		return $this->enrichWithAttributes(
+			$tokens,
+			new Ast\Type\ObjectShapeItemNode($key, $optional, $value),
+			$startLine,
+			$startIndex,
+		);
 	}
 
 	/**
@@ -986,19 +1118,11 @@ private function parseObjectShapeKey(TokenIterator $tokens)
 		$startIndex = $tokens->currentTokenIndex();
 
 		if ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING)) {
-			if ($this->quoteAwareConstExprString) {
-				$key = new Ast\ConstExpr\QuoteAwareConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\QuoteAwareConstExprStringNode::SINGLE_QUOTED);
-			} else {
-				$key = new Ast\ConstExpr\ConstExprStringNode(trim($tokens->currentTokenValue(), "'"));
-			}
+			$key = new Ast\ConstExpr\ConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\ConstExprStringNode::SINGLE_QUOTED);
 			$tokens->next();
 
 		} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING)) {
-			if ($this->quoteAwareConstExprString) {
-				$key = new Ast\ConstExpr\QuoteAwareConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\QuoteAwareConstExprStringNode::DOUBLE_QUOTED);
-			} else {
-				$key = new Ast\ConstExpr\ConstExprStringNode(trim($tokens->currentTokenValue(), '"'));
-			}
+			$key = new Ast\ConstExpr\ConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\ConstExpr\ConstExprStringNode::DOUBLE_QUOTED);
 			$tokens->next();
 
 		} else {
diff --git a/app/vendor/phpstan/phpdoc-parser/src/ParserConfig.php b/app/vendor/phpstan/phpdoc-parser/src/ParserConfig.php
new file mode 100644
index 000000000..0c4377adc
--- /dev/null
+++ b/app/vendor/phpstan/phpdoc-parser/src/ParserConfig.php
@@ -0,0 +1,24 @@
+useLinesAttributes = $usedAttributes['lines'] ?? false;
+		$this->useIndexAttributes = $usedAttributes['indexes'] ?? false;
+		$this->useCommentsAttributes = $usedAttributes['comments'] ?? false;
+	}
+
+}
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Printer/Differ.php b/app/vendor/phpstan/phpdoc-parser/src/Printer/Differ.php
index ab10be59b..c60fd4ad6 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Printer/Differ.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Printer/Differ.php
@@ -180,7 +180,7 @@ private function coalesceReplacements(array $diff): array
 					$newDiff[] = new DiffElem(
 						DiffElem::TYPE_REPLACE,
 						$diff[$i + $n]->old,
-						$diff[$j + $n]->new
+						$diff[$j + $n]->new,
 					);
 				}
 			} else {
diff --git a/app/vendor/phpstan/phpdoc-parser/src/Printer/Printer.php b/app/vendor/phpstan/phpdoc-parser/src/Printer/Printer.php
index d9a060b39..36f6ebe15 100644
--- a/app/vendor/phpstan/phpdoc-parser/src/Printer/Printer.php
+++ b/app/vendor/phpstan/phpdoc-parser/src/Printer/Printer.php
@@ -4,6 +4,7 @@
 
 use LogicException;
 use PHPStan\PhpDocParser\Ast\Attribute;
+use PHPStan\PhpDocParser\Ast\Comment;
 use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprArrayNode;
 use PHPStan\PhpDocParser\Ast\ConstExpr\ConstExprNode;
 use PHPStan\PhpDocParser\Ast\Node;
@@ -20,6 +21,9 @@
 use PHPStan\PhpDocParser\Ast\PhpDoc\MethodTagValueNode;
 use PHPStan\PhpDocParser\Ast\PhpDoc\MethodTagValueParameterNode;
 use PHPStan\PhpDocParser\Ast\PhpDoc\MixinTagValueNode;
+use PHPStan\PhpDocParser\Ast\PhpDoc\ParamClosureThisTagValueNode;
+use PHPStan\PhpDocParser\Ast\PhpDoc\ParamImmediatelyInvokedCallableTagValueNode;
+use PHPStan\PhpDocParser\Ast\PhpDoc\ParamLaterInvokedCallableTagValueNode;
 use PHPStan\PhpDocParser\Ast\PhpDoc\ParamOutTagValueNode;
 use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode;
 use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocChildNode;
@@ -28,9 +32,11 @@
 use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagValueNode;
 use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTextNode;
 use PHPStan\PhpDocParser\Ast\PhpDoc\PropertyTagValueNode;
+use PHPStan\PhpDocParser\Ast\PhpDoc\PureUnlessCallableIsImpureTagValueNode;
 use PHPStan\PhpDocParser\Ast\PhpDoc\RequireExtendsTagValueNode;
 use PHPStan\PhpDocParser\Ast\PhpDoc\RequireImplementsTagValueNode;
 use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
+use PHPStan\PhpDocParser\Ast\PhpDoc\SealedTagValueNode;
 use PHPStan\PhpDocParser\Ast\PhpDoc\SelfOutTagValueNode;
 use PHPStan\PhpDocParser\Ast\PhpDoc\TemplateTagValueNode;
 use PHPStan\PhpDocParser\Ast\PhpDoc\ThrowsTagValueNode;
@@ -40,6 +46,7 @@
 use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode;
 use PHPStan\PhpDocParser\Ast\Type\ArrayShapeItemNode;
 use PHPStan\PhpDocParser\Ast\Type\ArrayShapeNode;
+use PHPStan\PhpDocParser\Ast\Type\ArrayShapeUnsealedTypeNode;
 use PHPStan\PhpDocParser\Ast\Type\ArrayTypeNode;
 use PHPStan\PhpDocParser\Ast\Type\CallableTypeNode;
 use PHPStan\PhpDocParser\Ast\Type\CallableTypeParameterNode;
@@ -61,6 +68,7 @@
 use PHPStan\PhpDocParser\Parser\TokenIterator;
 use function array_keys;
 use function array_map;
+use function assert;
 use function count;
 use function get_class;
 use function get_object_vars;
@@ -69,6 +77,7 @@
 use function is_array;
 use function preg_match_all;
 use function sprintf;
+use function str_replace;
 use function strlen;
 use function strpos;
 use function trim;
@@ -84,7 +93,7 @@ final class Printer
 {
 
 	/** @var Differ */
-	private $differ;
+	private Differ $differ;
 
 	/**
 	 * Map From "{$class}->{$subNode}" to string that should be inserted
@@ -92,7 +101,7 @@ final class Printer
 	 *
 	 * @var array
 	 */
-	private $listInsertionMap = [
+	private array $listInsertionMap = [
 		PhpDocNode::class . '->children' => "\n * ",
 		UnionTypeNode::class . '->types' => '|',
 		IntersectionTypeNode::class . '->types' => '&',
@@ -112,7 +121,7 @@ final class Printer
 	 *
 	 * @var array
 	 */
-	private $emptyListInsertionMap = [
+	private array $emptyListInsertionMap = [
 		CallableTypeNode::class . '->parameters' => ['(', '', ''],
 		ArrayShapeNode::class . '->items' => ['{', '', ''],
 		ObjectShapeNode::class . '->items' => ['{', '', ''],
@@ -121,7 +130,7 @@ final class Printer
 	];
 
 	/** @var array>> */
-	private $parenthesesMap = [
+	private array $parenthesesMap = [
 		CallableTypeNode::class . '->returnType' => [
 			CallableTypeNode::class,
 			UnionTypeNode::class,
@@ -138,13 +147,12 @@ final class Printer
 			CallableTypeNode::class,
 			UnionTypeNode::class,
 			IntersectionTypeNode::class,
-			ConstTypeNode::class,
 			NullableTypeNode::class,
 		],
 	];
 
 	/** @var array>> */
-	private $parenthesesListMap = [
+	private array $parenthesesListMap = [
 		IntersectionTypeNode::class . '->types' => [
 			IntersectionTypeNode::class,
 			UnionTypeNode::class,
@@ -174,7 +182,7 @@ public function printFormatPreserving(PhpDocNode $node, PhpDocNode $originalNode
 			$originalTokens,
 			$tokenIndex,
 			PhpDocNode::class,
-			'children'
+			'children',
 		);
 		if ($result !== null) {
 			return $result . $originalTokens->getContentBetween($tokenIndex, $originalTokens->getTokenCount());
@@ -191,7 +199,7 @@ function (PhpDocChildNode $child): string {
 					$s = $this->print($child);
 					return $s === '' ? '' : ' ' . $s;
 				},
-				$node->children
+				$node->children,
 			)) . "\n */";
 		}
 		if ($node instanceof PhpDocTextNode) {
@@ -227,6 +235,12 @@ function (PhpDocChildNode $child): string {
 			$isOptional = $node->isOptional ? '=' : '';
 			return trim("{$type}{$isReference}{$isVariadic}{$node->parameterName}") . $isOptional;
 		}
+		if ($node instanceof ArrayShapeUnsealedTypeNode) {
+			if ($node->keyType !== null) {
+				return sprintf('<%s, %s>', $this->printType($node->keyType), $this->printType($node->valueType));
+			}
+			return sprintf('<%s>', $this->printType($node->valueType));
+		}
 		if ($node instanceof DoctrineAnnotation) {
 			return (string) $node;
 		}
@@ -239,6 +253,30 @@ function (PhpDocChildNode $child): string {
 		if ($node instanceof DoctrineArrayItem) {
 			return (string) $node;
 		}
+		if ($node instanceof ArrayShapeItemNode) {
+			if ($node->keyName !== null) {
+				return sprintf(
+					'%s%s: %s',
+					$this->print($node->keyName),
+					$node->optional ? '?' : '',
+					$this->printType($node->valueType),
+				);
+			}
+
+			return $this->printType($node->valueType);
+		}
+		if ($node instanceof ObjectShapeItemNode) {
+			if ($node->keyName !== null) {
+				return sprintf(
+					'%s%s: %s',
+					$this->print($node->keyName),
+					$node->optional ? '?' : '',
+					$this->printType($node->valueType),
+				);
+			}
+
+			return $this->printType($node->valueType);
+		}
 
 		throw new LogicException(sprintf('Unknown node type %s', get_class($node)));
 	}
@@ -273,13 +311,9 @@ private function printTagValue(PhpDocTagValueNode $node): string
 		if ($node instanceof MethodTagValueNode) {
 			$static = $node->isStatic ? 'static ' : '';
 			$returnType = $node->returnType !== null ? $this->printType($node->returnType) . ' ' : '';
-			$parameters = implode(', ', array_map(function (MethodTagValueParameterNode $parameter): string {
-				return $this->print($parameter);
-			}, $node->parameters));
+			$parameters = implode(', ', array_map(fn (MethodTagValueParameterNode $parameter): string => $this->print($parameter), $node->parameters));
 			$description = $node->description !== '' ? " {$node->description}" : '';
-			$templateTypes = count($node->templateTypes) > 0 ? '<' . implode(', ', array_map(function (TemplateTagValueNode $templateTag): string {
-				return $this->print($templateTag);
-			}, $node->templateTypes)) . '>' : '';
+			$templateTypes = count($node->templateTypes) > 0 ? '<' . implode(', ', array_map(fn (TemplateTagValueNode $templateTag): string => $this->print($templateTag), $node->templateTypes)) . '>' : '';
 			return "{$static}{$returnType}{$node->methodName}{$templateTypes}({$parameters}){$description}";
 		}
 		if ($node instanceof MixinTagValueNode) {
@@ -294,6 +328,10 @@ private function printTagValue(PhpDocTagValueNode $node): string
 			$type = $this->printType($node->type);
 			return trim("{$type} {$node->description}");
 		}
+		if ($node instanceof SealedTagValueNode) {
+			$type = $this->printType($node->type);
+			return trim("{$type} {$node->description}");
+		}
 		if ($node instanceof ParamOutTagValueNode) {
 			$type = $this->printType($node->type);
 			return trim("{$type} {$node->parameterName} {$node->description}");
@@ -304,6 +342,18 @@ private function printTagValue(PhpDocTagValueNode $node): string
 			$type = $this->printType($node->type);
 			return trim("{$type} {$reference}{$variadic}{$node->parameterName} {$node->description}");
 		}
+		if ($node instanceof ParamImmediatelyInvokedCallableTagValueNode) {
+			return trim("{$node->parameterName} {$node->description}");
+		}
+		if ($node instanceof ParamLaterInvokedCallableTagValueNode) {
+			return trim("{$node->parameterName} {$node->description}");
+		}
+		if ($node instanceof ParamClosureThisTagValueNode) {
+			return trim("{$node->type} {$node->parameterName} {$node->description}");
+		}
+		if ($node instanceof PureUnlessCallableIsImpureTagValueNode) {
+			return trim("{$node->parameterName} {$node->description}");
+		}
 		if ($node instanceof PropertyTagValueNode) {
 			$type = $this->printType($node->type);
 			return trim("{$type} {$node->propertyName} {$node->description}");
@@ -317,9 +367,10 @@ private function printTagValue(PhpDocTagValueNode $node): string
 			return trim($type . ' ' . $node->description);
 		}
 		if ($node instanceof TemplateTagValueNode) {
-			$bound = $node->bound !== null ? ' of ' . $this->printType($node->bound) : '';
+			$upperBound = $node->bound !== null ? ' of ' . $this->printType($node->bound) : '';
+			$lowerBound = $node->lowerBound !== null ? ' super ' . $this->printType($node->lowerBound) : '';
 			$default = $node->default !== null ? ' = ' . $this->printType($node->default) : '';
-			return trim("{$node->name}{$bound}{$default} {$node->description}");
+			return trim("{$node->name}{$upperBound}{$lowerBound}{$default} {$node->description}");
 		}
 		if ($node instanceof ThrowsTagValueNode) {
 			$type = $this->printType($node->type);
@@ -328,7 +379,7 @@ private function printTagValue(PhpDocTagValueNode $node): string
 		if ($node instanceof TypeAliasImportTagValueNode) {
 			return trim(
 				"{$node->importedAlias} from " . $this->printType($node->importedFrom)
-				. ($node->importedAs !== null ? " as {$node->importedAs}" : '')
+				. ($node->importedAs !== null ? " as {$node->importedAs}" : ''),
 			);
 		}
 		if ($node instanceof TypeAliasTagValueNode) {
@@ -350,28 +401,14 @@ private function printTagValue(PhpDocTagValueNode $node): string
 	private function printType(TypeNode $node): string
 	{
 		if ($node instanceof ArrayShapeNode) {
-			$items = array_map(function (ArrayShapeItemNode $item): string {
-				return $this->printType($item);
-			}, $node->items);
+			$items = array_map(fn (ArrayShapeItemNode $item): string => $this->print($item), $node->items);
 
 			if (! $node->sealed) {
-				$items[] = '...';
+				$items[] = '...' . ($node->unsealedType === null ? '' : $this->print($node->unsealedType));
 			}
 
 			return $node->kind . '{' . implode(', ', $items) . '}';
 		}
-		if ($node instanceof ArrayShapeItemNode) {
-			if ($node->keyName !== null) {
-				return sprintf(
-					'%s%s: %s',
-					$this->print($node->keyName),
-					$node->optional ? '?' : '',
-					$this->printType($node->valueType)
-				);
-			}
-
-			return $this->printType($node->valueType);
-		}
 		if ($node instanceof ArrayTypeNode) {
 			return $this->printOffsetAccessType($node->type) . '[]';
 		}
@@ -382,13 +419,9 @@ private function printType(TypeNode $node): string
 				$returnType = $this->printType($node->returnType);
 			}
 			$template = $node->templateTypes !== []
-				? '<' . implode(', ', array_map(function (TemplateTagValueNode $templateNode): string {
-					return $this->print($templateNode);
-				}, $node->templateTypes)) . '>'
+				? '<' . implode(', ', array_map(fn (TemplateTagValueNode $templateNode): string => $this->print($templateNode), $node->templateTypes)) . '>'
 				: '';
-			$parameters = implode(', ', array_map(function (CallableTypeParameterNode $parameterNode): string {
-				return $this->print($parameterNode);
-			}, $node->parameters));
+			$parameters = implode(', ', array_map(fn (CallableTypeParameterNode $parameterNode): string => $this->print($parameterNode), $node->parameters));
 			return "{$node->identifier}{$template}({$parameters}): {$returnType}";
 		}
 		if ($node instanceof ConditionalTypeForParameterNode) {
@@ -398,7 +431,7 @@ private function printType(TypeNode $node): string
 				$node->negated ? 'is not' : 'is',
 				$this->printType($node->targetType),
 				$this->printType($node->if),
-				$this->printType($node->else)
+				$this->printType($node->else),
 			);
 		}
 		if ($node instanceof ConditionalTypeNode) {
@@ -408,7 +441,7 @@ private function printType(TypeNode $node): string
 				$node->negated ? 'is not' : 'is',
 				$this->printType($node->targetType),
 				$this->printType($node->if),
-				$this->printType($node->else)
+				$this->printType($node->else),
 			);
 		}
 		if ($node instanceof ConstTypeNode) {
@@ -461,24 +494,10 @@ private function printType(TypeNode $node): string
 			return '?' . $this->printType($node->type);
 		}
 		if ($node instanceof ObjectShapeNode) {
-			$items = array_map(function (ObjectShapeItemNode $item): string {
-				return $this->printType($item);
-			}, $node->items);
+			$items = array_map(fn (ObjectShapeItemNode $item): string => $this->print($item), $node->items);
 
 			return 'object{' . implode(', ', $items) . '}';
 		}
-		if ($node instanceof ObjectShapeItemNode) {
-			if ($node->keyName !== null) {
-				return sprintf(
-					'%s%s: %s',
-					$this->print($node->keyName),
-					$node->optional ? '?' : '',
-					$this->printType($node->valueType)
-				);
-			}
-
-			return $this->printType($node->valueType);
-		}
 		if ($node instanceof OffsetAccessTypeNode) {
 			return $this->printOffsetAccessType($node->type) . '[' . $this->printType($node->offset) . ']';
 		}
@@ -500,7 +519,6 @@ private function printOffsetAccessType(TypeNode $type): string
 			$type instanceof CallableTypeNode
 			|| $type instanceof UnionTypeNode
 			|| $type instanceof IntersectionTypeNode
-			|| $type instanceof ConstTypeNode
 			|| $type instanceof NullableTypeNode
 		) {
 			return $this->wrapInParentheses($type);
@@ -537,19 +555,30 @@ private function printArrayFormatPreserving(array $nodes, array $originalNodes,
 
 		foreach ($diff as $i => $diffElem) {
 			$diffType = $diffElem->type;
-			$newNode = $diffElem->new;
-			$originalNode = $diffElem->old;
+			$arrItem = $diffElem->new;
+			$origArrayItem = $diffElem->old;
 			if ($diffType === DiffElem::TYPE_KEEP || $diffType === DiffElem::TYPE_REPLACE) {
 				$beforeFirstKeepOrReplace = false;
-				if (!$newNode instanceof Node || !$originalNode instanceof Node) {
+				if (!$arrItem instanceof Node || !$origArrayItem instanceof Node) {
 					return null;
 				}
-				$itemStartPos = $originalNode->getAttribute(Attribute::START_INDEX);
-				$itemEndPos = $originalNode->getAttribute(Attribute::END_INDEX);
+
+				/** @var int $itemStartPos */
+				$itemStartPos = $origArrayItem->getAttribute(Attribute::START_INDEX);
+
+				/** @var int $itemEndPos */
+				$itemEndPos = $origArrayItem->getAttribute(Attribute::END_INDEX);
+
 				if ($itemStartPos < 0 || $itemEndPos < 0 || $itemStartPos < $tokenIndex) {
 					throw new LogicException();
 				}
 
+				$comments = $arrItem->getAttribute(Attribute::COMMENTS) ?? [];
+				$origComments = $origArrayItem->getAttribute(Attribute::COMMENTS) ?? [];
+
+				$commentStartPos = count($origComments) > 0 ? $origComments[0]->startIndex : $itemStartPos;
+				assert($commentStartPos >= 0);
+
 				$result .= $originalTokens->getContentBetween($tokenIndex, $itemStartPos);
 
 				if (count($delayedAdd) > 0) {
@@ -559,6 +588,15 @@ private function printArrayFormatPreserving(array $nodes, array $originalNodes,
 						if ($parenthesesNeeded) {
 							$result .= '(';
 						}
+
+						if ($insertNewline) {
+							$delayedAddComments = $delayedAddNode->getAttribute(Attribute::COMMENTS) ?? [];
+							if (count($delayedAddComments) > 0) {
+								$result .= $this->printComments($delayedAddComments, $beforeAsteriskIndent, $afterAsteriskIndent);
+								$result .= sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent);
+							}
+						}
+
 						$result .= $this->printNodeFormatPreserving($delayedAddNode, $originalTokens);
 						if ($parenthesesNeeded) {
 							$result .= ')';
@@ -575,14 +613,21 @@ private function printArrayFormatPreserving(array $nodes, array $originalNodes,
 				}
 
 				$parenthesesNeeded = isset($this->parenthesesListMap[$mapKey])
-					&& in_array(get_class($newNode), $this->parenthesesListMap[$mapKey], true)
-					&& !in_array(get_class($originalNode), $this->parenthesesListMap[$mapKey], true);
+					&& in_array(get_class($arrItem), $this->parenthesesListMap[$mapKey], true)
+					&& !in_array(get_class($origArrayItem), $this->parenthesesListMap[$mapKey], true);
 				$addParentheses = $parenthesesNeeded && !$originalTokens->hasParentheses($itemStartPos, $itemEndPos);
 				if ($addParentheses) {
 					$result .= '(';
 				}
 
-				$result .= $this->printNodeFormatPreserving($newNode, $originalTokens);
+				if ($comments !== $origComments) {
+					if (count($comments) > 0) {
+						$result .= $this->printComments($comments, $beforeAsteriskIndent, $afterAsteriskIndent);
+						$result .= sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent);
+					}
+				}
+
+				$result .= $this->printNodeFormatPreserving($arrItem, $originalTokens);
 				if ($addParentheses) {
 					$result .= ')';
 				}
@@ -592,35 +637,42 @@ private function printArrayFormatPreserving(array $nodes, array $originalNodes,
 				if ($insertStr === null) {
 					return null;
 				}
-				if (!$newNode instanceof Node) {
+				if (!$arrItem instanceof Node) {
 					return null;
 				}
 
-				if ($insertStr === ', ' && $isMultiline) {
+				if ($insertStr === ', ' && $isMultiline || count($arrItem->getAttribute(Attribute::COMMENTS) ?? []) > 0) {
 					$insertStr = ',';
 					$insertNewline = true;
 				}
 
 				if ($beforeFirstKeepOrReplace) {
 					// Will be inserted at the next "replace" or "keep" element
-					$delayedAdd[] = $newNode;
+					$delayedAdd[] = $arrItem;
 					continue;
 				}
 
+				/** @var int $itemEndPos */
 				$itemEndPos = $tokenIndex - 1;
 				if ($insertNewline) {
-					$result .= $insertStr . sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent);
+					$comments = $arrItem->getAttribute(Attribute::COMMENTS) ?? [];
+					$result .= $insertStr;
+					if (count($comments) > 0) {
+						$result .= sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent);
+						$result .= $this->printComments($comments, $beforeAsteriskIndent, $afterAsteriskIndent);
+					}
+					$result .= sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? "\n", $beforeAsteriskIndent, $afterAsteriskIndent);
 				} else {
 					$result .= $insertStr;
 				}
 
 				$parenthesesNeeded = isset($this->parenthesesListMap[$mapKey])
-					&& in_array(get_class($newNode), $this->parenthesesListMap[$mapKey], true);
+					&& in_array(get_class($arrItem), $this->parenthesesListMap[$mapKey], true);
 				if ($parenthesesNeeded) {
 					$result .= '(';
 				}
 
-				$result .= $this->printNodeFormatPreserving($newNode, $originalTokens);
+				$result .= $this->printNodeFormatPreserving($arrItem, $originalTokens);
 				if ($parenthesesNeeded) {
 					$result .= ')';
 				}
@@ -628,12 +680,15 @@ private function printArrayFormatPreserving(array $nodes, array $originalNodes,
 				$tokenIndex = $itemEndPos + 1;
 
 			} elseif ($diffType === DiffElem::TYPE_REMOVE) {
-				if (!$originalNode instanceof Node) {
+				if (!$origArrayItem instanceof Node) {
 					return null;
 				}
 
-				$itemStartPos = $originalNode->getAttribute(Attribute::START_INDEX);
-				$itemEndPos = $originalNode->getAttribute(Attribute::END_INDEX);
+				/** @var int $itemStartPos */
+				$itemStartPos = $origArrayItem->getAttribute(Attribute::START_INDEX);
+
+				/** @var int $itemEndPos */
+				$itemEndPos = $origArrayItem->getAttribute(Attribute::END_INDEX);
 				if ($itemStartPos < 0 || $itemEndPos < 0) {
 					throw new LogicException();
 				}
@@ -692,7 +747,21 @@ private function printArrayFormatPreserving(array $nodes, array $originalNodes,
 	}
 
 	/**
-	 * @param Node[] $nodes
+	 * @param list $comments
+	 */
+	private function printComments(array $comments, string $beforeAsteriskIndent, string $afterAsteriskIndent): string
+	{
+		$formattedComments = [];
+
+		foreach ($comments as $comment) {
+			$formattedComments[] = str_replace("\n", "\n" . $beforeAsteriskIndent . '*' . $afterAsteriskIndent, $comment->getReformattedText());
+		}
+
+		return implode("\n$beforeAsteriskIndent*$afterAsteriskIndent", $formattedComments);
+	}
+
+	/**
+	 * @param array $nodes
 	 * @return array{bool, string, string}
 	 */
 	private function isMultiline(int $initialIndex, array $nodes, TokenIterator $originalTokens): array
@@ -720,7 +789,7 @@ private function isMultiline(int $initialIndex, array $nodes, TokenIterator $ori
 
 		$c = preg_match_all('~\n(?[\\x09\\x20]*)\*(?\\x20*)~', $allText, $matches, PREG_SET_ORDER);
 		if ($c === 0) {
-			return [$isMultiline, '', ''];
+			return [$isMultiline, ' ', '  '];
 		}
 
 		$before = '';
@@ -736,6 +805,9 @@ private function isMultiline(int $initialIndex, array $nodes, TokenIterator $ori
 			$after = $match['after'];
 		}
 
+		$before = strlen($before) === 0 ? ' ' : $before;
+		$after = strlen($after) === 0 ? '  ' : $after;
+
 		return [$isMultiline, $before, $after];
 	}
 
@@ -782,7 +854,7 @@ private function printNodeFormatPreserving(Node $node, TokenIterator $originalTo
 						$originalTokens,
 						$pos,
 						$class,
-						$subNodeName
+						$subNodeName,
 					);
 
 					if ($listResult === null) {
diff --git a/app/vendor/phpunit/php-code-coverage/ChangeLog-9.2.md b/app/vendor/phpunit/php-code-coverage/ChangeLog-9.2.md
index 9ef6be338..5176ae333 100644
--- a/app/vendor/phpunit/php-code-coverage/ChangeLog-9.2.md
+++ b/app/vendor/phpunit/php-code-coverage/ChangeLog-9.2.md
@@ -2,6 +2,12 @@
 
 All notable changes are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles.
 
+## [9.2.32] - 2024-08-22
+
+### Changed
+
+* Updated dependencies (so that users that install using Composer's `--prefer-lowest` CLI option also get recent versions)
+
 ## [9.2.31] - 2024-03-02
 
 ### Changed
@@ -511,6 +517,7 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt
 
 * This component is no longer supported on PHP 7.1
 
+[9.2.32]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.31...9.2.32
 [9.2.31]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.30...9.2.31
 [9.2.30]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.29...9.2.30
 [9.2.29]: https://github.com/sebastianbergmann/php-code-coverage/compare/9.2.28...9.2.29
diff --git a/app/vendor/phpunit/php-code-coverage/build/scripts/extract-release-notes.php b/app/vendor/phpunit/php-code-coverage/build/scripts/extract-release-notes.php
new file mode 100644
index 000000000..390143980
--- /dev/null
+++ b/app/vendor/phpunit/php-code-coverage/build/scripts/extract-release-notes.php
@@ -0,0 +1,47 @@
+#!/usr/bin/env php
+' . PHP_EOL;
+
+    exit(1);
+}
+
+$version       = $argv[1];
+$versionSeries = explode('.', $version)[0] . '.' . explode('.', $version)[1];
+
+$file = __DIR__ . '/../../ChangeLog-' . $versionSeries . '.md';
+
+if (!is_file($file) || !is_readable($file)) {
+    print $file . ' cannot be read' . PHP_EOL;
+
+    exit(1);
+}
+
+$buffer = '';
+$append = false;
+
+foreach (file($file) as $line) {
+    if (str_starts_with($line, '## [' . $version . ']')) {
+        $append = true;
+
+        continue;
+    }
+
+    if ($append && (str_starts_with($line, '## ') || str_starts_with($line, '['))) {
+        break;
+    }
+
+    if ($append) {
+        $buffer .= $line;
+    }
+}
+
+$buffer = trim($buffer);
+
+if ($buffer === '') {
+    print 'Unable to extract release notes' . PHP_EOL;
+
+    exit(1);
+}
+
+print $buffer . PHP_EOL;
diff --git a/app/vendor/phpunit/php-code-coverage/composer.json b/app/vendor/phpunit/php-code-coverage/composer.json
index 3646210fe..f9fd3613e 100644
--- a/app/vendor/phpunit/php-code-coverage/composer.json
+++ b/app/vendor/phpunit/php-code-coverage/composer.json
@@ -33,18 +33,18 @@
         "ext-dom": "*",
         "ext-libxml": "*",
         "ext-xmlwriter": "*",
-        "nikic/php-parser": "^4.18 || ^5.0",
-        "phpunit/php-file-iterator": "^3.0.3",
-        "phpunit/php-text-template": "^2.0.2",
-        "sebastian/code-unit-reverse-lookup": "^2.0.2",
-        "sebastian/complexity": "^2.0",
-        "sebastian/environment": "^5.1.2",
-        "sebastian/lines-of-code": "^1.0.3",
-        "sebastian/version": "^3.0.1",
-        "theseer/tokenizer": "^1.2.0"
+        "nikic/php-parser": "^4.19.1 || ^5.1.0",
+        "phpunit/php-file-iterator": "^3.0.6",
+        "phpunit/php-text-template": "^2.0.4",
+        "sebastian/code-unit-reverse-lookup": "^2.0.3",
+        "sebastian/complexity": "^2.0.3",
+        "sebastian/environment": "^5.1.5",
+        "sebastian/lines-of-code": "^1.0.4",
+        "sebastian/version": "^3.0.2",
+        "theseer/tokenizer": "^1.2.3"
     },
     "require-dev": {
-        "phpunit/phpunit": "^9.3"
+        "phpunit/phpunit": "^9.6"
     },
     "suggest": {
         "ext-pcov": "PHP extension that provides line coverage",
@@ -63,7 +63,7 @@
     },
     "extra": {
         "branch-alias": {
-            "dev-master": "9.2-dev"
+            "dev-main": "9.2.x-dev"
         }
     }
 }
diff --git a/app/vendor/phpunit/php-code-coverage/src/Exception/Xdebug2NotEnabledException.php b/app/vendor/phpunit/php-code-coverage/src/Exception/Xdebug2NotEnabledException.php
index 3039e77c0..4ee232d0f 100644
--- a/app/vendor/phpunit/php-code-coverage/src/Exception/Xdebug2NotEnabledException.php
+++ b/app/vendor/phpunit/php-code-coverage/src/Exception/Xdebug2NotEnabledException.php
@@ -16,6 +16,6 @@ final class Xdebug2NotEnabledException extends RuntimeException implements Excep
 {
     public function __construct()
     {
-        parent::__construct('xdebug.coverage_enable=On has to be set');
+        parent::__construct('xdebug.coverage_enable=On (PHP configuration setting) has to be set');
     }
 }
diff --git a/app/vendor/phpunit/php-code-coverage/src/Exception/Xdebug3NotEnabledException.php b/app/vendor/phpunit/php-code-coverage/src/Exception/Xdebug3NotEnabledException.php
index 5d3b106ce..6abc01f38 100644
--- a/app/vendor/phpunit/php-code-coverage/src/Exception/Xdebug3NotEnabledException.php
+++ b/app/vendor/phpunit/php-code-coverage/src/Exception/Xdebug3NotEnabledException.php
@@ -16,6 +16,6 @@ final class Xdebug3NotEnabledException extends RuntimeException implements Excep
 {
     public function __construct()
     {
-        parent::__construct('XDEBUG_MODE=coverage or xdebug.mode=coverage has to be set');
+        parent::__construct('XDEBUG_MODE=coverage (environment variable) or xdebug.mode=coverage (PHP configuration setting) has to be set');
     }
 }
diff --git a/app/vendor/phpunit/php-code-coverage/src/Version.php b/app/vendor/phpunit/php-code-coverage/src/Version.php
index 1753a97b2..93cf32d94 100644
--- a/app/vendor/phpunit/php-code-coverage/src/Version.php
+++ b/app/vendor/phpunit/php-code-coverage/src/Version.php
@@ -22,7 +22,7 @@ final class Version
     public static function id(): string
     {
         if (self::$version === null) {
-            self::$version = (new VersionId('9.2.31', dirname(__DIR__)))->getVersion();
+            self::$version = (new VersionId('9.2.32', dirname(__DIR__)))->getVersion();
         }
 
         return self::$version;
diff --git a/app/vendor/phpunit/phpunit/.phpstorm.meta.php b/app/vendor/phpunit/phpunit/.phpstorm.meta.php
deleted file mode 100644
index b69ff7890..000000000
--- a/app/vendor/phpunit/phpunit/.phpstorm.meta.php
+++ /dev/null
@@ -1,33 +0,0 @@
-"$0"])
-    );
-
-    override(
-        \PHPUnit\Framework\TestCase::createStub(0),
-        map([""=>"$0"])
-    );
-
-    override(
-        \PHPUnit\Framework\TestCase::createConfiguredMock(0),
-        map([""=>"$0"])
-    );
-
-    override(
-        \PHPUnit\Framework\TestCase::createPartialMock(0),
-        map([""=>"$0"])
-    );
-
-    override(
-        \PHPUnit\Framework\TestCase::createTestProxy(0),
-        map([""=>"$0"])
-    );
-
-    override(
-        \PHPUnit\Framework\TestCase::getMockForAbstractClass(0),
-        map([""=>"$0"])
-    );
-}
diff --git a/app/vendor/phpunit/phpunit/ChangeLog-9.6.md b/app/vendor/phpunit/phpunit/ChangeLog-9.6.md
index 9689bfbbc..c42084404 100644
--- a/app/vendor/phpunit/phpunit/ChangeLog-9.6.md
+++ b/app/vendor/phpunit/phpunit/ChangeLog-9.6.md
@@ -2,14 +2,62 @@
 
 All notable changes of the PHPUnit 9.6 release series are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles.
 
+## [9.6.23] - 2025-05-02
+
+### Changed
+
+* [#5956](https://github.com/sebastianbergmann/phpunit/issues/5956): Improved handling of deprecated `E_STRICT` constant
+* Improved message when test is considered risky for printing unexpected output
+
+## [9.6.22] - 2024-12-05
+
+### Fixed
+
+* [#6071](https://github.com/sebastianbergmann/phpunit/issues/6071): PHP Archives (PHARs) of PHPUnit 8.5 and PHPUnit 9.6 bundle outdated versions of Prophecy
+
+## [9.6.21] - 2024-09-19
+
+### Changed
+
+* [#5956](https://github.com/sebastianbergmann/phpunit/issues/5956): Deprecation of the `E_STRICT` constant in PHP 8.4
+* Removed `.phpstorm.meta.php` file as methods such as `TestCase::createStub()` use generics / template types for their return types and PhpStorm, for example, uses that information
+
+## [9.6.20] - 2024-07-10
+
+### Changed
+
+* Updated dependencies (so that users that install using Composer's `--prefer-lowest` CLI option also get recent versions)
+
+## [9.6.19] - 2024-04-05
+
+### Changed
+
+* The namespaces of dependencies are now prefixed with `PHPUnitPHAR` instead of just `PHPUnit` for the PHAR distribution of PHPUnit
+
+## [9.6.18] - 2024-03-21
+
+### Changed
+
+* [#5763](https://github.com/sebastianbergmann/phpunit/issues/5763): Release nullable type changes for PHPUnit 9.6
+
 ## [9.6.17] - 2024-02-23
 
+### Changed
+
+* Improve output of `--check-version` CLI option
+* Improve description of `--check-version` CLI option
+* Show help for `--manifest`, `--sbom`, and `--composer-lock` when the PHAR is used
+
 ### Fixed
 
 * [#5712](https://github.com/sebastianbergmann/phpunit/issues/5712): Update dependencies for PHAR distribution of PHPUnit 9.6
 
 ## [9.6.16] - 2024-01-19
 
+### Changed
+
+* Make PHAR build reproducible (the only remaining differences were in the timestamps for the files in the PHAR)
+
 ### Fixed
 
 * [#5516](https://github.com/sebastianbergmann/phpunit/issues/5516): Assertions that use the `LogicalNot` constraint (`assertNotEquals()`, `assertStringNotContainsString()`, ...) can generate confusing failure messages
@@ -121,6 +169,12 @@ All notable changes of the PHPUnit 9.6 release series are documented in this fil
 * [#5064](https://github.com/sebastianbergmann/phpunit/issues/5064): Deprecate `PHPUnit\Framework\TestCase::getMockClass()`
 * [#5132](https://github.com/sebastianbergmann/phpunit/issues/5132): Deprecate `Test` suffix for abstract test case classes
 
+[9.6.23]: https://github.com/sebastianbergmann/phpunit/compare/9.6.22...9.6.23
+[9.6.22]: https://github.com/sebastianbergmann/phpunit/compare/9.6.21...9.6.22
+[9.6.21]: https://github.com/sebastianbergmann/phpunit/compare/9.6.20...9.6.21
+[9.6.20]: https://github.com/sebastianbergmann/phpunit/compare/9.6.19...9.6.20
+[9.6.19]: https://github.com/sebastianbergmann/phpunit/compare/9.6.18...9.6.19
+[9.6.18]: https://github.com/sebastianbergmann/phpunit/compare/9.6.17...9.6.18
 [9.6.17]: https://github.com/sebastianbergmann/phpunit/compare/9.6.16...9.6.17
 [9.6.16]: https://github.com/sebastianbergmann/phpunit/compare/9.6.15...9.6.16
 [9.6.15]: https://github.com/sebastianbergmann/phpunit/compare/9.6.14...9.6.15
diff --git a/app/vendor/phpunit/phpunit/LICENSE b/app/vendor/phpunit/phpunit/LICENSE
index bdb57ec66..b687f39ac 100644
--- a/app/vendor/phpunit/phpunit/LICENSE
+++ b/app/vendor/phpunit/phpunit/LICENSE
@@ -1,6 +1,6 @@
 BSD 3-Clause License
 
-Copyright (c) 2001-2024, Sebastian Bergmann
+Copyright (c) 2001-2025, Sebastian Bergmann
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
diff --git a/app/vendor/phpunit/phpunit/README.md b/app/vendor/phpunit/phpunit/README.md
index 9fae13df6..8aff03453 100644
--- a/app/vendor/phpunit/phpunit/README.md
+++ b/app/vendor/phpunit/phpunit/README.md
@@ -1,8 +1,7 @@
 # PHPUnit
 
-[![Latest Stable Version](https://poser.pugx.org/phpunit/phpunit/v/stable.png)](https://packagist.org/packages/phpunit/phpunit)
+[![Latest Stable Version](https://poser.pugx.org/phpunit/phpunit/v)](https://packagist.org/packages/phpunit/phpunit)
 [![CI Status](https://github.com/sebastianbergmann/phpunit/workflows/CI/badge.svg)](https://github.com/sebastianbergmann/phpunit/actions)
-[![Type Coverage](https://shepherd.dev/github/sebastianbergmann/phpunit/coverage.svg)](https://shepherd.dev/github/sebastianbergmann/phpunit)
 [![codecov](https://codecov.io/gh/sebastianbergmann/phpunit/branch/9.6/graph/badge.svg)](https://codecov.io/gh/sebastianbergmann/phpunit)
 
 PHPUnit is a programmer-oriented testing framework for PHP. It is an instance of the xUnit architecture for unit testing frameworks.
@@ -19,7 +18,7 @@ $ php phpunit-X.Y.phar --version
 
 Please replace `X.Y` with the version of PHPUnit you are interested in.
 
-Alternatively, you may use [Composer](https://getcomposer.org/) to download and install PHPUnit as well as its dependencies. Please refer to the "[Getting Started](https://phpunit.de/getting-started-with-phpunit.html)" guide for details on how to install PHPUnit.
+Alternatively, you may use [Composer](https://getcomposer.org/) to download and install PHPUnit as well as its dependencies. Please refer to the [documentation](https://phpunit.de/documentation.html) for details on how to install PHPUnit.
 
 ## Contribute
 
diff --git a/app/vendor/phpunit/phpunit/composer.json b/app/vendor/phpunit/phpunit/composer.json
index 42e16c6f3..ef995c906 100644
--- a/app/vendor/phpunit/phpunit/composer.json
+++ b/app/vendor/phpunit/phpunit/composer.json
@@ -29,31 +29,32 @@
         "ext-mbstring": "*",
         "ext-xml": "*",
         "ext-xmlwriter": "*",
-        "doctrine/instantiator": "^1.3.1 || ^2",
-        "myclabs/deep-copy": "^1.10.1",
-        "phar-io/manifest": "^2.0.3",
-        "phar-io/version": "^3.0.2",
-        "phpunit/php-code-coverage": "^9.2.28",
-        "phpunit/php-file-iterator": "^3.0.5",
+        "doctrine/instantiator": "^1.5.0 || ^2",
+        "myclabs/deep-copy": "^1.13.1",
+        "phar-io/manifest": "^2.0.4",
+        "phar-io/version": "^3.2.1",
+        "phpunit/php-code-coverage": "^9.2.32",
+        "phpunit/php-file-iterator": "^3.0.6",
         "phpunit/php-invoker": "^3.1.1",
-        "phpunit/php-text-template": "^2.0.3",
-        "phpunit/php-timer": "^5.0.2",
-        "sebastian/cli-parser": "^1.0.1",
-        "sebastian/code-unit": "^1.0.6",
+        "phpunit/php-text-template": "^2.0.4",
+        "phpunit/php-timer": "^5.0.3",
+        "sebastian/cli-parser": "^1.0.2",
+        "sebastian/code-unit": "^1.0.8",
         "sebastian/comparator": "^4.0.8",
-        "sebastian/diff": "^4.0.3",
-        "sebastian/environment": "^5.1.3",
-        "sebastian/exporter": "^4.0.5",
-        "sebastian/global-state": "^5.0.1",
-        "sebastian/object-enumerator": "^4.0.3",
-        "sebastian/resource-operations": "^3.0.3",
-        "sebastian/type": "^3.2",
+        "sebastian/diff": "^4.0.6",
+        "sebastian/environment": "^5.1.5",
+        "sebastian/exporter": "^4.0.6",
+        "sebastian/global-state": "^5.0.7",
+        "sebastian/object-enumerator": "^4.0.4",
+        "sebastian/resource-operations": "^3.0.4",
+        "sebastian/type": "^3.2.1",
         "sebastian/version": "^3.0.2"
     },
     "config": {
         "platform": {
             "php": "7.3.0"
         },
+        "classmap-authoritative": true,
         "optimize-autoloader": true,
         "sort-packages": true
     },
diff --git a/app/vendor/phpunit/phpunit/composer.lock b/app/vendor/phpunit/phpunit/composer.lock
index 6965da455..be0c8c824 100644
--- a/app/vendor/phpunit/phpunit/composer.lock
+++ b/app/vendor/phpunit/phpunit/composer.lock
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "a33593542389289bb642826edd1be24d",
+    "content-hash": "4f546599de962e2d0c22325fa943c784",
     "packages": [
         {
             "name": "doctrine/instantiator",
@@ -78,16 +78,16 @@
         },
         {
             "name": "myclabs/deep-copy",
-            "version": "1.11.1",
+            "version": "1.13.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/myclabs/DeepCopy.git",
-                "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c"
+                "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
-                "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c",
+                "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/1720ddd719e16cf0db4eb1c6eca108031636d46c",
+                "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c",
                 "shasum": ""
             },
             "require": {
@@ -95,11 +95,12 @@
             },
             "conflict": {
                 "doctrine/collections": "<1.6.8",
-                "doctrine/common": "<2.13.3 || >=3,<3.2.2"
+                "doctrine/common": "<2.13.3 || >=3 <3.2.2"
             },
             "require-dev": {
                 "doctrine/collections": "^1.6.8",
                 "doctrine/common": "^2.13.3 || ^3.2.2",
+                "phpspec/prophecy": "^1.10",
                 "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
             },
             "type": "library",
@@ -125,7 +126,7 @@
             ],
             "support": {
                 "issues": "https://github.com/myclabs/DeepCopy/issues",
-                "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1"
+                "source": "https://github.com/myclabs/DeepCopy/tree/1.13.1"
             },
             "funding": [
                 {
@@ -133,29 +134,29 @@
                     "type": "tidelift"
                 }
             ],
-            "time": "2023-03-08T13:26:56+00:00"
+            "time": "2025-04-29T12:36:36+00:00"
         },
         {
             "name": "nikic/php-parser",
-            "version": "v4.18.0",
+            "version": "v4.19.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/nikic/PHP-Parser.git",
-                "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999"
+                "reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999",
-                "reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999",
+                "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/715f4d25e225bc47b293a8b997fe6ce99bf987d2",
+                "reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2",
                 "shasum": ""
             },
             "require": {
                 "ext-tokenizer": "*",
-                "php": ">=7.0"
+                "php": ">=7.1"
             },
             "require-dev": {
                 "ircmaxell/php-yacc": "^0.0.7",
-                "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0"
+                "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
             },
             "bin": [
                 "bin/php-parse"
@@ -187,26 +188,27 @@
             ],
             "support": {
                 "issues": "https://github.com/nikic/PHP-Parser/issues",
-                "source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0"
+                "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.4"
             },
-            "time": "2023-12-10T21:03:43+00:00"
+            "time": "2024-09-29T15:01:53+00:00"
         },
         {
             "name": "phar-io/manifest",
-            "version": "2.0.3",
+            "version": "2.0.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phar-io/manifest.git",
-                "reference": "97803eca37d319dfa7826cc2437fc020857acb53"
+                "reference": "54750ef60c58e43759730615a392c31c80e23176"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53",
-                "reference": "97803eca37d319dfa7826cc2437fc020857acb53",
+                "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176",
+                "reference": "54750ef60c58e43759730615a392c31c80e23176",
                 "shasum": ""
             },
             "require": {
                 "ext-dom": "*",
+                "ext-libxml": "*",
                 "ext-phar": "*",
                 "ext-xmlwriter": "*",
                 "phar-io/version": "^3.0.1",
@@ -247,9 +249,15 @@
             "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
             "support": {
                 "issues": "https://github.com/phar-io/manifest/issues",
-                "source": "https://github.com/phar-io/manifest/tree/2.0.3"
+                "source": "https://github.com/phar-io/manifest/tree/2.0.4"
             },
-            "time": "2021-07-20T11:28:43+00:00"
+            "funding": [
+                {
+                    "url": "https://github.com/theseer",
+                    "type": "github"
+                }
+            ],
+            "time": "2024-03-03T12:33:53+00:00"
         },
         {
             "name": "phar-io/version",
@@ -304,35 +312,35 @@
         },
         {
             "name": "phpunit/php-code-coverage",
-            "version": "9.2.30",
+            "version": "9.2.32",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/php-code-coverage.git",
-                "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089"
+                "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca2bd87d2f9215904682a9cb9bb37dda98e76089",
-                "reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089",
+                "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5",
+                "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5",
                 "shasum": ""
             },
             "require": {
                 "ext-dom": "*",
                 "ext-libxml": "*",
                 "ext-xmlwriter": "*",
-                "nikic/php-parser": "^4.18 || ^5.0",
+                "nikic/php-parser": "^4.19.1 || ^5.1.0",
                 "php": ">=7.3",
-                "phpunit/php-file-iterator": "^3.0.3",
-                "phpunit/php-text-template": "^2.0.2",
-                "sebastian/code-unit-reverse-lookup": "^2.0.2",
-                "sebastian/complexity": "^2.0",
-                "sebastian/environment": "^5.1.2",
-                "sebastian/lines-of-code": "^1.0.3",
-                "sebastian/version": "^3.0.1",
-                "theseer/tokenizer": "^1.2.0"
+                "phpunit/php-file-iterator": "^3.0.6",
+                "phpunit/php-text-template": "^2.0.4",
+                "sebastian/code-unit-reverse-lookup": "^2.0.3",
+                "sebastian/complexity": "^2.0.3",
+                "sebastian/environment": "^5.1.5",
+                "sebastian/lines-of-code": "^1.0.4",
+                "sebastian/version": "^3.0.2",
+                "theseer/tokenizer": "^1.2.3"
             },
             "require-dev": {
-                "phpunit/phpunit": "^9.3"
+                "phpunit/phpunit": "^9.6"
             },
             "suggest": {
                 "ext-pcov": "PHP extension that provides line coverage",
@@ -341,7 +349,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "9.2-dev"
+                    "dev-main": "9.2.x-dev"
                 }
             },
             "autoload": {
@@ -370,7 +378,7 @@
             "support": {
                 "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
                 "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
-                "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.30"
+                "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.32"
             },
             "funding": [
                 {
@@ -378,7 +386,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2023-12-22T06:47:57+00:00"
+            "time": "2024-08-22T04:23:01+00:00"
         },
         {
             "name": "phpunit/php-file-iterator",
@@ -623,16 +631,16 @@
         },
         {
             "name": "sebastian/cli-parser",
-            "version": "1.0.1",
+            "version": "1.0.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/cli-parser.git",
-                "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2"
+                "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2",
-                "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2",
+                "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b",
+                "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b",
                 "shasum": ""
             },
             "require": {
@@ -667,7 +675,7 @@
             "homepage": "https://github.com/sebastianbergmann/cli-parser",
             "support": {
                 "issues": "https://github.com/sebastianbergmann/cli-parser/issues",
-                "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1"
+                "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2"
             },
             "funding": [
                 {
@@ -675,7 +683,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2020-09-28T06:08:49+00:00"
+            "time": "2024-03-02T06:27:43+00:00"
         },
         {
             "name": "sebastian/code-unit",
@@ -921,16 +929,16 @@
         },
         {
             "name": "sebastian/diff",
-            "version": "4.0.5",
+            "version": "4.0.6",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/diff.git",
-                "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131"
+                "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
-                "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131",
+                "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc",
+                "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc",
                 "shasum": ""
             },
             "require": {
@@ -975,7 +983,7 @@
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/diff/issues",
-                "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5"
+                "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6"
             },
             "funding": [
                 {
@@ -983,7 +991,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2023-05-07T05:35:17+00:00"
+            "time": "2024-03-02T06:30:58+00:00"
         },
         {
             "name": "sebastian/environment",
@@ -1050,16 +1058,16 @@
         },
         {
             "name": "sebastian/exporter",
-            "version": "4.0.5",
+            "version": "4.0.6",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/exporter.git",
-                "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d"
+                "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d",
-                "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d",
+                "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72",
+                "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72",
                 "shasum": ""
             },
             "require": {
@@ -1115,7 +1123,7 @@
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/exporter/issues",
-                "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5"
+                "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6"
             },
             "funding": [
                 {
@@ -1123,20 +1131,20 @@
                     "type": "github"
                 }
             ],
-            "time": "2022-09-14T06:03:37+00:00"
+            "time": "2024-03-02T06:33:00+00:00"
         },
         {
             "name": "sebastian/global-state",
-            "version": "5.0.6",
+            "version": "5.0.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/global-state.git",
-                "reference": "bde739e7565280bda77be70044ac1047bc007e34"
+                "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34",
-                "reference": "bde739e7565280bda77be70044ac1047bc007e34",
+                "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
+                "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
                 "shasum": ""
             },
             "require": {
@@ -1179,7 +1187,7 @@
             ],
             "support": {
                 "issues": "https://github.com/sebastianbergmann/global-state/issues",
-                "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6"
+                "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7"
             },
             "funding": [
                 {
@@ -1187,7 +1195,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2023-08-02T09:26:13+00:00"
+            "time": "2024-03-02T06:35:11+00:00"
         },
         {
             "name": "sebastian/lines-of-code",
@@ -1423,16 +1431,16 @@
         },
         {
             "name": "sebastian/resource-operations",
-            "version": "3.0.3",
+            "version": "3.0.4",
             "source": {
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/resource-operations.git",
-                "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8"
+                "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8",
-                "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8",
+                "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e",
+                "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e",
                 "shasum": ""
             },
             "require": {
@@ -1444,7 +1452,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.0-dev"
+                    "dev-main": "3.0-dev"
                 }
             },
             "autoload": {
@@ -1465,8 +1473,7 @@
             "description": "Provides a list of PHP built-in functions that operate on resources",
             "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
             "support": {
-                "issues": "https://github.com/sebastianbergmann/resource-operations/issues",
-                "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3"
+                "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4"
             },
             "funding": [
                 {
@@ -1474,7 +1481,7 @@
                     "type": "github"
                 }
             ],
-            "time": "2020-09-28T06:45:17+00:00"
+            "time": "2024-03-14T16:00:52+00:00"
         },
         {
             "name": "sebastian/type",
@@ -1587,16 +1594,16 @@
         },
         {
             "name": "theseer/tokenizer",
-            "version": "1.2.2",
+            "version": "1.2.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/theseer/tokenizer.git",
-                "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96"
+                "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
-                "reference": "b2ad5003ca10d4ee50a12da31de12a5774ba6b96",
+                "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
+                "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
                 "shasum": ""
             },
             "require": {
@@ -1625,7 +1632,7 @@
             "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
             "support": {
                 "issues": "https://github.com/theseer/tokenizer/issues",
-                "source": "https://github.com/theseer/tokenizer/tree/1.2.2"
+                "source": "https://github.com/theseer/tokenizer/tree/1.2.3"
             },
             "funding": [
                 {
@@ -1633,13 +1640,13 @@
                     "type": "github"
                 }
             ],
-            "time": "2023-11-20T00:12:19+00:00"
+            "time": "2024-03-03T12:36:25+00:00"
         }
     ],
     "packages-dev": [],
     "aliases": [],
     "minimum-stability": "stable",
-    "stability-flags": [],
+    "stability-flags": {},
     "prefer-stable": true,
     "prefer-lowest": false,
     "platform": {
@@ -1651,7 +1658,7 @@
         "ext-xml": "*",
         "ext-xmlwriter": "*"
     },
-    "platform-dev": [],
+    "platform-dev": {},
     "platform-overrides": {
         "php": "7.3.0"
     },
diff --git a/app/vendor/phpunit/phpunit/src/Framework/Assert/Functions.php b/app/vendor/phpunit/phpunit/src/Framework/Assert/Functions.php
index 2005cfdeb..5b6cc850c 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/Assert/Functions.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/Assert/Functions.php
@@ -70,6 +70,7 @@
 use PHPUnit\Framework\MockObject\Stub\ReturnSelf as ReturnSelfStub;
 use PHPUnit\Framework\MockObject\Stub\ReturnStub;
 use PHPUnit\Framework\MockObject\Stub\ReturnValueMap as ReturnValueMapStub;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 use Throwable;
 
 if (!function_exists('PHPUnit\Framework\assertArrayHasKey')) {
@@ -80,7 +81,7 @@
      * @param array|ArrayAccess $array
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws Exception
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -101,7 +102,7 @@ function assertArrayHasKey($key, $array, string $message = ''): void
      * @param array|ArrayAccess $array
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws Exception
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -119,7 +120,7 @@ function assertArrayNotHasKey($key, $array, string $message = ''): void
      * Asserts that a haystack contains a needle.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws Exception
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -144,7 +145,7 @@ function assertContainsEquals($needle, iterable $haystack, string $message = '')
      * Asserts that a haystack does not contain a needle.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws Exception
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -169,7 +170,7 @@ function assertNotContainsEquals($needle, iterable $haystack, string $message =
      * Asserts that a haystack contains only values of a given type.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -186,7 +187,7 @@ function assertContainsOnly(string $type, iterable $haystack, ?bool $isNativeTyp
      * Asserts that a haystack contains only instances of a given class name.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -203,7 +204,7 @@ function assertContainsOnlyInstancesOf(string $className, iterable $haystack, st
      * Asserts that a haystack does not contain only values of a given type.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -222,7 +223,7 @@ function assertNotContainsOnly(string $type, iterable $haystack, ?bool $isNative
      * @param Countable|iterable $haystack
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws Exception
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -242,7 +243,7 @@ function assertCount(int $expectedCount, $haystack, string $message = ''): void
      * @param Countable|iterable $haystack
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws Exception
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -260,7 +261,7 @@ function assertNotCount(int $expectedCount, $haystack, string $message = ''): vo
      * Asserts that two variables are equal.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -277,7 +278,7 @@ function assertEquals($expected, $actual, string $message = ''): void
      * Asserts that two variables are equal (canonicalizing).
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -294,7 +295,7 @@ function assertEqualsCanonicalizing($expected, $actual, string $message = ''): v
      * Asserts that two variables are equal (ignoring case).
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -311,7 +312,7 @@ function assertEqualsIgnoringCase($expected, $actual, string $message = ''): voi
      * Asserts that two variables are equal (with delta).
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -328,7 +329,7 @@ function assertEqualsWithDelta($expected, $actual, float $delta, string $message
      * Asserts that two variables are not equal.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -345,7 +346,7 @@ function assertNotEquals($expected, $actual, string $message = ''): void
      * Asserts that two variables are not equal (canonicalizing).
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -362,7 +363,7 @@ function assertNotEqualsCanonicalizing($expected, $actual, string $message = '')
      * Asserts that two variables are not equal (ignoring case).
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -379,7 +380,7 @@ function assertNotEqualsIgnoringCase($expected, $actual, string $message = ''):
      * Asserts that two variables are not equal (with delta).
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -410,7 +411,7 @@ function assertObjectEquals(object $expected, object $actual, string $method = '
      * Asserts that a variable is empty.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert empty $actual
      *
@@ -429,7 +430,7 @@ function assertEmpty($actual, string $message = ''): void
      * Asserts that a variable is not empty.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert !empty $actual
      *
@@ -448,7 +449,7 @@ function assertNotEmpty($actual, string $message = ''): void
      * Asserts that a value is greater than another value.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -465,7 +466,7 @@ function assertGreaterThan($expected, $actual, string $message = ''): void
      * Asserts that a value is greater than or equal to another value.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -482,7 +483,7 @@ function assertGreaterThanOrEqual($expected, $actual, string $message = ''): voi
      * Asserts that a value is smaller than another value.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -499,7 +500,7 @@ function assertLessThan($expected, $actual, string $message = ''): void
      * Asserts that a value is smaller than or equal to another value.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -517,7 +518,7 @@ function assertLessThanOrEqual($expected, $actual, string $message = ''): void
      * file.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -535,7 +536,7 @@ function assertFileEquals(string $expected, string $actual, string $message = ''
      * file (canonicalizing).
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -553,7 +554,7 @@ function assertFileEqualsCanonicalizing(string $expected, string $actual, string
      * file (ignoring case).
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -571,7 +572,7 @@ function assertFileEqualsIgnoringCase(string $expected, string $actual, string $
      * another file.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -589,7 +590,7 @@ function assertFileNotEquals(string $expected, string $actual, string $message =
      * file (canonicalizing).
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -607,7 +608,7 @@ function assertFileNotEqualsCanonicalizing(string $expected, string $actual, str
      * file (ignoring case).
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -625,7 +626,7 @@ function assertFileNotEqualsIgnoringCase(string $expected, string $actual, strin
      * to the contents of a file.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -643,7 +644,7 @@ function assertStringEqualsFile(string $expectedFile, string $actualString, stri
      * to the contents of a file (canonicalizing).
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -661,7 +662,7 @@ function assertStringEqualsFileCanonicalizing(string $expectedFile, string $actu
      * to the contents of a file (ignoring case).
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -679,7 +680,7 @@ function assertStringEqualsFileIgnoringCase(string $expectedFile, string $actual
      * to the contents of a file.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -697,7 +698,7 @@ function assertStringNotEqualsFile(string $expectedFile, string $actualString, s
      * to the contents of a file (canonicalizing).
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -715,7 +716,7 @@ function assertStringNotEqualsFileCanonicalizing(string $expectedFile, string $a
      * to the contents of a file (ignoring case).
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -732,7 +733,7 @@ function assertStringNotEqualsFileIgnoringCase(string $expectedFile, string $act
      * Asserts that a file/dir is readable.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -749,7 +750,7 @@ function assertIsReadable(string $filename, string $message = ''): void
      * Asserts that a file/dir exists and is not readable.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -766,7 +767,7 @@ function assertIsNotReadable(string $filename, string $message = ''): void
      * Asserts that a file/dir exists and is not readable.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @codeCoverageIgnore
      *
@@ -787,7 +788,7 @@ function assertNotIsReadable(string $filename, string $message = ''): void
      * Asserts that a file/dir exists and is writable.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -804,7 +805,7 @@ function assertIsWritable(string $filename, string $message = ''): void
      * Asserts that a file/dir exists and is not writable.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -821,7 +822,7 @@ function assertIsNotWritable(string $filename, string $message = ''): void
      * Asserts that a file/dir exists and is not writable.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @codeCoverageIgnore
      *
@@ -842,7 +843,7 @@ function assertNotIsWritable(string $filename, string $message = ''): void
      * Asserts that a directory exists.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -859,7 +860,7 @@ function assertDirectoryExists(string $directory, string $message = ''): void
      * Asserts that a directory does not exist.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -876,7 +877,7 @@ function assertDirectoryDoesNotExist(string $directory, string $message = ''): v
      * Asserts that a directory does not exist.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @codeCoverageIgnore
      *
@@ -897,7 +898,7 @@ function assertDirectoryNotExists(string $directory, string $message = ''): void
      * Asserts that a directory exists and is readable.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -914,7 +915,7 @@ function assertDirectoryIsReadable(string $directory, string $message = ''): voi
      * Asserts that a directory exists and is not readable.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -931,7 +932,7 @@ function assertDirectoryIsNotReadable(string $directory, string $message = ''):
      * Asserts that a directory exists and is not readable.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @codeCoverageIgnore
      *
@@ -952,7 +953,7 @@ function assertDirectoryNotIsReadable(string $directory, string $message = ''):
      * Asserts that a directory exists and is writable.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -969,7 +970,7 @@ function assertDirectoryIsWritable(string $directory, string $message = ''): voi
      * Asserts that a directory exists and is not writable.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -986,7 +987,7 @@ function assertDirectoryIsNotWritable(string $directory, string $message = ''):
      * Asserts that a directory exists and is not writable.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @codeCoverageIgnore
      *
@@ -1007,7 +1008,7 @@ function assertDirectoryNotIsWritable(string $directory, string $message = ''):
      * Asserts that a file exists.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -1024,7 +1025,7 @@ function assertFileExists(string $filename, string $message = ''): void
      * Asserts that a file does not exist.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -1041,7 +1042,7 @@ function assertFileDoesNotExist(string $filename, string $message = ''): void
      * Asserts that a file does not exist.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @codeCoverageIgnore
      *
@@ -1062,7 +1063,7 @@ function assertFileNotExists(string $filename, string $message = ''): void
      * Asserts that a file exists and is readable.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -1079,7 +1080,7 @@ function assertFileIsReadable(string $file, string $message = ''): void
      * Asserts that a file exists and is not readable.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -1096,7 +1097,7 @@ function assertFileIsNotReadable(string $file, string $message = ''): void
      * Asserts that a file exists and is not readable.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @codeCoverageIgnore
      *
@@ -1117,7 +1118,7 @@ function assertFileNotIsReadable(string $file, string $message = ''): void
      * Asserts that a file exists and is writable.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -1134,7 +1135,7 @@ function assertFileIsWritable(string $file, string $message = ''): void
      * Asserts that a file exists and is not writable.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -1151,7 +1152,7 @@ function assertFileIsNotWritable(string $file, string $message = ''): void
      * Asserts that a file exists and is not writable.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @codeCoverageIgnore
      *
@@ -1172,7 +1173,7 @@ function assertFileNotIsWritable(string $file, string $message = ''): void
      * Asserts that a condition is true.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert true $condition
      *
@@ -1191,7 +1192,7 @@ function assertTrue($condition, string $message = ''): void
      * Asserts that a condition is not true.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert !true $condition
      *
@@ -1210,7 +1211,7 @@ function assertNotTrue($condition, string $message = ''): void
      * Asserts that a condition is false.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert false $condition
      *
@@ -1229,7 +1230,7 @@ function assertFalse($condition, string $message = ''): void
      * Asserts that a condition is not false.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert !false $condition
      *
@@ -1248,7 +1249,7 @@ function assertNotFalse($condition, string $message = ''): void
      * Asserts that a variable is null.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert null $actual
      *
@@ -1267,7 +1268,7 @@ function assertNull($actual, string $message = ''): void
      * Asserts that a variable is not null.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert !null $actual
      *
@@ -1286,7 +1287,7 @@ function assertNotNull($actual, string $message = ''): void
      * Asserts that a variable is finite.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -1303,7 +1304,7 @@ function assertFinite($actual, string $message = ''): void
      * Asserts that a variable is infinite.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -1320,7 +1321,7 @@ function assertInfinite($actual, string $message = ''): void
      * Asserts that a variable is nan.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -1337,7 +1338,7 @@ function assertNan($actual, string $message = ''): void
      * Asserts that a class has a specified attribute.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws Exception
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -1355,7 +1356,7 @@ function assertClassHasAttribute(string $attributeName, string $className, strin
      * Asserts that a class does not have a specified attribute.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws Exception
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -1373,7 +1374,7 @@ function assertClassNotHasAttribute(string $attributeName, string $className, st
      * Asserts that a class has a specified static attribute.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws Exception
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -1391,7 +1392,7 @@ function assertClassHasStaticAttribute(string $attributeName, string $className,
      * Asserts that a class does not have a specified static attribute.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws Exception
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -1411,7 +1412,7 @@ function assertClassNotHasStaticAttribute(string $attributeName, string $classNa
      * @param object $object
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws Exception
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -1431,7 +1432,7 @@ function assertObjectHasAttribute(string $attributeName, $object, string $messag
      * @param object $object
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws Exception
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -1449,7 +1450,7 @@ function assertObjectNotHasAttribute(string $attributeName, $object, string $mes
      * Asserts that an object has a specified property.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws Exception
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -1467,7 +1468,7 @@ function assertObjectHasProperty(string $attributeName, object $object, string $
      * Asserts that an object does not have a specified property.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws Exception
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -1487,7 +1488,7 @@ function assertObjectNotHasProperty(string $attributeName, object $object, strin
      * the same object.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-template ExpectedType
      *
@@ -1512,7 +1513,7 @@ function assertSame($expected, $actual, string $message = ''): void
      * the same object.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -1529,7 +1530,7 @@ function assertNotSame($expected, $actual, string $message = ''): void
      * Asserts that a variable is of a given type.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws Exception
      *
      * @psalm-template ExpectedType of object
@@ -1553,7 +1554,7 @@ function assertInstanceOf(string $expected, $actual, string $message = ''): void
      * Asserts that a variable is not of a given type.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws Exception
      *
      * @psalm-template ExpectedType of object
@@ -1577,7 +1578,7 @@ function assertNotInstanceOf(string $expected, $actual, string $message = ''): v
      * Asserts that a variable is of type array.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert array $actual
      *
@@ -1596,7 +1597,7 @@ function assertIsArray($actual, string $message = ''): void
      * Asserts that a variable is of type bool.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert bool $actual
      *
@@ -1615,7 +1616,7 @@ function assertIsBool($actual, string $message = ''): void
      * Asserts that a variable is of type float.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert float $actual
      *
@@ -1634,7 +1635,7 @@ function assertIsFloat($actual, string $message = ''): void
      * Asserts that a variable is of type int.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert int $actual
      *
@@ -1653,7 +1654,7 @@ function assertIsInt($actual, string $message = ''): void
      * Asserts that a variable is of type numeric.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert numeric $actual
      *
@@ -1672,7 +1673,7 @@ function assertIsNumeric($actual, string $message = ''): void
      * Asserts that a variable is of type object.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert object $actual
      *
@@ -1691,7 +1692,7 @@ function assertIsObject($actual, string $message = ''): void
      * Asserts that a variable is of type resource.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert resource $actual
      *
@@ -1710,7 +1711,7 @@ function assertIsResource($actual, string $message = ''): void
      * Asserts that a variable is of type resource and is closed.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert resource $actual
      *
@@ -1729,7 +1730,7 @@ function assertIsClosedResource($actual, string $message = ''): void
      * Asserts that a variable is of type string.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert string $actual
      *
@@ -1748,7 +1749,7 @@ function assertIsString($actual, string $message = ''): void
      * Asserts that a variable is of type scalar.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert scalar $actual
      *
@@ -1767,7 +1768,7 @@ function assertIsScalar($actual, string $message = ''): void
      * Asserts that a variable is of type callable.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert callable $actual
      *
@@ -1786,7 +1787,7 @@ function assertIsCallable($actual, string $message = ''): void
      * Asserts that a variable is of type iterable.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert iterable $actual
      *
@@ -1805,7 +1806,7 @@ function assertIsIterable($actual, string $message = ''): void
      * Asserts that a variable is not of type array.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert !array $actual
      *
@@ -1824,7 +1825,7 @@ function assertIsNotArray($actual, string $message = ''): void
      * Asserts that a variable is not of type bool.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert !bool $actual
      *
@@ -1843,7 +1844,7 @@ function assertIsNotBool($actual, string $message = ''): void
      * Asserts that a variable is not of type float.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert !float $actual
      *
@@ -1862,7 +1863,7 @@ function assertIsNotFloat($actual, string $message = ''): void
      * Asserts that a variable is not of type int.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert !int $actual
      *
@@ -1881,7 +1882,7 @@ function assertIsNotInt($actual, string $message = ''): void
      * Asserts that a variable is not of type numeric.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert !numeric $actual
      *
@@ -1900,7 +1901,7 @@ function assertIsNotNumeric($actual, string $message = ''): void
      * Asserts that a variable is not of type object.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert !object $actual
      *
@@ -1919,7 +1920,7 @@ function assertIsNotObject($actual, string $message = ''): void
      * Asserts that a variable is not of type resource.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert !resource $actual
      *
@@ -1938,7 +1939,7 @@ function assertIsNotResource($actual, string $message = ''): void
      * Asserts that a variable is not of type resource.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert !resource $actual
      *
@@ -1957,7 +1958,7 @@ function assertIsNotClosedResource($actual, string $message = ''): void
      * Asserts that a variable is not of type string.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert !string $actual
      *
@@ -1976,7 +1977,7 @@ function assertIsNotString($actual, string $message = ''): void
      * Asserts that a variable is not of type scalar.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert !scalar $actual
      *
@@ -1995,7 +1996,7 @@ function assertIsNotScalar($actual, string $message = ''): void
      * Asserts that a variable is not of type callable.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert !callable $actual
      *
@@ -2014,7 +2015,7 @@ function assertIsNotCallable($actual, string $message = ''): void
      * Asserts that a variable is not of type iterable.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @psalm-assert !iterable $actual
      *
@@ -2033,7 +2034,7 @@ function assertIsNotIterable($actual, string $message = ''): void
      * Asserts that a string matches a given regular expression.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -2050,7 +2051,7 @@ function assertMatchesRegularExpression(string $pattern, string $string, string
      * Asserts that a string matches a given regular expression.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @codeCoverageIgnore
      *
@@ -2071,7 +2072,7 @@ function assertRegExp(string $pattern, string $string, string $message = ''): vo
      * Asserts that a string does not match a given regular expression.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -2088,7 +2089,7 @@ function assertDoesNotMatchRegularExpression(string $pattern, string $string, st
      * Asserts that a string does not match a given regular expression.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @codeCoverageIgnore
      *
@@ -2113,7 +2114,7 @@ function assertNotRegExp(string $pattern, string $string, string $message = ''):
      * @param Countable|iterable $actual
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws Exception
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -2135,7 +2136,7 @@ function assertSameSize($expected, $actual, string $message = ''): void
      * @param Countable|iterable $actual
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws Exception
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -2153,7 +2154,7 @@ function assertNotSameSize($expected, $actual, string $message = ''): void
      * Asserts that a string matches a given format string.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -2170,7 +2171,7 @@ function assertStringMatchesFormat(string $format, string $string, string $messa
      * Asserts that a string does not match a given format string.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -2187,7 +2188,7 @@ function assertStringNotMatchesFormat(string $format, string $string, string $me
      * Asserts that a string matches a given format file.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -2204,7 +2205,7 @@ function assertStringMatchesFormatFile(string $formatFile, string $string, strin
      * Asserts that a string does not match a given format string.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -2221,7 +2222,7 @@ function assertStringNotMatchesFormatFile(string $formatFile, string $string, st
      * Asserts that a string starts with a given prefix.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -2241,7 +2242,7 @@ function assertStringStartsWith(string $prefix, string $string, string $message
      * @param string $string
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -2256,7 +2257,7 @@ function assertStringStartsNotWith($prefix, $string, string $message = ''): void
 if (!function_exists('PHPUnit\Framework\assertStringContainsString')) {
     /**
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -2271,7 +2272,7 @@ function assertStringContainsString(string $needle, string $haystack, string $me
 if (!function_exists('PHPUnit\Framework\assertStringContainsStringIgnoringCase')) {
     /**
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -2286,7 +2287,7 @@ function assertStringContainsStringIgnoringCase(string $needle, string $haystack
 if (!function_exists('PHPUnit\Framework\assertStringNotContainsString')) {
     /**
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -2301,7 +2302,7 @@ function assertStringNotContainsString(string $needle, string $haystack, string
 if (!function_exists('PHPUnit\Framework\assertStringNotContainsStringIgnoringCase')) {
     /**
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -2318,7 +2319,7 @@ function assertStringNotContainsStringIgnoringCase(string $needle, string $hayst
      * Asserts that a string ends with a given suffix.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -2335,7 +2336,7 @@ function assertStringEndsWith(string $suffix, string $string, string $message =
      * Asserts that a string ends not with a given suffix.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -2352,7 +2353,7 @@ function assertStringEndsNotWith(string $suffix, string $string, string $message
      * Asserts that two XML files are equal.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws Exception
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -2370,7 +2371,7 @@ function assertXmlFileEqualsXmlFile(string $expectedFile, string $actualFile, st
      * Asserts that two XML files are not equal.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws \PHPUnit\Util\Exception
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -2390,7 +2391,7 @@ function assertXmlFileNotEqualsXmlFile(string $expectedFile, string $actualFile,
      * @param DOMDocument|string $actualXml
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws \PHPUnit\Util\Xml\Exception
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -2410,7 +2411,7 @@ function assertXmlStringEqualsXmlFile(string $expectedFile, $actualXml, string $
      * @param DOMDocument|string $actualXml
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws \PHPUnit\Util\Xml\Exception
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -2431,7 +2432,7 @@ function assertXmlStringNotEqualsXmlFile(string $expectedFile, $actualXml, strin
      * @param DOMDocument|string $actualXml
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws \PHPUnit\Util\Xml\Exception
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -2452,7 +2453,7 @@ function assertXmlStringEqualsXmlString($expectedXml, $actualXml, string $messag
      * @param DOMDocument|string $actualXml
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws \PHPUnit\Util\Xml\Exception
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -2471,7 +2472,7 @@ function assertXmlStringNotEqualsXmlString($expectedXml, $actualXml, string $mes
      *
      * @throws AssertionFailedError
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @codeCoverageIgnore
      *
@@ -2492,7 +2493,7 @@ function assertEqualXMLStructure(DOMElement $expectedElement, DOMElement $actual
      * Evaluates a PHPUnit\Framework\Constraint matcher object.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -2509,7 +2510,7 @@ function assertThat($value, Constraint $constraint, string $message = ''): void
      * Asserts that a string is a valid JSON string.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -2526,7 +2527,7 @@ function assertJson(string $actualJson, string $message = ''): void
      * Asserts that two given JSON encoded objects or arrays are equal.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -2546,7 +2547,7 @@ function assertJsonStringEqualsJsonString(string $expectedJson, string $actualJs
      * @param string $actualJson
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -2563,7 +2564,7 @@ function assertJsonStringNotEqualsJsonString($expectedJson, $actualJson, string
      * Asserts that the generated JSON encoded object and the content of the given file are equal.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -2580,7 +2581,7 @@ function assertJsonStringEqualsJsonFile(string $expectedFile, string $actualJson
      * Asserts that the generated JSON encoded object and the content of the given file are not equal.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -2597,7 +2598,7 @@ function assertJsonStringNotEqualsJsonFile(string $expectedFile, string $actualJ
      * Asserts that two JSON files are equal.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
@@ -2614,7 +2615,7 @@ function assertJsonFileEqualsJsonFile(string $expectedFile, string $actualFile,
      * Asserts that two JSON files are not equal.
      *
      * @throws ExpectationFailedException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
      *
diff --git a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/GreaterThan.php b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/GreaterThan.php
index 31df50201..7d079f508 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/GreaterThan.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/GreaterThan.php
@@ -9,6 +9,8 @@
  */
 namespace PHPUnit\Framework\Constraint;
 
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
+
 /**
  * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
  */
@@ -30,7 +32,7 @@ public function __construct($value)
     /**
      * Returns a string representation of the constraint.
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function toString(): string
     {
diff --git a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/LessThan.php b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/LessThan.php
index c7884ba1d..4d0184a25 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/LessThan.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Cardinality/LessThan.php
@@ -9,6 +9,8 @@
  */
 namespace PHPUnit\Framework\Constraint;
 
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
+
 /**
  * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
  */
@@ -30,7 +32,7 @@ public function __construct($value)
     /**
      * Returns a string representation of the constraint.
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function toString(): string
     {
diff --git a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Constraint.php b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Constraint.php
index 37548e566..2ee73973c 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Constraint.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Constraint.php
@@ -15,6 +15,7 @@
 use PHPUnit\Framework\SelfDescribing;
 use SebastianBergmann\Comparator\ComparisonFailure;
 use SebastianBergmann\Exporter\Exporter;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 
 /**
  * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -36,8 +37,8 @@ abstract class Constraint implements Countable, SelfDescribing
      * a boolean value instead: true in case of success, false in case of a
      * failure.
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
      * @throws ExpectationFailedException
+     * @throws InvalidArgumentException
      */
     public function evaluate($other, string $description = '', bool $returnResult = false): ?bool
     {
@@ -96,12 +97,12 @@ protected function matches($other): bool
      * @param mixed  $other       evaluated value or object
      * @param string $description Additional information about the test
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
      * @throws ExpectationFailedException
+     * @throws InvalidArgumentException
      *
      * @psalm-return never-return
      */
-    protected function fail($other, $description, ComparisonFailure $comparisonFailure = null): void
+    protected function fail($other, $description, ?ComparisonFailure $comparisonFailure = null): void
     {
         $failureDescription = sprintf(
             'Failed asserting that %s.',
@@ -148,7 +149,7 @@ protected function additionalFailureDescription($other): string
      *
      * @param mixed $other evaluated value or object
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     protected function failureDescription($other): string
     {
diff --git a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqual.php b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqual.php
index d209444b9..04bfe4e86 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqual.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqual.php
@@ -16,6 +16,7 @@
 use PHPUnit\Framework\ExpectationFailedException;
 use SebastianBergmann\Comparator\ComparisonFailure;
 use SebastianBergmann\Comparator\Factory as ComparatorFactory;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 
 /**
  * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -103,7 +104,7 @@ public function evaluate($other, string $description = '', bool $returnResult =
     /**
      * Returns a string representation of the constraint.
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function toString(): string
     {
diff --git a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualCanonicalizing.php b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualCanonicalizing.php
index b87dadad9..6d49c350e 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualCanonicalizing.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualCanonicalizing.php
@@ -16,6 +16,7 @@
 use PHPUnit\Framework\ExpectationFailedException;
 use SebastianBergmann\Comparator\ComparisonFailure;
 use SebastianBergmann\Comparator\Factory as ComparatorFactory;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 
 /**
  * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -85,7 +86,7 @@ public function evaluate($other, string $description = '', bool $returnResult =
     /**
      * Returns a string representation of the constraint.
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function toString(): string
     {
diff --git a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualIgnoringCase.php b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualIgnoringCase.php
index 3642da213..932b7318d 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualIgnoringCase.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualIgnoringCase.php
@@ -16,6 +16,7 @@
 use PHPUnit\Framework\ExpectationFailedException;
 use SebastianBergmann\Comparator\ComparisonFailure;
 use SebastianBergmann\Comparator\Factory as ComparatorFactory;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 
 /**
  * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -85,7 +86,7 @@ public function evaluate($other, string $description = '', bool $returnResult =
     /**
      * Returns a string representation of the constraint.
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function toString(): string
     {
diff --git a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualWithDelta.php b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualWithDelta.php
index f7d8aced9..0a04ffc8b 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualWithDelta.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Equality/IsEqualWithDelta.php
@@ -14,6 +14,7 @@
 use PHPUnit\Framework\ExpectationFailedException;
 use SebastianBergmann\Comparator\ComparisonFailure;
 use SebastianBergmann\Comparator\Factory as ComparatorFactory;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 
 /**
  * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -87,7 +88,7 @@ public function evaluate($other, string $description = '', bool $returnResult =
     /**
      * Returns a string representation of the constraint.
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function toString(): string
     {
diff --git a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Exception/ExceptionCode.php b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Exception/ExceptionCode.php
index a6fad4c75..4d65e03b9 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Exception/ExceptionCode.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Exception/ExceptionCode.php
@@ -10,6 +10,7 @@
 namespace PHPUnit\Framework\Constraint;
 
 use function sprintf;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 use Throwable;
 
 /**
@@ -54,7 +55,7 @@ protected function matches($other): bool
      *
      * @param mixed $other evaluated value or object
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     protected function failureDescription($other): string
     {
diff --git a/app/vendor/phpunit/phpunit/src/Framework/Constraint/IsIdentical.php b/app/vendor/phpunit/phpunit/src/Framework/Constraint/IsIdentical.php
index f36d44e74..9eb44a992 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/Constraint/IsIdentical.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/Constraint/IsIdentical.php
@@ -16,6 +16,7 @@
 use function sprintf;
 use PHPUnit\Framework\ExpectationFailedException;
 use SebastianBergmann\Comparator\ComparisonFailure;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 
 /**
  * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -42,8 +43,8 @@ public function __construct($value)
      * a boolean value instead: true in case of success, false in case of a
      * failure.
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
      * @throws ExpectationFailedException
+     * @throws InvalidArgumentException
      */
     public function evaluate($other, string $description = '', bool $returnResult = false): ?bool
     {
@@ -85,7 +86,7 @@ public function evaluate($other, string $description = '', bool $returnResult =
     /**
      * Returns a string representation of the constraint.
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function toString(): string
     {
@@ -105,7 +106,7 @@ public function toString(): string
      *
      * @param mixed $other evaluated value or object
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     protected function failureDescription($other): string
     {
diff --git a/app/vendor/phpunit/phpunit/src/Framework/Constraint/JsonMatches.php b/app/vendor/phpunit/phpunit/src/Framework/Constraint/JsonMatches.php
index 54de688c8..6fbd38c3b 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/Constraint/JsonMatches.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/Constraint/JsonMatches.php
@@ -11,9 +11,11 @@
 
 use function json_decode;
 use function sprintf;
+use PHPUnit\Framework\Exception;
 use PHPUnit\Framework\ExpectationFailedException;
 use PHPUnit\Util\Json;
 use SebastianBergmann\Comparator\ComparisonFailure;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 
 /**
  * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -72,13 +74,13 @@ protected function matches($other): bool
      * @param mixed  $other       evaluated value or object
      * @param string $description Additional information about the test
      *
-     * @throws \PHPUnit\Framework\Exception
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws Exception
      * @throws ExpectationFailedException
+     * @throws InvalidArgumentException
      *
      * @psalm-return never-return
      */
-    protected function fail($other, $description, ComparisonFailure $comparisonFailure = null): void
+    protected function fail($other, $description, ?ComparisonFailure $comparisonFailure = null): void
     {
         if ($comparisonFailure === null) {
             [$error, $recodedOther] = Json::canonicalize($other);
diff --git a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Operator/UnaryOperator.php b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Operator/UnaryOperator.php
index 0a7a5fa2f..f8c24a52a 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Operator/UnaryOperator.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Operator/UnaryOperator.php
@@ -10,6 +10,7 @@
 namespace PHPUnit\Framework\Constraint;
 
 use function count;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 
 /**
  * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -79,7 +80,7 @@ public function count(): int
      *
      * @param mixed $other evaluated value or object
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     protected function failureDescription($other): string
     {
@@ -105,7 +106,7 @@ protected function failureDescription($other): string
     }
 
     /**
-     * Transforms string returned by the memeber constraint's toString() or
+     * Transforms string returned by the member constraint's toString() or
      * failureDescription() such that it reflects constraint's participation in
      * this expression.
      *
diff --git a/app/vendor/phpunit/phpunit/src/Framework/Constraint/String/IsJson.php b/app/vendor/phpunit/phpunit/src/Framework/Constraint/String/IsJson.php
index f90704f0a..bdf363326 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/Constraint/String/IsJson.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/Constraint/String/IsJson.php
@@ -12,6 +12,7 @@
 use function json_decode;
 use function json_last_error;
 use function sprintf;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 
 /**
  * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -55,7 +56,7 @@ protected function matches($other): bool
      *
      * @param mixed $other evaluated value or object
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     protected function failureDescription($other): string
     {
diff --git a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/ArrayHasKey.php b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/ArrayHasKey.php
index 44cada3a7..98a757a73 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/ArrayHasKey.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/ArrayHasKey.php
@@ -12,6 +12,7 @@
 use function array_key_exists;
 use function is_array;
 use ArrayAccess;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 
 /**
  * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -34,7 +35,7 @@ public function __construct($key)
     /**
      * Returns a string representation of the constraint.
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function toString(): string
     {
@@ -68,7 +69,7 @@ protected function matches($other): bool
      *
      * @param mixed $other evaluated value or object
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     protected function failureDescription($other): string
     {
diff --git a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/TraversableContains.php b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/TraversableContains.php
index d0f61f46a..0f934396e 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/TraversableContains.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/TraversableContains.php
@@ -11,6 +11,7 @@
 
 use function is_array;
 use function sprintf;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 
 /**
  * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -30,7 +31,7 @@ public function __construct($value)
     /**
      * Returns a string representation of the constraint.
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function toString(): string
     {
@@ -45,7 +46,7 @@ public function toString(): string
      *
      * @param mixed $other evaluated value or object
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     protected function failureDescription($other): string
     {
diff --git a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/TraversableContainsOnly.php b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/TraversableContainsOnly.php
index e5c688902..4f34f72a3 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/TraversableContainsOnly.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Traversable/TraversableContainsOnly.php
@@ -9,7 +9,9 @@
  */
 namespace PHPUnit\Framework\Constraint;
 
+use PHPUnit\Framework\Exception;
 use PHPUnit\Framework\ExpectationFailedException;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 use Traversable;
 
 /**
@@ -28,7 +30,7 @@ final class TraversableContainsOnly extends Constraint
     private $type;
 
     /**
-     * @throws \PHPUnit\Framework\Exception
+     * @throws Exception
      */
     public function __construct(string $type, bool $isNativeType = true)
     {
@@ -55,8 +57,8 @@ public function __construct(string $type, bool $isNativeType = true)
      *
      * @param mixed|Traversable $other
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
      * @throws ExpectationFailedException
+     * @throws InvalidArgumentException
      */
     public function evaluate($other, string $description = '', bool $returnResult = false): ?bool
     {
diff --git a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Type/IsInstanceOf.php b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Type/IsInstanceOf.php
index ef26813f9..c1b73a837 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Type/IsInstanceOf.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Type/IsInstanceOf.php
@@ -12,6 +12,7 @@
 use function sprintf;
 use ReflectionClass;
 use ReflectionException;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 
 /**
  * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -59,7 +60,7 @@ protected function matches($other): bool
      *
      * @param mixed $other evaluated value or object
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     protected function failureDescription($other): string
     {
diff --git a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Type/IsType.php b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Type/IsType.php
index 6edcc2b95..285b74a77 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/Constraint/Type/IsType.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/Constraint/Type/IsType.php
@@ -21,6 +21,7 @@
 use function is_scalar;
 use function is_string;
 use function sprintf;
+use PHPUnit\Framework\Exception;
 
 /**
  * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit
@@ -121,12 +122,12 @@ final class IsType extends Constraint
     private $type;
 
     /**
-     * @throws \PHPUnit\Framework\Exception
+     * @throws Exception
      */
     public function __construct(string $type)
     {
         if (!isset(self::KNOWN_TYPES[$type])) {
-            throw new \PHPUnit\Framework\Exception(
+            throw new Exception(
                 sprintf(
                     'Type specified for PHPUnit\Framework\Constraint\IsType <%s> ' .
                     'is not a valid type.',
diff --git a/app/vendor/phpunit/phpunit/src/Framework/DataProviderTestSuite.php b/app/vendor/phpunit/phpunit/src/Framework/DataProviderTestSuite.php
index 18b549996..4d7ab8597 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/DataProviderTestSuite.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/DataProviderTestSuite.php
@@ -11,6 +11,7 @@
 
 use function explode;
 use PHPUnit\Util\Test as TestUtil;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 
 /**
  * @internal This class is not covered by the backward compatibility promise for PHPUnit
@@ -64,7 +65,7 @@ public function requires(): array
     /**
      * Returns the size of the each test created using the data provider(s).
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function getSize(): int
     {
diff --git a/app/vendor/phpunit/phpunit/src/Framework/Error/Error.php b/app/vendor/phpunit/phpunit/src/Framework/Error/Error.php
index 2990b360e..3163a8670 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/Error/Error.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/Error/Error.php
@@ -16,7 +16,7 @@
  */
 class Error extends Exception
 {
-    public function __construct(string $message, int $code, string $file, int $line, \Exception $previous = null)
+    public function __construct(string $message, int $code, string $file, int $line, ?\Exception $previous = null)
     {
         parent::__construct($message, $code, $previous);
 
diff --git a/app/vendor/phpunit/phpunit/src/Framework/Exception/Exception.php b/app/vendor/phpunit/phpunit/src/Framework/Exception/Exception.php
index 0b21e6de3..3ed049274 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/Exception/Exception.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/Exception/Exception.php
@@ -44,7 +44,7 @@ class Exception extends RuntimeException implements \PHPUnit\Exception
      */
     protected $serializableTrace;
 
-    public function __construct($message = '', $code = 0, Throwable $previous = null)
+    public function __construct($message = '', $code = 0, ?Throwable $previous = null)
     {
         parent::__construct($message, $code, $previous);
 
diff --git a/app/vendor/phpunit/phpunit/src/Framework/Exception/ExpectationFailedException.php b/app/vendor/phpunit/phpunit/src/Framework/Exception/ExpectationFailedException.php
index b9a595a88..a81d7535f 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/Exception/ExpectationFailedException.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/Exception/ExpectationFailedException.php
@@ -28,7 +28,7 @@ final class ExpectationFailedException extends AssertionFailedError
      */
     protected $comparisonFailure;
 
-    public function __construct(string $message, ComparisonFailure $comparisonFailure = null, Exception $previous = null)
+    public function __construct(string $message, ?ComparisonFailure $comparisonFailure = null, ?Exception $previous = null)
     {
         $this->comparisonFailure = $comparisonFailure;
 
diff --git a/app/vendor/phpunit/phpunit/src/Framework/Exception/InvalidArgumentException.php b/app/vendor/phpunit/phpunit/src/Framework/Exception/InvalidArgumentException.php
index 888e9300b..4181b3206 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/Exception/InvalidArgumentException.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/Exception/InvalidArgumentException.php
@@ -39,7 +39,7 @@ public static function create(int $argument, string $type): self
         );
     }
 
-    private function __construct(string $message = '', int $code = 0, \Exception $previous = null)
+    private function __construct(string $message = '', int $code = 0, ?\Exception $previous = null)
     {
         parent::__construct($message, $code, $previous);
     }
diff --git a/app/vendor/phpunit/phpunit/src/Framework/ExceptionWrapper.php b/app/vendor/phpunit/phpunit/src/Framework/ExceptionWrapper.php
index 00d40353a..d30e90b2f 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/ExceptionWrapper.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/ExceptionWrapper.php
@@ -114,7 +114,7 @@ public function getOriginalException(): ?Throwable
      *
      * Approach works both for var_dump() and var_export() and print_r().
      */
-    private function originalException(Throwable $exceptionToStore = null): ?Throwable
+    private function originalException(?Throwable $exceptionToStore = null): ?Throwable
     {
         // drop once PHP 7.3 support is removed
         if (PHP_VERSION_ID < 70400) {
diff --git a/app/vendor/phpunit/phpunit/src/Framework/IncompleteTestCase.php b/app/vendor/phpunit/phpunit/src/Framework/IncompleteTestCase.php
index 53e031a2a..8da567942 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/IncompleteTestCase.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/IncompleteTestCase.php
@@ -9,6 +9,8 @@
  */
 namespace PHPUnit\Framework;
 
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
+
 /**
  * @internal This class is not covered by the backward compatibility promise for PHPUnit
  */
@@ -49,7 +51,7 @@ public function getMessage(): string
     /**
      * Returns a string representation of the test case.
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function toString(): string
     {
diff --git a/app/vendor/phpunit/phpunit/src/Framework/MockObject/Builder/InvocationMocker.php b/app/vendor/phpunit/phpunit/src/Framework/MockObject/Builder/InvocationMocker.php
index 626c33a7b..b23e5e389 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/MockObject/Builder/InvocationMocker.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/MockObject/Builder/InvocationMocker.php
@@ -16,6 +16,7 @@
 use function is_string;
 use function strtolower;
 use PHPUnit\Framework\Constraint\Constraint;
+use PHPUnit\Framework\InvalidArgumentException;
 use PHPUnit\Framework\MockObject\ConfigurableMethod;
 use PHPUnit\Framework\MockObject\IncompatibleReturnValueException;
 use PHPUnit\Framework\MockObject\InvocationHandler;
@@ -224,7 +225,7 @@ public function withAnyParameters(): self
     /**
      * @param Constraint|string $constraint
      *
-     * @throws \PHPUnit\Framework\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws MethodCannotBeConfiguredException
      * @throws MethodNameAlreadyConfiguredException
      *
diff --git a/app/vendor/phpunit/phpunit/src/Framework/MockObject/Builder/MethodNameMatch.php b/app/vendor/phpunit/phpunit/src/Framework/MockObject/Builder/MethodNameMatch.php
index 543d596cc..a71caf797 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/MockObject/Builder/MethodNameMatch.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/MockObject/Builder/MethodNameMatch.php
@@ -9,6 +9,8 @@
  */
 namespace PHPUnit\Framework\MockObject\Builder;
 
+use PHPUnit\Framework\Constraint\Constraint;
+
 /**
  * @internal This class is not covered by the backward compatibility promise for PHPUnit
  */
@@ -18,7 +20,7 @@ interface MethodNameMatch extends ParametersMatch
      * Adds a new method name match and returns the parameter match object for
      * further matching possibilities.
      *
-     * @param \PHPUnit\Framework\Constraint\Constraint $constraint Constraint for matching method, if a string is passed it will use the PHPUnit_Framework_Constraint_IsEqual
+     * @param Constraint $constraint Constraint for matching method, if a string is passed it will use the PHPUnit_Framework_Constraint_IsEqual
      *
      * @return ParametersMatch
      */
diff --git a/app/vendor/phpunit/phpunit/src/Framework/MockObject/Generator.php b/app/vendor/phpunit/phpunit/src/Framework/MockObject/Generator.php
index fa6724796..49211ad7e 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/MockObject/Generator.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/MockObject/Generator.php
@@ -152,7 +152,7 @@ public function __clone()
      * @throws RuntimeException
      * @throws UnknownTypeException
      */
-    public function getMock(string $type, $methods = [], array $arguments = [], string $mockClassName = '', bool $callOriginalConstructor = true, bool $callOriginalClone = true, bool $callAutoload = true, bool $cloneArguments = true, bool $callOriginalMethods = false, object $proxyTarget = null, bool $allowMockingUnknownTypes = true, bool $returnValueGeneration = true): MockObject
+    public function getMock(string $type, $methods = [], array $arguments = [], string $mockClassName = '', bool $callOriginalConstructor = true, bool $callOriginalClone = true, bool $callAutoload = true, bool $cloneArguments = true, bool $callOriginalMethods = false, ?object $proxyTarget = null, bool $allowMockingUnknownTypes = true, bool $returnValueGeneration = true): MockObject
     {
         if (!is_array($methods) && null !== $methods) {
             throw InvalidArgumentException::create(2, 'array');
@@ -307,7 +307,7 @@ public function getMockForInterfaces(array $interfaces, bool $callAutoload = tru
      * @throws UnknownClassException
      * @throws UnknownTypeException
      */
-    public function getMockForAbstractClass(string $originalClassName, array $arguments = [], string $mockClassName = '', bool $callOriginalConstructor = true, bool $callOriginalClone = true, bool $callAutoload = true, array $mockedMethods = null, bool $cloneArguments = true): MockObject
+    public function getMockForAbstractClass(string $originalClassName, array $arguments = [], string $mockClassName = '', bool $callOriginalConstructor = true, bool $callOriginalClone = true, bool $callAutoload = true, ?array $mockedMethods = null, bool $cloneArguments = true): MockObject
     {
         if (class_exists($originalClassName, $callAutoload) ||
             interface_exists($originalClassName, $callAutoload)) {
@@ -370,7 +370,7 @@ interface_exists($originalClassName, $callAutoload)) {
      * @throws UnknownTraitException
      * @throws UnknownTypeException
      */
-    public function getMockForTrait(string $traitName, array $arguments = [], string $mockClassName = '', bool $callOriginalConstructor = true, bool $callOriginalClone = true, bool $callAutoload = true, array $mockedMethods = null, bool $cloneArguments = true): MockObject
+    public function getMockForTrait(string $traitName, array $arguments = [], string $mockClassName = '', bool $callOriginalConstructor = true, bool $callOriginalClone = true, bool $callAutoload = true, ?array $mockedMethods = null, bool $cloneArguments = true): MockObject
     {
         if (!trait_exists($traitName, $callAutoload)) {
             throw new UnknownTraitException($traitName);
@@ -447,7 +447,7 @@ public function getObjectForTrait(string $traitName, string $traitClassName = ''
      * @throws ReflectionException
      * @throws RuntimeException
      */
-    public function generate(string $type, array $methods = null, string $mockClassName = '', bool $callOriginalClone = true, bool $callAutoload = true, bool $cloneArguments = true, bool $callOriginalMethods = false): MockClass
+    public function generate(string $type, ?array $methods = null, string $mockClassName = '', bool $callOriginalClone = true, bool $callAutoload = true, bool $cloneArguments = true, bool $callOriginalMethods = false): MockClass
     {
         if ($mockClassName !== '') {
             return $this->generateMock(
@@ -703,7 +703,7 @@ private function userDefinedInterfaceMethods(string $interfaceName): array
      * @throws ReflectionException
      * @throws RuntimeException
      */
-    private function getObject(MockType $mockClass, $type = '', bool $callOriginalConstructor = false, bool $callAutoload = false, array $arguments = [], bool $callOriginalMethods = false, object $proxyTarget = null, bool $returnValueGeneration = true)
+    private function getObject(MockType $mockClass, $type = '', bool $callOriginalConstructor = false, bool $callAutoload = false, array $arguments = [], bool $callOriginalMethods = false, ?object $proxyTarget = null, bool $returnValueGeneration = true)
     {
         $className = $mockClass->generate();
 
diff --git a/app/vendor/phpunit/phpunit/src/Framework/MockObject/Matcher.php b/app/vendor/phpunit/phpunit/src/Framework/MockObject/Matcher.php
index a8ebe14fa..cc8be0585 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/MockObject/Matcher.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/MockObject/Matcher.php
@@ -22,6 +22,7 @@
 use PHPUnit\Framework\MockObject\Rule\ParametersRule;
 use PHPUnit\Framework\MockObject\Stub\Stub;
 use PHPUnit\Framework\TestFailure;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 
 /**
  * @internal This class is not covered by the backward compatibility promise for PHPUnit
@@ -157,8 +158,8 @@ public function invoked(Invocation $invocation)
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
      * @throws ExpectationFailedException
+     * @throws InvalidArgumentException
      * @throws MatchBuilderNotFoundException
      * @throws MethodNameNotConfiguredException
      * @throws RuntimeException
@@ -209,8 +210,8 @@ public function matches(Invocation $invocation): bool
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
      * @throws ExpectationFailedException
+     * @throws InvalidArgumentException
      * @throws MethodNameNotConfiguredException
      */
     public function verify(): void
diff --git a/app/vendor/phpunit/phpunit/src/Framework/MockObject/MockBuilder.php b/app/vendor/phpunit/phpunit/src/Framework/MockObject/MockBuilder.php
index 69ec25026..487ea16ad 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/MockObject/MockBuilder.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/MockObject/MockBuilder.php
@@ -11,6 +11,8 @@
 
 use function array_diff;
 use function array_merge;
+use PHPUnit\Framework\Exception;
+use PHPUnit\Framework\InvalidArgumentException;
 use PHPUnit\Framework\TestCase;
 use ReflectionClass;
 
@@ -111,11 +113,11 @@ public function __construct(TestCase $testCase, $type)
     /**
      * Creates a mock object using a fluent interface.
      *
-     * @throws \PHPUnit\Framework\InvalidArgumentException
      * @throws ClassAlreadyExistsException
      * @throws ClassIsFinalException
      * @throws ClassIsReadonlyException
      * @throws DuplicateMethodException
+     * @throws InvalidArgumentException
      * @throws InvalidMethodNameException
      * @throws OriginalConstructorInvocationRequiredException
      * @throws ReflectionException
@@ -151,7 +153,7 @@ public function getMock(): MockObject
      *
      * @psalm-return MockObject&MockedType
      *
-     * @throws \PHPUnit\Framework\Exception
+     * @throws Exception
      * @throws ReflectionException
      * @throws RuntimeException
      */
@@ -178,7 +180,7 @@ public function getMockForAbstractClass(): MockObject
      *
      * @psalm-return MockObject&MockedType
      *
-     * @throws \PHPUnit\Framework\Exception
+     * @throws Exception
      * @throws ReflectionException
      * @throws RuntimeException
      */
diff --git a/app/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/ConsecutiveParameters.php b/app/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/ConsecutiveParameters.php
index c2de01a4f..9d3ab7203 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/ConsecutiveParameters.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/ConsecutiveParameters.php
@@ -15,9 +15,11 @@
 use function sprintf;
 use PHPUnit\Framework\Constraint\Constraint;
 use PHPUnit\Framework\Constraint\IsEqual;
+use PHPUnit\Framework\Exception;
 use PHPUnit\Framework\ExpectationFailedException;
 use PHPUnit\Framework\InvalidParameterGroupException;
 use PHPUnit\Framework\MockObject\Invocation as BaseInvocation;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 
 /**
  * @internal This class is not covered by the backward compatibility promise for PHPUnit
@@ -37,7 +39,7 @@ final class ConsecutiveParameters implements ParametersRule
     private $invocations = [];
 
     /**
-     * @throws \PHPUnit\Framework\Exception
+     * @throws Exception
      */
     public function __construct(array $parameterGroups)
     {
@@ -68,8 +70,8 @@ public function toString(): string
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
      * @throws ExpectationFailedException
+     * @throws InvalidArgumentException
      */
     public function apply(BaseInvocation $invocation): void
     {
@@ -80,8 +82,8 @@ public function apply(BaseInvocation $invocation): void
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
      * @throws ExpectationFailedException
+     * @throws InvalidArgumentException
      */
     public function verify(): void
     {
@@ -95,8 +97,8 @@ public function verify(): void
      *
      * @param int $callIndex
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
      * @throws ExpectationFailedException
+     * @throws InvalidArgumentException
      */
     private function verifyInvocation(BaseInvocation $invocation, $callIndex): void
     {
diff --git a/app/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/MethodName.php b/app/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/MethodName.php
index 83ba3b8da..53c638876 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/MethodName.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/MethodName.php
@@ -11,6 +11,7 @@
 
 use function is_string;
 use PHPUnit\Framework\Constraint\Constraint;
+use PHPUnit\Framework\ExpectationFailedException;
 use PHPUnit\Framework\InvalidArgumentException;
 use PHPUnit\Framework\MockObject\Invocation as BaseInvocation;
 use PHPUnit\Framework\MockObject\MethodNameConstraint;
@@ -49,8 +50,8 @@ public function toString(): string
     }
 
     /**
-     * @throws \PHPUnit\Framework\ExpectationFailedException
      * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws ExpectationFailedException
      */
     public function matches(BaseInvocation $invocation): bool
     {
@@ -58,8 +59,8 @@ public function matches(BaseInvocation $invocation): bool
     }
 
     /**
-     * @throws \PHPUnit\Framework\ExpectationFailedException
      * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws ExpectationFailedException
      */
     public function matchesName(string $methodName): bool
     {
diff --git a/app/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/Parameters.php b/app/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/Parameters.php
index cb71b271c..c03671c72 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/Parameters.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/MockObject/Rule/Parameters.php
@@ -18,6 +18,7 @@
 use PHPUnit\Framework\Constraint\IsEqual;
 use PHPUnit\Framework\ExpectationFailedException;
 use PHPUnit\Framework\MockObject\Invocation as BaseInvocation;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 
 /**
  * @internal This class is not covered by the backward compatibility promise for PHPUnit
@@ -92,8 +93,8 @@ public function apply(BaseInvocation $invocation): void
      * does the rule will get the invoked() method called which should check
      * if an expectation is met.
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
      * @throws ExpectationFailedException
+     * @throws InvalidArgumentException
      */
     public function verify(): void
     {
@@ -101,8 +102,8 @@ public function verify(): void
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
      * @throws ExpectationFailedException
+     * @throws InvalidArgumentException
      */
     private function doVerify(): bool
     {
diff --git a/app/vendor/phpunit/phpunit/src/Framework/SelfDescribing.php b/app/vendor/phpunit/phpunit/src/Framework/SelfDescribing.php
index 73034f650..6513f1439 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/SelfDescribing.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/SelfDescribing.php
@@ -10,7 +10,7 @@
 namespace PHPUnit\Framework;
 
 /**
- * @internal This class is not covered by the backward compatibility promise for PHPUnit
+ * @internal This interface is not covered by the backward compatibility promise for PHPUnit
  */
 interface SelfDescribing
 {
diff --git a/app/vendor/phpunit/phpunit/src/Framework/SkippedTestCase.php b/app/vendor/phpunit/phpunit/src/Framework/SkippedTestCase.php
index 6f8a267c0..49d73759b 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/SkippedTestCase.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/SkippedTestCase.php
@@ -9,6 +9,8 @@
  */
 namespace PHPUnit\Framework;
 
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
+
 /**
  * @internal This class is not covered by the backward compatibility promise for PHPUnit
  */
@@ -49,7 +51,7 @@ public function getMessage(): string
     /**
      * Returns a string representation of the test case.
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function toString(): string
     {
diff --git a/app/vendor/phpunit/phpunit/src/Framework/Test.php b/app/vendor/phpunit/phpunit/src/Framework/Test.php
index be0dcd0ef..2f218ad9f 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/Test.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/Test.php
@@ -19,5 +19,5 @@ interface Test extends Countable
     /**
      * Runs a test and collects its result in a TestResult instance.
      */
-    public function run(TestResult $result = null): TestResult;
+    public function run(?TestResult $result = null): TestResult;
 }
diff --git a/app/vendor/phpunit/phpunit/src/Framework/TestCase.php b/app/vendor/phpunit/phpunit/src/Framework/TestCase.php
index acb5cf40e..30dd5b954 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/TestCase.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/TestCase.php
@@ -98,12 +98,16 @@
 use PHPUnit\Util\GlobalState;
 use PHPUnit\Util\PHP\AbstractPhpProcess;
 use PHPUnit\Util\Test as TestUtil;
+use Prophecy\Exception\Doubler\ClassNotFoundException;
+use Prophecy\Exception\Doubler\DoubleException;
+use Prophecy\Exception\Doubler\InterfaceNotFoundException;
 use Prophecy\Exception\Prediction\PredictionException;
 use Prophecy\Prophecy\MethodProphecy;
 use Prophecy\Prophecy\ObjectProphecy;
 use Prophecy\Prophet;
 use ReflectionClass;
 use ReflectionException;
+use SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException;
 use SebastianBergmann\Comparator\Comparator;
 use SebastianBergmann\Comparator\Factory as ComparatorFactory;
 use SebastianBergmann\Diff\Differ;
@@ -112,6 +116,7 @@
 use SebastianBergmann\GlobalState\Restorer;
 use SebastianBergmann\GlobalState\Snapshot;
 use SebastianBergmann\ObjectEnumerator\Enumerator;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 use SebastianBergmann\Template\Template;
 use SoapClient;
 use Throwable;
@@ -545,8 +550,8 @@ protected function tearDown(): void
     /**
      * Returns a string representation of the test case.
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
      * @throws Exception
+     * @throws InvalidArgumentException
      */
     public function toString(): string
     {
@@ -594,7 +599,7 @@ public function expectOutputString(string $expectedString): void
     }
 
     /**
-     * @psalm-param class-string<\Throwable> $exception
+     * @psalm-param class-string $exception
      */
     public function expectException(string $exception): void
     {
@@ -807,12 +812,12 @@ public function hasFailed(): bool
      * If no TestResult object is passed a new one will be created.
      *
      * @throws \SebastianBergmann\CodeCoverage\InvalidArgumentException
-     * @throws \SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
      * @throws CodeCoverageException
+     * @throws InvalidArgumentException
+     * @throws UnintentionallyCoveredCodeException
      * @throws UtilException
      */
-    public function run(TestResult $result = null): TestResult
+    public function run(?TestResult $result = null): TestResult
     {
         if ($result === null) {
             $result = $this->createResult();
@@ -1023,7 +1028,7 @@ public function setGroups(array $groups): void
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @internal This method is not covered by the backward compatibility promise for PHPUnit
      */
@@ -1039,7 +1044,7 @@ public function getName(bool $withDataSet = true): string
     /**
      * Returns the size of the test.
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @internal This method is not covered by the backward compatibility promise for PHPUnit
      */
@@ -1052,7 +1057,7 @@ public function getSize(): int
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @internal This method is not covered by the backward compatibility promise for PHPUnit
      */
@@ -1062,7 +1067,7 @@ public function hasSize(): bool
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @internal This method is not covered by the backward compatibility promise for PHPUnit
      */
@@ -1072,7 +1077,7 @@ public function isSmall(): bool
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @internal This method is not covered by the backward compatibility promise for PHPUnit
      */
@@ -1082,7 +1087,7 @@ public function isMedium(): bool
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      *
      * @internal This method is not covered by the backward compatibility promise for PHPUnit
      */
@@ -2033,9 +2038,9 @@ protected function getObjectForTrait(string $traitName, array $arguments = [], s
     }
 
     /**
-     * @throws \Prophecy\Exception\Doubler\ClassNotFoundException
-     * @throws \Prophecy\Exception\Doubler\DoubleException
-     * @throws \Prophecy\Exception\Doubler\InterfaceNotFoundException
+     * @throws ClassNotFoundException
+     * @throws DoubleException
+     * @throws InterfaceNotFoundException
      *
      * @psalm-param class-string|null $classOrInterface
      *
@@ -2332,7 +2337,7 @@ private function snapshotGlobalState(): void
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws RiskyTestError
      */
     private function restoreGlobalState(): void
@@ -2428,7 +2433,7 @@ private function createGlobalStateSnapshot(bool $backupGlobals): Snapshot
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      * @throws RiskyTestError
      */
     private function compareGlobalStateSnapshots(Snapshot $before, Snapshot $after): void
@@ -2510,7 +2515,7 @@ private function shouldInvocationMockerBeReset(MockObject $mock): bool
     /**
      * @throws \SebastianBergmann\ObjectEnumerator\InvalidArgumentException
      * @throws \SebastianBergmann\ObjectReflector\InvalidArgumentException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     private function registerMockObjectsFromTestArguments(array $testArguments, array &$visited = []): void
     {
diff --git a/app/vendor/phpunit/phpunit/src/Framework/TestResult.php b/app/vendor/phpunit/phpunit/src/Framework/TestResult.php
index 2c487255f..29d9535f0 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/TestResult.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/TestResult.php
@@ -34,6 +34,7 @@
 use SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException;
 use SebastianBergmann\Invoker\Invoker;
 use SebastianBergmann\Invoker\TimeoutException;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 use SebastianBergmann\ResourceOperations\ResourceOperations;
 use SebastianBergmann\Timer\Timer;
 use Throwable;
@@ -444,7 +445,7 @@ public function startTest(Test $test): void
     /**
      * Informs the result that a test was completed.
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function endTest(Test $test, float $time): void
     {
@@ -634,8 +635,8 @@ public function getCollectCodeCoverageInformation(): bool
      * Runs a TestCase.
      *
      * @throws \SebastianBergmann\CodeCoverage\InvalidArgumentException
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
      * @throws CodeCoverageException
+     * @throws InvalidArgumentException
      * @throws UnintentionallyCoveredCodeException
      */
     public function run(Test $test): void
@@ -954,7 +955,7 @@ function_exists('xdebug_start_function_monitor');
                 $test,
                 new OutputError(
                     sprintf(
-                        'This test printed output: %s',
+                        'Test code or tested code printed unexpected output: %s',
                         $test->getActualOutput(),
                     ),
                 ),
diff --git a/app/vendor/phpunit/phpunit/src/Framework/TestSuite.php b/app/vendor/phpunit/phpunit/src/Framework/TestSuite.php
index c60678d02..3fa0ba525 100644
--- a/app/vendor/phpunit/phpunit/src/Framework/TestSuite.php
+++ b/app/vendor/phpunit/phpunit/src/Framework/TestSuite.php
@@ -44,6 +44,7 @@
 use ReflectionClass;
 use ReflectionException;
 use ReflectionMethod;
+use SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException;
 use Throwable;
 
 /**
@@ -594,12 +595,12 @@ public function setGroupDetails(array $groups): void
      * Runs the tests and collects their result in a TestResult.
      *
      * @throws \SebastianBergmann\CodeCoverage\InvalidArgumentException
-     * @throws \SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException
      * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
      * @throws CodeCoverageException
+     * @throws UnintentionallyCoveredCodeException
      * @throws Warning
      */
-    public function run(TestResult $result = null): TestResult
+    public function run(?TestResult $result = null): TestResult
     {
         if ($result === null) {
             $result = $this->createResult();
diff --git a/app/vendor/phpunit/phpunit/src/Runner/Filter/Factory.php b/app/vendor/phpunit/phpunit/src/Runner/Filter/Factory.php
index b7d83b9f8..4880470ea 100644
--- a/app/vendor/phpunit/phpunit/src/Runner/Filter/Factory.php
+++ b/app/vendor/phpunit/phpunit/src/Runner/Filter/Factory.php
@@ -24,7 +24,7 @@
 final class Factory
 {
     /**
-     * @psalm-var array
+     * @psalm-var array
      */
     private $filters = [];
 
diff --git a/app/vendor/phpunit/phpunit/src/Runner/Filter/NameFilterIterator.php b/app/vendor/phpunit/phpunit/src/Runner/Filter/NameFilterIterator.php
index 45c62f056..80ab5817d 100644
--- a/app/vendor/phpunit/phpunit/src/Runner/Filter/NameFilterIterator.php
+++ b/app/vendor/phpunit/phpunit/src/Runner/Filter/NameFilterIterator.php
@@ -19,8 +19,10 @@
 use PHPUnit\Framework\TestSuite;
 use PHPUnit\Framework\WarningTestCase;
 use PHPUnit\Util\RegularExpression;
+use PHPUnit\Util\Test;
 use RecursiveFilterIterator;
 use RecursiveIterator;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 
 /**
  * @internal This class is not covered by the backward compatibility promise for PHPUnit
@@ -53,7 +55,7 @@ public function __construct(RecursiveIterator $iterator, string $filter)
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function accept(): bool
     {
@@ -63,7 +65,7 @@ public function accept(): bool
             return true;
         }
 
-        $tmp = \PHPUnit\Util\Test::describe($test);
+        $tmp = Test::describe($test);
 
         if ($test instanceof ErrorTestCase || $test instanceof WarningTestCase) {
             $name = $test->getMessage();
diff --git a/app/vendor/phpunit/phpunit/src/Runner/PhptTestCase.php b/app/vendor/phpunit/phpunit/src/Runner/PhptTestCase.php
index 988b0ece4..b345dfc4f 100644
--- a/app/vendor/phpunit/phpunit/src/Runner/PhptTestCase.php
+++ b/app/vendor/phpunit/phpunit/src/Runner/PhptTestCase.php
@@ -55,7 +55,9 @@
 use PHPUnit\Framework\Test;
 use PHPUnit\Framework\TestResult;
 use PHPUnit\Util\PHP\AbstractPhpProcess;
+use SebastianBergmann\CodeCoverage\InvalidArgumentException;
 use SebastianBergmann\CodeCoverage\RawCodeCoverageData;
+use SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException;
 use SebastianBergmann\Template\Template;
 use SebastianBergmann\Timer\Timer;
 use Throwable;
@@ -85,7 +87,7 @@ final class PhptTestCase implements Reorderable, SelfDescribing, Test
      *
      * @throws Exception
      */
-    public function __construct(string $filename, AbstractPhpProcess $phpUtil = null)
+    public function __construct(string $filename, ?AbstractPhpProcess $phpUtil = null)
     {
         if (!is_file($filename)) {
             throw new Exception(
@@ -111,12 +113,12 @@ public function count(): int
     /**
      * Runs a test and collects its result in a TestResult instance.
      *
-     * @throws \SebastianBergmann\CodeCoverage\InvalidArgumentException
-     * @throws \SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException
      * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
      * @throws Exception
+     * @throws InvalidArgumentException
+     * @throws UnintentionallyCoveredCodeException
      */
-    public function run(TestResult $result = null): TestResult
+    public function run(?TestResult $result = null): TestResult
     {
         if ($result === null) {
             $result = new TestResult;
@@ -343,7 +345,7 @@ private function parseEnvSection(string $content): array
         foreach (explode("\n", trim($content)) as $e) {
             $e = explode('=', trim($e), 2);
 
-            if (!empty($e[0]) && isset($e[1])) {
+            if ($e[0] !== '' && isset($e[1])) {
                 $env[$e[0]] = $e[1];
             }
         }
diff --git a/app/vendor/phpunit/phpunit/src/Runner/TestSuiteSorter.php b/app/vendor/phpunit/phpunit/src/Runner/TestSuiteSorter.php
index 9ec82b600..a48a7db61 100644
--- a/app/vendor/phpunit/phpunit/src/Runner/TestSuiteSorter.php
+++ b/app/vendor/phpunit/phpunit/src/Runner/TestSuiteSorter.php
@@ -24,6 +24,7 @@
 use PHPUnit\Framework\TestCase;
 use PHPUnit\Framework\TestSuite;
 use PHPUnit\Util\Test as TestUtil;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 
 /**
  * @internal This class is not covered by the backward compatibility promise for PHPUnit
@@ -108,8 +109,8 @@ public function __construct(?TestResultCache $cache = null)
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
      * @throws Exception
+     * @throws InvalidArgumentException
      */
     public function reorderTestsInSuite(Test $suite, int $order, bool $resolveDependencies, int $orderDefects, bool $isRootTestSuite = true): void
     {
@@ -198,7 +199,7 @@ private function sort(TestSuite $suite, int $order, bool $resolveDependencies, i
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     private function addSuiteToDefectSortOrder(TestSuite $suite): void
     {
@@ -235,7 +236,7 @@ private function sortDefectsFirst(array $tests): array
         usort(
             $tests,
             /**
-             * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+             * @throws InvalidArgumentException
              */
             function ($left, $right)
             {
@@ -251,7 +252,7 @@ private function sortByDuration(array $tests): array
         usort(
             $tests,
             /**
-             * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+             * @throws InvalidArgumentException
              */
             function ($left, $right)
             {
@@ -267,7 +268,7 @@ private function sortBySize(array $tests): array
         usort(
             $tests,
             /**
-             * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+             * @throws InvalidArgumentException
              */
             function ($left, $right)
             {
@@ -285,7 +286,7 @@ function ($left, $right)
      * 2. when tests are equally defective, sort the fastest to the front
      * 3. do not reorder successful tests
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     private function cmpDefectPriorityAndTime(Test $a, Test $b): int
     {
@@ -312,7 +313,7 @@ private function cmpDefectPriorityAndTime(Test $a, Test $b): int
     /**
      * Compares test duration for sorting tests by duration ascending.
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     private function cmpDuration(Test $a, Test $b): int
     {
@@ -373,7 +374,7 @@ private function resolveDependencies(array $tests): array
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     private function calculateTestExecutionOrder(Test $suite): array
     {
diff --git a/app/vendor/phpunit/phpunit/src/Runner/Version.php b/app/vendor/phpunit/phpunit/src/Runner/Version.php
index ba589b2aa..9b9959295 100644
--- a/app/vendor/phpunit/phpunit/src/Runner/Version.php
+++ b/app/vendor/phpunit/phpunit/src/Runner/Version.php
@@ -44,7 +44,7 @@ public static function id(): string
         }
 
         if (self::$version === '') {
-            self::$version = (new VersionId('9.6.17', dirname(__DIR__, 2)))->getVersion();
+            self::$version = (new VersionId('9.6.23', dirname(__DIR__, 2)))->getVersion();
 
             assert(!empty(self::$version));
         }
diff --git a/app/vendor/phpunit/phpunit/src/TextUI/Command.php b/app/vendor/phpunit/phpunit/src/TextUI/Command.php
index b656b0fc8..7b963f0a7 100644
--- a/app/vendor/phpunit/phpunit/src/TextUI/Command.php
+++ b/app/vendor/phpunit/phpunit/src/TextUI/Command.php
@@ -61,6 +61,7 @@
 use ReflectionClass;
 use SebastianBergmann\CodeCoverage\Filter;
 use SebastianBergmann\CodeCoverage\StaticAnalysis\CacheWarmer;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 use SebastianBergmann\Timer\Timer;
 use Throwable;
 
@@ -737,7 +738,7 @@ private function handleListSuites(bool $exit): int
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     private function handleListTests(TestSuite $suite, bool $exit): int
     {
@@ -764,7 +765,7 @@ private function handleListTests(TestSuite $suite, bool $exit): int
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     private function handleListTestsXml(TestSuite $suite, string $target, bool $exit): int
     {
diff --git a/app/vendor/phpunit/phpunit/src/TextUI/TestRunner.php b/app/vendor/phpunit/phpunit/src/TextUI/TestRunner.php
index 8907c470a..1b23a3dcf 100644
--- a/app/vendor/phpunit/phpunit/src/TextUI/TestRunner.php
+++ b/app/vendor/phpunit/phpunit/src/TextUI/TestRunner.php
@@ -122,7 +122,7 @@ final class TestRunner extends BaseTestRunner
      */
     private $timer;
 
-    public function __construct(TestSuiteLoader $loader = null, CodeCoverageFilter $filter = null)
+    public function __construct(?TestSuiteLoader $loader = null, ?CodeCoverageFilter $filter = null)
     {
         if ($filter === null) {
             $filter = new CodeCoverageFilter;
diff --git a/app/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Loader.php b/app/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Loader.php
index 7a7786b68..fa677212c 100644
--- a/app/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Loader.php
+++ b/app/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Loader.php
@@ -50,6 +50,7 @@
 use PHPUnit\TextUI\XmlConfiguration\Logging\TestDox\Xml as TestDoxXml;
 use PHPUnit\TextUI\XmlConfiguration\Logging\Text;
 use PHPUnit\TextUI\XmlConfiguration\TestSuite as TestSuiteConfiguration;
+use PHPUnit\TextUI\XmlConfigurationTest;
 use PHPUnit\Util\TestDox\CliTestDoxPrinter;
 use PHPUnit\Util\VersionComparisonOperator;
 use PHPUnit\Util\Xml;
@@ -702,7 +703,7 @@ private function legacyCodeCoverage(string $filename, DOMXPath $xpath, DOMDocume
      * If $value is 'false' or 'true', this returns the value that $value represents.
      * Otherwise, returns $default, which may be a string in rare cases.
      *
-     * @see \PHPUnit\TextUI\XmlConfigurationTest::testPHPConfigurationIsReadCorrectly
+     * @see XmlConfigurationTest::testPHPConfigurationIsReadCorrectly
      *
      * @param bool|string $default
      *
diff --git a/app/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/MigrationBuilderException.php b/app/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/MigrationBuilderException.php
index 3d3c767af..ebee6e917 100644
--- a/app/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/MigrationBuilderException.php
+++ b/app/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/MigrationBuilderException.php
@@ -9,11 +9,12 @@
  */
 namespace PHPUnit\TextUI\XmlConfiguration;
 
+use PHPUnit\Exception;
 use RuntimeException;
 
 /**
  * @internal This class is not covered by the backward compatibility promise for PHPUnit
  */
-final class MigrationBuilderException extends RuntimeException implements \PHPUnit\Exception
+final class MigrationBuilderException extends RuntimeException implements Exception
 {
 }
diff --git a/app/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/MigrationException.php b/app/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/MigrationException.php
index f92b2db30..9fa4068ce 100644
--- a/app/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/MigrationException.php
+++ b/app/vendor/phpunit/phpunit/src/TextUI/XmlConfiguration/Migration/MigrationException.php
@@ -9,11 +9,12 @@
  */
 namespace PHPUnit\TextUI\XmlConfiguration;
 
+use PHPUnit\Exception;
 use RuntimeException;
 
 /**
  * @internal This class is not covered by the backward compatibility promise for PHPUnit
  */
-final class MigrationException extends RuntimeException implements \PHPUnit\Exception
+final class MigrationException extends RuntimeException implements Exception
 {
 }
diff --git a/app/vendor/phpunit/phpunit/src/Util/ErrorHandler.php b/app/vendor/phpunit/phpunit/src/Util/ErrorHandler.php
index 3bdf9bf1d..f28c89646 100644
--- a/app/vendor/phpunit/phpunit/src/Util/ErrorHandler.php
+++ b/app/vendor/phpunit/phpunit/src/Util/ErrorHandler.php
@@ -11,11 +11,11 @@
 
 use const E_DEPRECATED;
 use const E_NOTICE;
-use const E_STRICT;
 use const E_USER_DEPRECATED;
 use const E_USER_NOTICE;
 use const E_USER_WARNING;
 use const E_WARNING;
+use function defined;
 use function error_reporting;
 use function restore_error_handler;
 use function set_error_handler;
@@ -93,10 +93,18 @@ public function __invoke(int $errorNumber, string $errorString, string $errorFil
             return false;
         }
 
+        /**
+         * E_STRICT is deprecated since PHP 8.4.
+         *
+         * @see https://github.com/sebastianbergmann/phpunit/issues/5956
+         */
+        if (defined('E_STRICT') && $errorNumber === 2048) {
+            $errorNumber = E_NOTICE;
+        }
+
         switch ($errorNumber) {
             case E_NOTICE:
             case E_USER_NOTICE:
-            case E_STRICT:
                 if (!$this->convertNoticesToExceptions) {
                     return false;
                 }
diff --git a/app/vendor/phpunit/phpunit/src/Util/InvalidDataSetException.php b/app/vendor/phpunit/phpunit/src/Util/InvalidDataSetException.php
index 3493d113a..13dcc0e09 100644
--- a/app/vendor/phpunit/phpunit/src/Util/InvalidDataSetException.php
+++ b/app/vendor/phpunit/phpunit/src/Util/InvalidDataSetException.php
@@ -9,11 +9,12 @@
  */
 namespace PHPUnit\Util;
 
+use PHPUnit\Exception;
 use RuntimeException;
 
 /**
  * @internal This class is not covered by the backward compatibility promise for PHPUnit
  */
-final class InvalidDataSetException extends RuntimeException implements \PHPUnit\Exception
+final class InvalidDataSetException extends RuntimeException implements Exception
 {
 }
diff --git a/app/vendor/phpunit/phpunit/src/Util/Log/TeamCity.php b/app/vendor/phpunit/phpunit/src/Util/Log/TeamCity.php
index 30375bd3c..3ba687a11 100644
--- a/app/vendor/phpunit/phpunit/src/Util/Log/TeamCity.php
+++ b/app/vendor/phpunit/phpunit/src/Util/Log/TeamCity.php
@@ -9,6 +9,7 @@
  */
 namespace PHPUnit\Util\Log;
 
+use const PHP_EOL;
 use function class_exists;
 use function count;
 use function explode;
diff --git a/app/vendor/phpunit/phpunit/src/Util/PHP/AbstractPhpProcess.php b/app/vendor/phpunit/phpunit/src/Util/PHP/AbstractPhpProcess.php
index 0405d1f33..9620846a6 100644
--- a/app/vendor/phpunit/phpunit/src/Util/PHP/AbstractPhpProcess.php
+++ b/app/vendor/phpunit/phpunit/src/Util/PHP/AbstractPhpProcess.php
@@ -38,6 +38,7 @@
 use PHPUnit\Framework\TestFailure;
 use PHPUnit\Framework\TestResult;
 use SebastianBergmann\Environment\Runtime;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 
 /**
  * @internal This class is not covered by the backward compatibility promise for PHPUnit
@@ -175,7 +176,7 @@ public function getTimeout(): int
     /**
      * Runs a single test in a separate PHP process.
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function runTestJob(string $job, Test $test, TestResult $result, string $processResultFile): void
     {
@@ -201,7 +202,7 @@ public function runTestJob(string $job, Test $test, TestResult $result, string $
     /**
      * Returns the command based into the configurations.
      */
-    public function getCommand(array $settings, string $file = null): string
+    public function getCommand(array $settings, ?string $file = null): string
     {
         $command = $this->runtime->getBinary();
 
@@ -268,7 +269,7 @@ protected function settingsToParameters(array $settings): string
     /**
      * Processes the TestResult object from an isolated process.
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     private function processChildResult(Test $test, TestResult $result, string $stdout, string $stderr): void
     {
diff --git a/app/vendor/phpunit/phpunit/src/Util/PHP/WindowsPhpProcess.php b/app/vendor/phpunit/phpunit/src/Util/PHP/WindowsPhpProcess.php
index 2480bc8c1..338fea717 100644
--- a/app/vendor/phpunit/phpunit/src/Util/PHP/WindowsPhpProcess.php
+++ b/app/vendor/phpunit/phpunit/src/Util/PHP/WindowsPhpProcess.php
@@ -20,7 +20,7 @@
  */
 final class WindowsPhpProcess extends DefaultPhpProcess
 {
-    public function getCommand(array $settings, string $file = null): string
+    public function getCommand(array $settings, ?string $file = null): string
     {
         if (PHP_MAJOR_VERSION < 8) {
             return '"' . parent::getCommand($settings, $file) . '"';
diff --git a/app/vendor/phpunit/phpunit/src/Util/Test.php b/app/vendor/phpunit/phpunit/src/Util/Test.php
index 12c6bf16a..4d6319b9d 100644
--- a/app/vendor/phpunit/phpunit/src/Util/Test.php
+++ b/app/vendor/phpunit/phpunit/src/Util/Test.php
@@ -52,6 +52,7 @@
 use SebastianBergmann\CodeUnit\InvalidCodeUnitException;
 use SebastianBergmann\CodeUnit\Mapper;
 use SebastianBergmann\Environment\OperatingSystem;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 
 /**
  * @internal This class is not covered by the backward compatibility promise for PHPUnit
@@ -84,7 +85,7 @@ final class Test
     private static $hookMethods = [];
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public static function describe(\PHPUnit\Framework\Test $test): array
     {
diff --git a/app/vendor/phpunit/phpunit/src/Util/TestDox/CliTestDoxPrinter.php b/app/vendor/phpunit/phpunit/src/Util/TestDox/CliTestDoxPrinter.php
index 031c7ed63..3348957de 100644
--- a/app/vendor/phpunit/phpunit/src/Util/TestDox/CliTestDoxPrinter.php
+++ b/app/vendor/phpunit/phpunit/src/Util/TestDox/CliTestDoxPrinter.php
@@ -21,12 +21,16 @@
 use function strlen;
 use function strpos;
 use function trim;
+use PHPUnit\Framework\Exception;
 use PHPUnit\Framework\Test;
 use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\TestFailure;
 use PHPUnit\Framework\TestResult;
 use PHPUnit\Runner\BaseTestRunner;
 use PHPUnit\Runner\PhptTestCase;
 use PHPUnit\Util\Color;
+use PHPUnit\Util\Filter;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 use SebastianBergmann\Timer\ResourceUsageFormatter;
 use SebastianBergmann\Timer\Timer;
 use Throwable;
@@ -122,7 +126,7 @@ class CliTestDoxPrinter extends TestDoxPrinter
      * @param null|resource|string $out
      * @param int|string           $numberOfColumns
      *
-     * @throws \PHPUnit\Framework\Exception
+     * @throws Exception
      */
     public function __construct($out = null, bool $verbose = false, string $colors = self::COLOR_DEFAULT, bool $debug = false, $numberOfColumns = 80, bool $reverse = false)
     {
@@ -157,7 +161,7 @@ protected function formatClassName(Test $test): string
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     protected function registerTestResult(Test $test, ?Throwable $t, int $status, float $time, bool $verbose): void
     {
@@ -169,7 +173,7 @@ protected function registerTestResult(Test $test, ?Throwable $t, int $status, fl
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     protected function formatTestName(Test $test): string
     {
@@ -216,7 +220,7 @@ protected function writeTestResult(array $prevResult, array $result): void
 
     protected function formatThrowable(Throwable $t, ?int $status = null): string
     {
-        return trim(\PHPUnit\Framework\TestFailure::exceptionToString($t));
+        return trim(TestFailure::exceptionToString($t));
     }
 
     protected function colorizeMessageAndDiff(string $style, string $buffer): array
@@ -255,7 +259,7 @@ protected function colorizeMessageAndDiff(string $style, string $buffer): array
 
     protected function formatStacktrace(Throwable $t): string
     {
-        $trace = \PHPUnit\Util\Filter::getFilteredStacktrace($t);
+        $trace = Filter::getFilteredStacktrace($t);
 
         if (!$this->colors) {
             return $trace;
diff --git a/app/vendor/phpunit/phpunit/src/Util/TestDox/NamePrettifier.php b/app/vendor/phpunit/phpunit/src/Util/TestDox/NamePrettifier.php
index ee0a41b1c..f67cff68b 100644
--- a/app/vendor/phpunit/phpunit/src/Util/TestDox/NamePrettifier.php
+++ b/app/vendor/phpunit/phpunit/src/Util/TestDox/NamePrettifier.php
@@ -46,6 +46,7 @@
 use ReflectionMethod;
 use ReflectionObject;
 use SebastianBergmann\Exporter\Exporter;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 
 /**
  * @internal This class is not covered by the backward compatibility promise for PHPUnit
@@ -118,7 +119,7 @@ public function prettifyTestClass(string $className): string
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function prettifyTestCase(TestCase $test): string
     {
@@ -232,7 +233,7 @@ public function prettifyTestMethod(string $name): string
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     private function mapTestMethodParameterNamesToProvidedDataValues(TestCase $test): array
     {
diff --git a/app/vendor/phpunit/phpunit/src/Util/TestDox/ResultPrinter.php b/app/vendor/phpunit/phpunit/src/Util/TestDox/ResultPrinter.php
index c4b63644f..841279e8e 100644
--- a/app/vendor/phpunit/phpunit/src/Util/TestDox/ResultPrinter.php
+++ b/app/vendor/phpunit/phpunit/src/Util/TestDox/ResultPrinter.php
@@ -13,6 +13,7 @@
 use function in_array;
 use PHPUnit\Framework\AssertionFailedError;
 use PHPUnit\Framework\ErrorTestCase;
+use PHPUnit\Framework\Exception;
 use PHPUnit\Framework\Test;
 use PHPUnit\Framework\TestCase;
 use PHPUnit\Framework\TestSuite;
@@ -21,6 +22,7 @@
 use PHPUnit\Runner\BaseTestRunner;
 use PHPUnit\TextUI\ResultPrinter as ResultPrinterInterface;
 use PHPUnit\Util\Printer;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 use Throwable;
 
 /**
@@ -101,7 +103,7 @@ abstract class ResultPrinter extends Printer implements ResultPrinterInterface
     /**
      * @param resource $out
      *
-     * @throws \PHPUnit\Framework\Exception
+     * @throws Exception
      */
     public function __construct($out = null, array $groups = [], array $excludeGroups = [])
     {
@@ -220,7 +222,7 @@ public function endTestSuite(TestSuite $suite): void
     /**
      * A test started.
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function startTest(Test $test): void
     {
diff --git a/app/vendor/phpunit/phpunit/src/Util/TestDox/TestDoxPrinter.php b/app/vendor/phpunit/phpunit/src/Util/TestDox/TestDoxPrinter.php
index 5a418998d..9e1fdab1a 100644
--- a/app/vendor/phpunit/phpunit/src/Util/TestDox/TestDoxPrinter.php
+++ b/app/vendor/phpunit/phpunit/src/Util/TestDox/TestDoxPrinter.php
@@ -17,15 +17,19 @@
 use function preg_split;
 use function trim;
 use PHPUnit\Framework\AssertionFailedError;
+use PHPUnit\Framework\Exception;
 use PHPUnit\Framework\Reorderable;
 use PHPUnit\Framework\Test;
 use PHPUnit\Framework\TestCase;
+use PHPUnit\Framework\TestFailure;
 use PHPUnit\Framework\TestResult;
 use PHPUnit\Framework\TestSuite;
 use PHPUnit\Framework\Warning;
 use PHPUnit\Runner\BaseTestRunner;
 use PHPUnit\Runner\PhptTestCase;
 use PHPUnit\TextUI\DefaultResultPrinter;
+use PHPUnit\Util\Filter;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 use Throwable;
 
 /**
@@ -82,7 +86,7 @@ class TestDoxPrinter extends DefaultResultPrinter
      * @param null|resource|string $out
      * @param int|string           $numberOfColumns
      *
-     * @throws \PHPUnit\Framework\Exception
+     * @throws Exception
      */
     public function __construct($out = null, bool $verbose = false, string $colors = self::COLOR_DEFAULT, bool $debug = false, $numberOfColumns = 80, bool $reverse = false)
     {
@@ -107,7 +111,7 @@ public function printResult(TestResult $result): void
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function endTest(Test $test, float $time): void
     {
@@ -127,7 +131,7 @@ public function endTest(Test $test, float $time): void
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function addError(Test $test, Throwable $t, float $time): void
     {
@@ -135,7 +139,7 @@ public function addError(Test $test, Throwable $t, float $time): void
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function addWarning(Test $test, Warning $e, float $time): void
     {
@@ -143,7 +147,7 @@ public function addWarning(Test $test, Warning $e, float $time): void
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function addFailure(Test $test, AssertionFailedError $e, float $time): void
     {
@@ -151,7 +155,7 @@ public function addFailure(Test $test, AssertionFailedError $e, float $time): vo
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function addIncompleteTest(Test $test, Throwable $t, float $time): void
     {
@@ -159,7 +163,7 @@ public function addIncompleteTest(Test $test, Throwable $t, float $time): void
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function addRiskyTest(Test $test, Throwable $t, float $time): void
     {
@@ -167,7 +171,7 @@ public function addRiskyTest(Test $test, Throwable $t, float $time): void
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function addSkippedTest(Test $test, Throwable $t, float $time): void
     {
@@ -185,7 +189,7 @@ public function flush(): void
     }
 
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     protected function registerTestResult(Test $test, ?Throwable $t, int $status, float $time, bool $verbose): void
     {
@@ -339,7 +343,7 @@ protected function getTestResultByName(?string $testName): array
 
     protected function formatThrowable(Throwable $t, ?int $status = null): string
     {
-        $message = trim(\PHPUnit\Framework\TestFailure::exceptionToString($t));
+        $message = trim(TestFailure::exceptionToString($t));
 
         if ($message) {
             $message .= PHP_EOL . PHP_EOL . $this->formatStacktrace($t);
@@ -352,7 +356,7 @@ protected function formatThrowable(Throwable $t, ?int $status = null): string
 
     protected function formatStacktrace(Throwable $t): string
     {
-        return \PHPUnit\Util\Filter::getFilteredStacktrace($t);
+        return Filter::getFilteredStacktrace($t);
     }
 
     protected function formatTestResultMessage(Throwable $t, array $result, string $prefix = '│'): string
diff --git a/app/vendor/phpunit/phpunit/src/Util/TestDox/XmlResultPrinter.php b/app/vendor/phpunit/phpunit/src/Util/TestDox/XmlResultPrinter.php
index 84d4d37ca..10b7bff76 100644
--- a/app/vendor/phpunit/phpunit/src/Util/TestDox/XmlResultPrinter.php
+++ b/app/vendor/phpunit/phpunit/src/Util/TestDox/XmlResultPrinter.php
@@ -27,6 +27,7 @@
 use PHPUnit\Util\Test as TestUtil;
 use ReflectionClass;
 use ReflectionException;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 use Throwable;
 
 /**
@@ -151,7 +152,7 @@ public function startTest(Test $test): void
     /**
      * A test ended.
      *
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function endTest(Test $test, float $time): void
     {
diff --git a/app/vendor/phpunit/phpunit/src/Util/TextTestListRenderer.php b/app/vendor/phpunit/phpunit/src/Util/TextTestListRenderer.php
index beb0e4b07..c9f8af16b 100644
--- a/app/vendor/phpunit/phpunit/src/Util/TextTestListRenderer.php
+++ b/app/vendor/phpunit/phpunit/src/Util/TextTestListRenderer.php
@@ -17,6 +17,7 @@
 use PHPUnit\Framework\TestSuite;
 use PHPUnit\Runner\PhptTestCase;
 use RecursiveIteratorIterator;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 
 /**
  * @internal This class is not covered by the backward compatibility promise for PHPUnit
@@ -24,7 +25,7 @@
 final class TextTestListRenderer
 {
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function render(TestSuite $suite): string
     {
diff --git a/app/vendor/phpunit/phpunit/src/Util/Xml/ValidationResult.php b/app/vendor/phpunit/phpunit/src/Util/Xml/ValidationResult.php
index 3292267bd..a44b309ca 100644
--- a/app/vendor/phpunit/phpunit/src/Util/Xml/ValidationResult.php
+++ b/app/vendor/phpunit/phpunit/src/Util/Xml/ValidationResult.php
@@ -9,6 +9,7 @@
  */
 namespace PHPUnit\Util\Xml;
 
+use const PHP_EOL;
 use function sprintf;
 use function trim;
 
diff --git a/app/vendor/phpunit/phpunit/src/Util/XmlTestListRenderer.php b/app/vendor/phpunit/phpunit/src/Util/XmlTestListRenderer.php
index 7a63b10d4..2ed6559fe 100644
--- a/app/vendor/phpunit/phpunit/src/Util/XmlTestListRenderer.php
+++ b/app/vendor/phpunit/phpunit/src/Util/XmlTestListRenderer.php
@@ -16,6 +16,7 @@
 use PHPUnit\Framework\TestSuite;
 use PHPUnit\Runner\PhptTestCase;
 use RecursiveIteratorIterator;
+use SebastianBergmann\RecursionContext\InvalidArgumentException;
 use XMLWriter;
 
 /**
@@ -24,7 +25,7 @@
 final class XmlTestListRenderer
 {
     /**
-     * @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
+     * @throws InvalidArgumentException
      */
     public function render(TestSuite $suite): string
     {
diff --git a/app/vendor/psy/psysh/src/CodeCleaner.php b/app/vendor/psy/psysh/src/CodeCleaner.php
index 0d9900b8d..9cde20fe0 100644
--- a/app/vendor/psy/psysh/src/CodeCleaner.php
+++ b/app/vendor/psy/psysh/src/CodeCleaner.php
@@ -48,13 +48,13 @@
  */
 class CodeCleaner
 {
-    private $yolo = false;
-    private $strictTypes = false;
+    private bool $yolo = false;
+    private bool $strictTypes = false;
 
-    private $parser;
-    private $printer;
-    private $traverser;
-    private $namespace;
+    private Parser $parser;
+    private Printer $printer;
+    private NodeTraverser $traverser;
+    private ?array $namespace = null;
 
     /**
      * CodeCleaner constructor.
@@ -65,7 +65,7 @@ class CodeCleaner
      * @param bool               $yolo        run without input validation
      * @param bool               $strictTypes enforce strict types by default
      */
-    public function __construct(Parser $parser = null, Printer $printer = null, NodeTraverser $traverser = null, bool $yolo = false, bool $strictTypes = false)
+    public function __construct(?Parser $parser = null, ?Printer $printer = null, ?NodeTraverser $traverser = null, bool $yolo = false, bool $strictTypes = false)
     {
         $this->yolo = $yolo;
         $this->strictTypes = $strictTypes;
@@ -94,10 +94,6 @@ public function yolo(): bool
      */
     private function getDefaultPasses(): array
     {
-        if ($this->yolo) {
-            return $this->getYoloPasses();
-        }
-
         $useStatementPass = new UseStatementPass();
         $namespacePass = new NamespacePass($this);
 
@@ -105,6 +101,25 @@ private function getDefaultPasses(): array
         // based on the file in which the `debug` call was made.
         $this->addImplicitDebugContext([$useStatementPass, $namespacePass]);
 
+        // A set of code cleaner passes that don't try to do any validation, and
+        // only do minimal rewriting to make things work inside the REPL.
+        //
+        // When in --yolo mode, these are the only code cleaner passes used.
+        $rewritePasses = [
+            new LeavePsyshAlonePass(),
+            $useStatementPass,        // must run before the namespace pass
+            new ExitPass(),
+            new ImplicitReturnPass(),
+            new MagicConstantsPass(),
+            $namespacePass,           // must run after the implicit return pass
+            new RequirePass(),
+            new StrictTypesPass($this->strictTypes),
+        ];
+
+        if ($this->yolo) {
+            return $rewritePasses;
+        }
+
         return [
             // Validation passes
             new AbstractClassPass(),
@@ -116,7 +131,6 @@ private function getDefaultPasses(): array
             new FunctionReturnInWriteContextPass(),
             new IssetPass(),
             new LabelContextPass(),
-            new LeavePsyshAlonePass(),
             new ListPass(),
             new LoopContextPass(),
             new PassableByReferencePass(),
@@ -125,13 +139,7 @@ private function getDefaultPasses(): array
             new ValidConstructorPass(),
 
             // Rewriting shenanigans
-            $useStatementPass,        // must run before the namespace pass
-            new ExitPass(),
-            new ImplicitReturnPass(),
-            new MagicConstantsPass(),
-            $namespacePass,           // must run after the implicit return pass
-            new RequirePass(),
-            new StrictTypesPass($this->strictTypes),
+            ...$rewritePasses,
 
             // Namespace-aware validation (which depends on aforementioned shenanigans)
             new ValidClassNamePass(),
@@ -139,36 +147,6 @@ private function getDefaultPasses(): array
         ];
     }
 
-    /**
-     * A set of code cleaner passes that don't try to do any validation, and
-     * only do minimal rewriting to make things work inside the REPL.
-     *
-     * This list should stay in sync with the "rewriting shenanigans" in
-     * getDefaultPasses above.
-     *
-     * @return CodeCleanerPass[]
-     */
-    private function getYoloPasses(): array
-    {
-        $useStatementPass = new UseStatementPass();
-        $namespacePass = new NamespacePass($this);
-
-        // Try to add implicit `use` statements and an implicit namespace,
-        // based on the file in which the `debug` call was made.
-        $this->addImplicitDebugContext([$useStatementPass, $namespacePass]);
-
-        return [
-            new LeavePsyshAlonePass(),
-            $useStatementPass,        // must run before the namespace pass
-            new ExitPass(),
-            new ImplicitReturnPass(),
-            new MagicConstantsPass(),
-            $namespacePass,           // must run after the implicit return pass
-            new RequirePass(),
-            new StrictTypesPass($this->strictTypes),
-        ];
-    }
-
     /**
      * "Warm up" code cleaner passes when we're coming from a debug call.
      *
@@ -197,6 +175,7 @@ private function addImplicitDebugContext(array $passes)
             }
 
             // Set up a clean traverser for just these code cleaner passes
+            // @todo Pass visitors directly to once we drop support for PHP-Parser 4.x
             $traverser = new NodeTraverser();
             foreach ($passes as $pass) {
                 $traverser->addVisitor($pass);
@@ -280,10 +259,8 @@ public function clean(array $codeLines, bool $requireSemicolons = false)
 
     /**
      * Set the current local namespace.
-     *
-     * @param array|null $namespace (default: null)
      */
-    public function setNamespace(array $namespace = null)
+    public function setNamespace(?array $namespace = null)
     {
         $this->namespace = $namespace;
     }
@@ -306,9 +283,6 @@ public function getNamespace()
      * @throws ParseErrorException for parse errors that can't be resolved by
      *                             waiting a line to see what comes next
      *
-     * @param string $code
-     * @param bool   $requireSemicolons
-     *
      * @return array|false A set of statements, or false if incomplete
      */
     protected function parse(string $code, bool $requireSemicolons = false)
@@ -358,9 +332,6 @@ private function parseErrorIsEOF(\PhpParser\Error $e): bool
      * Unlike (all?) other unclosed statements, single quoted strings have
      * their own special beautiful snowflake syntax error just for
      * themselves.
-     *
-     * @param \PhpParser\Error $e
-     * @param string           $code
      */
     private function parseErrorIsUnclosedString(\PhpParser\Error $e, string $code): bool
     {
@@ -377,12 +348,12 @@ private function parseErrorIsUnclosedString(\PhpParser\Error $e, string $code):
         return true;
     }
 
-    private function parseErrorIsUnterminatedComment(\PhpParser\Error $e, $code): bool
+    private function parseErrorIsUnterminatedComment(\PhpParser\Error $e, string $code): bool
     {
         return $e->getRawMessage() === 'Unterminated comment';
     }
 
-    private function parseErrorIsTrailingComma(\PhpParser\Error $e, $code): bool
+    private function parseErrorIsTrailingComma(\PhpParser\Error $e, string $code): bool
     {
         return ($e->getRawMessage() === 'A trailing comma is not allowed here') && (\substr(\rtrim($code), -1) === ',');
     }
diff --git a/app/vendor/psy/psysh/src/CodeCleaner/AbstractClassPass.php b/app/vendor/psy/psysh/src/CodeCleaner/AbstractClassPass.php
index 5b491ceb9..eed1e8df3 100644
--- a/app/vendor/psy/psysh/src/CodeCleaner/AbstractClassPass.php
+++ b/app/vendor/psy/psysh/src/CodeCleaner/AbstractClassPass.php
@@ -21,8 +21,8 @@
  */
 class AbstractClassPass extends CodeCleanerPass
 {
-    private $class;
-    private $abstractMethods;
+    private Class_ $class;
+    private array $abstractMethods;
 
     /**
      * @throws FatalErrorException if the node is an abstract function with a body
diff --git a/app/vendor/psy/psysh/src/CodeCleaner/CalledClassPass.php b/app/vendor/psy/psysh/src/CodeCleaner/CalledClassPass.php
index 441685f97..0ec0c0106 100644
--- a/app/vendor/psy/psysh/src/CodeCleaner/CalledClassPass.php
+++ b/app/vendor/psy/psysh/src/CodeCleaner/CalledClassPass.php
@@ -26,7 +26,7 @@
  */
 class CalledClassPass extends CodeCleanerPass
 {
-    private $inClass;
+    private bool $inClass = false;
 
     /**
      * @param array $nodes
diff --git a/app/vendor/psy/psysh/src/CodeCleaner/EmptyArrayDimFetchPass.php b/app/vendor/psy/psysh/src/CodeCleaner/EmptyArrayDimFetchPass.php
index 88cdae9f4..0429589b8 100644
--- a/app/vendor/psy/psysh/src/CodeCleaner/EmptyArrayDimFetchPass.php
+++ b/app/vendor/psy/psysh/src/CodeCleaner/EmptyArrayDimFetchPass.php
@@ -25,7 +25,7 @@ class EmptyArrayDimFetchPass extends CodeCleanerPass
 {
     const EXCEPTION_MESSAGE = 'Cannot use [] for reading';
 
-    private $theseOnesAreFine = [];
+    private array $theseOnesAreFine = [];
 
     /**
      * @return Node[]|null Array of nodes
diff --git a/app/vendor/psy/psysh/src/CodeCleaner/FinalClassPass.php b/app/vendor/psy/psysh/src/CodeCleaner/FinalClassPass.php
index 1507664fe..cef5e91ad 100644
--- a/app/vendor/psy/psysh/src/CodeCleaner/FinalClassPass.php
+++ b/app/vendor/psy/psysh/src/CodeCleaner/FinalClassPass.php
@@ -20,7 +20,7 @@
  */
 class FinalClassPass extends CodeCleanerPass
 {
-    private $finalClasses;
+    private array $finalClasses = [];
 
     /**
      * @param array $nodes
diff --git a/app/vendor/psy/psysh/src/CodeCleaner/FunctionContextPass.php b/app/vendor/psy/psysh/src/CodeCleaner/FunctionContextPass.php
index 07a3e8fd6..d57889111 100644
--- a/app/vendor/psy/psysh/src/CodeCleaner/FunctionContextPass.php
+++ b/app/vendor/psy/psysh/src/CodeCleaner/FunctionContextPass.php
@@ -18,8 +18,7 @@
 
 class FunctionContextPass extends CodeCleanerPass
 {
-    /** @var int */
-    private $functionDepth;
+    private int $functionDepth = 0;
 
     /**
      * @param array $nodes
diff --git a/app/vendor/psy/psysh/src/CodeCleaner/LabelContextPass.php b/app/vendor/psy/psysh/src/CodeCleaner/LabelContextPass.php
index 44962f63d..fa130b15c 100644
--- a/app/vendor/psy/psysh/src/CodeCleaner/LabelContextPass.php
+++ b/app/vendor/psy/psysh/src/CodeCleaner/LabelContextPass.php
@@ -31,13 +31,9 @@
  */
 class LabelContextPass extends CodeCleanerPass
 {
-    /** @var int */
-    private $functionDepth;
-
-    /** @var array */
-    private $labelDeclarations;
-    /** @var array */
-    private $labelGotos;
+    private int $functionDepth = 0;
+    private array $labelDeclarations = [];
+    private array $labelGotos = [];
 
     /**
      * @param array $nodes
diff --git a/app/vendor/psy/psysh/src/CodeCleaner/ListPass.php b/app/vendor/psy/psysh/src/CodeCleaner/ListPass.php
index eb0001ab1..696508559 100644
--- a/app/vendor/psy/psysh/src/CodeCleaner/ListPass.php
+++ b/app/vendor/psy/psysh/src/CodeCleaner/ListPass.php
@@ -12,9 +12,11 @@
 namespace Psy\CodeCleaner;
 
 use PhpParser\Node;
+use PhpParser\Node\ArrayItem;
 use PhpParser\Node\Expr\Array_;
 use PhpParser\Node\Expr\ArrayDimFetch;
-use PhpParser\Node\Expr\ArrayItem;
+// @todo Drop PhpParser\Node\Expr\ArrayItem once we drop support for PHP-Parser 4.x
+use PhpParser\Node\Expr\ArrayItem as LegacyArrayItem;
 use PhpParser\Node\Expr\Assign;
 use PhpParser\Node\Expr\FuncCall;
 use PhpParser\Node\Expr\List_;
@@ -80,7 +82,7 @@ public function enterNode(Node $node)
      */
     private static function isValidArrayItem(Node $item): bool
     {
-        $value = ($item instanceof ArrayItem) ? $item->value : $item;
+        $value = ($item instanceof ArrayItem || $item instanceof LegacyArrayItem) ? $item->value : $item;
 
         while ($value instanceof ArrayDimFetch || $value instanceof PropertyFetch) {
             $value = $value->var;
diff --git a/app/vendor/psy/psysh/src/CodeCleaner/LoopContextPass.php b/app/vendor/psy/psysh/src/CodeCleaner/LoopContextPass.php
index 5bb175e40..29a0ecf19 100644
--- a/app/vendor/psy/psysh/src/CodeCleaner/LoopContextPass.php
+++ b/app/vendor/psy/psysh/src/CodeCleaner/LoopContextPass.php
@@ -13,6 +13,8 @@
 
 use PhpParser\Node;
 use PhpParser\Node\Scalar\DNumber;
+use PhpParser\Node\Scalar\Float_;
+use PhpParser\Node\Scalar\Int_;
 use PhpParser\Node\Scalar\LNumber;
 use PhpParser\Node\Stmt\Break_;
 use PhpParser\Node\Stmt\Continue_;
@@ -28,7 +30,7 @@
  */
 class LoopContextPass extends CodeCleanerPass
 {
-    private $loopDepth;
+    private int $loopDepth = 0;
 
     /**
      * {@inheritdoc}
@@ -70,7 +72,13 @@ public function enterNode(Node $node)
                     throw new FatalErrorException($msg, 0, \E_ERROR, null, $node->getStartLine());
                 }
 
-                if ($node->num instanceof LNumber || $node->num instanceof DNumber) {
+                // @todo Remove LNumber and DNumber once we drop support for PHP-Parser 4.x
+                if (
+                    $node->num instanceof LNumber ||
+                    $node->num instanceof DNumber ||
+                    $node->num instanceof Int_ ||
+                    $node->num instanceof Float_
+                ) {
                     $num = $node->num->value;
                     if ($node->num instanceof DNumber || $num < 1) {
                         $msg = \sprintf("'%s' operator accepts only positive numbers", $operator);
diff --git a/app/vendor/psy/psysh/src/CodeCleaner/NamespaceAwarePass.php b/app/vendor/psy/psysh/src/CodeCleaner/NamespaceAwarePass.php
index 53290fd8e..41d1f1df9 100644
--- a/app/vendor/psy/psysh/src/CodeCleaner/NamespaceAwarePass.php
+++ b/app/vendor/psy/psysh/src/CodeCleaner/NamespaceAwarePass.php
@@ -21,8 +21,8 @@
  */
 abstract class NamespaceAwarePass extends CodeCleanerPass
 {
-    protected $namespace;
-    protected $currentScope;
+    protected array $namespace = [];
+    protected array $currentScope = [];
 
     /**
      * @todo should this be final? Extending classes should be sure to either
diff --git a/app/vendor/psy/psysh/src/CodeCleaner/NamespacePass.php b/app/vendor/psy/psysh/src/CodeCleaner/NamespacePass.php
index 25c0be035..49d9bca2b 100644
--- a/app/vendor/psy/psysh/src/CodeCleaner/NamespacePass.php
+++ b/app/vendor/psy/psysh/src/CodeCleaner/NamespacePass.php
@@ -29,8 +29,8 @@
  */
 class NamespacePass extends CodeCleanerPass
 {
-    private $namespace = null;
-    private $cleaner;
+    private ?Name $namespace = null;
+    private CodeCleaner $cleaner;
 
     /**
      * @param CodeCleaner $cleaner
@@ -83,7 +83,7 @@ public function beforeTraverse(array $nodes)
      *
      * @param Name|null $namespace
      */
-    private function setNamespace($namespace)
+    private function setNamespace(?Name $namespace)
     {
         $this->namespace = $namespace;
         $this->cleaner->setNamespace($namespace === null ? null : $this->getParts($namespace));
diff --git a/app/vendor/psy/psysh/src/CodeCleaner/PassableByReferencePass.php b/app/vendor/psy/psysh/src/CodeCleaner/PassableByReferencePass.php
index 7a3315158..5118c5bbd 100644
--- a/app/vendor/psy/psysh/src/CodeCleaner/PassableByReferencePass.php
+++ b/app/vendor/psy/psysh/src/CodeCleaner/PassableByReferencePass.php
@@ -21,6 +21,7 @@
 use PhpParser\Node\Expr\PropertyFetch;
 use PhpParser\Node\Expr\StaticCall;
 use PhpParser\Node\Expr\Variable;
+use PhpParser\Node\VariadicPlaceholder;
 use Psy\Exception\FatalErrorException;
 
 /**
@@ -59,9 +60,18 @@ public function enterNode(Node $node)
                 return;
             }
 
+            $args = [];
+            foreach ($node->args as $position => $arg) {
+                if ($arg instanceof VariadicPlaceholder) {
+                    continue;
+                }
+
+                $args[$arg->name !== null ? $arg->name->name : $position] = $arg;
+            }
+
             foreach ($refl->getParameters() as $key => $param) {
-                if (\array_key_exists($key, $node->args)) {
-                    $arg = $node->args[$key];
+                if (\array_key_exists($key, $args) || \array_key_exists($param->name, $args)) {
+                    $arg = $args[$param->name] ?? $args[$key];
                     if ($param->isPassedByReference() && !$this->isPassableByReference($arg)) {
                         throw new FatalErrorException(self::EXCEPTION_MESSAGE, 0, \E_ERROR, null, $node->getStartLine());
                     }
diff --git a/app/vendor/psy/psysh/src/CodeCleaner/RequirePass.php b/app/vendor/psy/psysh/src/CodeCleaner/RequirePass.php
index 0fe7af071..5c8cde49c 100644
--- a/app/vendor/psy/psysh/src/CodeCleaner/RequirePass.php
+++ b/app/vendor/psy/psysh/src/CodeCleaner/RequirePass.php
@@ -16,6 +16,7 @@
 use PhpParser\Node\Expr\Include_;
 use PhpParser\Node\Expr\StaticCall;
 use PhpParser\Node\Name\FullyQualified as FullyQualifiedName;
+use PhpParser\Node\Scalar\Int_;
 use PhpParser\Node\Scalar\LNumber;
 use Psy\Exception\ErrorException;
 use Psy\Exception\FatalErrorException;
@@ -25,7 +26,7 @@
  */
 class RequirePass extends CodeCleanerPass
 {
-    private static $requireTypes = [Include_::TYPE_REQUIRE, Include_::TYPE_REQUIRE_ONCE];
+    private const REQUIRE_TYPES = [Include_::TYPE_REQUIRE, Include_::TYPE_REQUIRE_ONCE];
 
     /**
      * {@inheritdoc}
@@ -49,10 +50,15 @@ public function enterNode(Node $origNode)
          *
          *   $foo = require \Psy\CodeCleaner\RequirePass::resolve($bar)
          */
+        // @todo Remove LNumber once we drop support for PHP-Parser 4.x
+        $arg = \class_exists('PhpParser\Node\Scalar\Int_') ?
+            new Int_($origNode->getStartLine()) :
+            new LNumber($origNode->getStartLine());
+
         $node->expr = new StaticCall(
             new FullyQualifiedName(self::class),
             'resolve',
-            [new Arg($origNode->expr), new Arg(new LNumber($origNode->getStartLine()))],
+            [new Arg($origNode->expr), new Arg($arg)],
             $origNode->getAttributes()
         );
 
@@ -119,7 +125,7 @@ public static function resolve($file, $startLine = null): string
 
     private function isRequireNode(Node $node): bool
     {
-        return $node instanceof Include_ && \in_array($node->type, self::$requireTypes);
+        return $node instanceof Include_ && \in_array($node->type, self::REQUIRE_TYPES);
     }
 
     private static function getIncludePath(): array
diff --git a/app/vendor/psy/psysh/src/CodeCleaner/ReturnTypePass.php b/app/vendor/psy/psysh/src/CodeCleaner/ReturnTypePass.php
index c9894fbdd..8ab898460 100644
--- a/app/vendor/psy/psysh/src/CodeCleaner/ReturnTypePass.php
+++ b/app/vendor/psy/psysh/src/CodeCleaner/ReturnTypePass.php
@@ -15,6 +15,8 @@
 use PhpParser\Node\Expr\Closure;
 use PhpParser\Node\Expr\ConstFetch;
 use PhpParser\Node\Identifier;
+use PhpParser\Node\IntersectionType;
+use PhpParser\Node\Name;
 use PhpParser\Node\NullableType;
 use PhpParser\Node\Stmt\Function_;
 use PhpParser\Node\Stmt\Return_;
@@ -32,7 +34,7 @@ class ReturnTypePass extends CodeCleanerPass
     const VOID_NULL_MESSAGE = 'A void function must not return a value (did you mean "return;" instead of "return null;"?)';
     const NULLABLE_VOID_MESSAGE = 'Void type cannot be nullable';
 
-    private $returnTypeStack = [];
+    private array $returnTypeStack = [];
 
     /**
      * {@inheritdoc}
@@ -100,12 +102,16 @@ private function typeName(Node $node): string
             return \implode('|', \array_map([$this, 'typeName'], $node->types));
         }
 
+        if ($node instanceof IntersectionType) {
+            return \implode('&', \array_map([$this, 'typeName'], $node->types));
+        }
+
         if ($node instanceof NullableType) {
-            return \strtolower($node->type->name);
+            return $this->typeName($node->type);
         }
 
-        if ($node instanceof Identifier) {
-            return \strtolower($node->name);
+        if ($node instanceof Identifier || $node instanceof Name) {
+            return $node->toLowerString();
         }
 
         throw new \InvalidArgumentException('Unable to find type name');
diff --git a/app/vendor/psy/psysh/src/CodeCleaner/StrictTypesPass.php b/app/vendor/psy/psysh/src/CodeCleaner/StrictTypesPass.php
index d0ce353cc..8fd6ab711 100644
--- a/app/vendor/psy/psysh/src/CodeCleaner/StrictTypesPass.php
+++ b/app/vendor/psy/psysh/src/CodeCleaner/StrictTypesPass.php
@@ -12,6 +12,8 @@
 namespace Psy\CodeCleaner;
 
 use PhpParser\Node;
+use PhpParser\Node\DeclareItem;
+use PhpParser\Node\Scalar\Int_;
 use PhpParser\Node\Scalar\LNumber;
 use PhpParser\Node\Stmt\Declare_;
 use PhpParser\Node\Stmt\DeclareDeclare;
@@ -31,7 +33,7 @@ class StrictTypesPass extends CodeCleanerPass
 {
     const EXCEPTION_MESSAGE = 'strict_types declaration must have 0 or 1 as its value';
 
-    private $strictTypes = false;
+    private bool $strictTypes;
 
     /**
      * @param bool $strictTypes enforce strict types by default
@@ -62,7 +64,8 @@ public function beforeTraverse(array $nodes)
                 foreach ($node->declares as $declare) {
                     if ($declare->key->toString() === 'strict_types') {
                         $value = $declare->value;
-                        if (!$value instanceof LNumber || ($value->value !== 0 && $value->value !== 1)) {
+                        // @todo Remove LNumber once we drop support for PHP-Parser 4.x
+                        if ((!$value instanceof LNumber && !$value instanceof Int_) || ($value->value !== 0 && $value->value !== 1)) {
                             throw new FatalErrorException(self::EXCEPTION_MESSAGE, 0, \E_ERROR, null, $node->getStartLine());
                         }
 
@@ -75,7 +78,13 @@ public function beforeTraverse(array $nodes)
         if ($prependStrictTypes) {
             $first = \reset($nodes);
             if (!$first instanceof Declare_) {
-                $declare = new Declare_([new DeclareDeclare('strict_types', new LNumber(1))]);
+                // @todo Switch to PhpParser\Node\DeclareItem once we drop support for PHP-Parser 4.x
+                // @todo Remove LNumber once we drop support for PHP-Parser 4.x
+                $arg = \class_exists('PhpParser\Node\Scalar\Int_') ? new Int_(1) : new LNumber(1);
+                $declareItem = \class_exists('PhpParser\Node\DeclareItem') ?
+                    new DeclareItem('strict_types', $arg) :
+                    new DeclareDeclare('strict_types', $arg);
+                $declare = new Declare_([$declareItem]);
                 \array_unshift($nodes, $declare);
             }
         }
diff --git a/app/vendor/psy/psysh/src/CodeCleaner/UseStatementPass.php b/app/vendor/psy/psysh/src/CodeCleaner/UseStatementPass.php
index 5d4cbdcf4..a2ddc9ef4 100644
--- a/app/vendor/psy/psysh/src/CodeCleaner/UseStatementPass.php
+++ b/app/vendor/psy/psysh/src/CodeCleaner/UseStatementPass.php
@@ -33,9 +33,9 @@
  */
 class UseStatementPass extends CodeCleanerPass
 {
-    private $aliases = [];
-    private $lastAliases = [];
-    private $lastNamespace = null;
+    private array $aliases = [];
+    private array $lastAliases = [];
+    private ?Name $lastNamespace = null;
 
     /**
      * Re-load the last set of use statements on re-entering a namespace.
@@ -77,6 +77,7 @@ public function leaveNode(Node $node)
                 $this->aliases[\strtolower($useItem->getAlias())] = $useItem->name;
             }
 
+            // @todo Rename to Node_Visitor::REMOVE_NODE once we drop support for PHP-Parser 4.x
             return NodeTraverser::REMOVE_NODE;
         }
 
@@ -89,6 +90,7 @@ public function leaveNode(Node $node)
                 ]);
             }
 
+            // @todo Rename to Node_Visitor::REMOVE_NODE once we drop support for PHP-Parser 4.x
             return NodeTraverser::REMOVE_NODE;
         }
 
diff --git a/app/vendor/psy/psysh/src/CodeCleaner/ValidClassNamePass.php b/app/vendor/psy/psysh/src/CodeCleaner/ValidClassNamePass.php
index dff32d58d..331ca743a 100644
--- a/app/vendor/psy/psysh/src/CodeCleaner/ValidClassNamePass.php
+++ b/app/vendor/psy/psysh/src/CodeCleaner/ValidClassNamePass.php
@@ -36,7 +36,7 @@ class ValidClassNamePass extends NamespaceAwarePass
     const INTERFACE_TYPE = 'interface';
     const TRAIT_TYPE = 'trait';
 
-    private $conditionalScopes = 0;
+    private int $conditionalScopes = 0;
 
     /**
      * Validate class, interface and trait definitions.
diff --git a/app/vendor/psy/psysh/src/CodeCleaner/ValidConstructorPass.php b/app/vendor/psy/psysh/src/CodeCleaner/ValidConstructorPass.php
index 481de6fc2..3d14d98d3 100644
--- a/app/vendor/psy/psysh/src/CodeCleaner/ValidConstructorPass.php
+++ b/app/vendor/psy/psysh/src/CodeCleaner/ValidConstructorPass.php
@@ -33,7 +33,7 @@
  */
 class ValidConstructorPass extends CodeCleanerPass
 {
-    private $namespace;
+    private array $namespace = [];
 
     /**
      * @return Node[]|null Array of nodes
@@ -69,7 +69,7 @@ public function enterNode(Node $node)
                     }
 
                     // We found a possible old-style constructor (unless there is also a __construct method)
-                    if (empty($this->namespace) && \strtolower($node->name) === \strtolower($stmt->name)) {
+                    if (empty($this->namespace) && $node->name !== null && \strtolower($node->name) === \strtolower($stmt->name)) {
                         $constructor = $stmt;
                     }
                 }
diff --git a/app/vendor/psy/psysh/src/CodeCleaner/ValidFunctionNamePass.php b/app/vendor/psy/psysh/src/CodeCleaner/ValidFunctionNamePass.php
index bd20607c4..789364f18 100644
--- a/app/vendor/psy/psysh/src/CodeCleaner/ValidFunctionNamePass.php
+++ b/app/vendor/psy/psysh/src/CodeCleaner/ValidFunctionNamePass.php
@@ -27,7 +27,7 @@
  */
 class ValidFunctionNamePass extends NamespaceAwarePass
 {
-    private $conditionalScopes = 0;
+    private int $conditionalScopes = 0;
 
     /**
      * Store newly defined function names on the way in, to allow recursion.
diff --git a/app/vendor/psy/psysh/src/Command/BufferCommand.php b/app/vendor/psy/psysh/src/Command/BufferCommand.php
index 8348aee64..5372dd3a9 100644
--- a/app/vendor/psy/psysh/src/Command/BufferCommand.php
+++ b/app/vendor/psy/psysh/src/Command/BufferCommand.php
@@ -11,7 +11,6 @@
 
 namespace Psy\Command;
 
-use Psy\Exception\RuntimeException;
 use Psy\Output\ShellOutput;
 use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Input\InputOption;
@@ -52,14 +51,11 @@ protected function configure()
      */
     protected function execute(InputInterface $input, OutputInterface $output): int
     {
-        $app = $this->getApplication();
-        if (!$app instanceof \Psy\Shell) {
-            throw new RuntimeException('Buffer command requires a \Psy\Shell application');
-        }
+        $shell = $this->getShell();
 
-        $buf = $app->getCodeBuffer();
+        $buf = $shell->getCodeBuffer();
         if ($input->getOption('clear')) {
-            $app->resetCodeBuffer();
+            $shell->resetCodeBuffer();
             $output->writeln($this->formatLines($buf, 'urgent'), ShellOutput::NUMBER_LINES);
         } else {
             $output->writeln($this->formatLines($buf), ShellOutput::NUMBER_LINES);
diff --git a/app/vendor/psy/psysh/src/Command/CodeArgumentParser.php b/app/vendor/psy/psysh/src/Command/CodeArgumentParser.php
index 4803aec1c..6d32276f3 100644
--- a/app/vendor/psy/psysh/src/Command/CodeArgumentParser.php
+++ b/app/vendor/psy/psysh/src/Command/CodeArgumentParser.php
@@ -20,9 +20,9 @@
  */
 class CodeArgumentParser
 {
-    private $parser;
+    private Parser $parser;
 
-    public function __construct(Parser $parser = null)
+    public function __construct(?Parser $parser = null)
     {
         $this->parser = $parser ?? (new ParserFactory())->createParser();
     }
diff --git a/app/vendor/psy/psysh/src/Command/Command.php b/app/vendor/psy/psysh/src/Command/Command.php
index 0d18d2c6f..693c5fc36 100644
--- a/app/vendor/psy/psysh/src/Command/Command.php
+++ b/app/vendor/psy/psysh/src/Command/Command.php
@@ -30,7 +30,7 @@ abstract class Command extends BaseCommand
      *
      * @api
      */
-    public function setApplication(Application $application = null): void
+    public function setApplication(?Application $application = null): void
     {
         if ($application !== null && !$application instanceof Shell) {
             throw new \InvalidArgumentException('PsySH Commands require an instance of Psy\Shell');
@@ -39,6 +39,19 @@ public function setApplication(Application $application = null): void
         parent::setApplication($application);
     }
 
+    /**
+     * getApplication, but is guaranteed to return a Shell instance.
+     */
+    protected function getShell(): Shell
+    {
+        $shell = $this->getApplication();
+        if (!$shell instanceof Shell) {
+            throw new \RuntimeException('PsySH Commands require an instance of Psy\Shell');
+        }
+
+        return $shell;
+    }
+
     /**
      * {@inheritdoc}
      */
@@ -140,9 +153,11 @@ private function argumentsAsText(): string
                     $default = '';
                 }
 
+                $name = $argument->getName();
+                $pad = \str_pad('', $max - \strlen($name));
                 $description = \str_replace("\n", "\n".\str_pad('', $max + 2, ' '), $argument->getDescription());
 
-                $messages[] = \sprintf(" %-{$max}s %s%s", $argument->getName(), $description, $default);
+                $messages[] = \sprintf(' %s%s %s%s', $name, $pad, $description, $default);
             }
 
             $messages[] = '';
diff --git a/app/vendor/psy/psysh/src/Command/DocCommand.php b/app/vendor/psy/psysh/src/Command/DocCommand.php
index 1650ccf62..77343dd01 100644
--- a/app/vendor/psy/psysh/src/Command/DocCommand.php
+++ b/app/vendor/psy/psysh/src/Command/DocCommand.php
@@ -73,7 +73,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
             $doc = $this->getManualDoc($reflector) ?: DocblockFormatter::format($reflector);
         }
 
-        $db = $this->getApplication()->getManualDb();
+        $db = $this->getShell()->getManualDb();
 
         if ($output instanceof ShellOutput) {
             $output->startPaging();
@@ -242,7 +242,7 @@ private function getParentReflectors($reflector): \Generator
 
     private function getManualDocById($id)
     {
-        if ($db = $this->getApplication()->getManualDb()) {
+        if ($db = $this->getShell()->getManualDb()) {
             $result = $db->query(\sprintf('SELECT doc FROM php_manual WHERE id = %s', $db->quote($id)));
             if ($result !== false) {
                 return $result->fetchColumn(0);
diff --git a/app/vendor/psy/psysh/src/Command/DumpCommand.php b/app/vendor/psy/psysh/src/Command/DumpCommand.php
index 88ddbe26a..145851d0f 100644
--- a/app/vendor/psy/psysh/src/Command/DumpCommand.php
+++ b/app/vendor/psy/psysh/src/Command/DumpCommand.php
@@ -11,7 +11,9 @@
 
 namespace Psy\Command;
 
+use Psy\Exception\RuntimeException;
 use Psy\Input\CodeArgument;
+use Psy\Output\ShellOutput;
 use Psy\VarDumper\Presenter;
 use Psy\VarDumper\PresenterAware;
 use Symfony\Component\Console\Input\InputInterface;
@@ -25,7 +27,7 @@
  */
 class DumpCommand extends ReflectingCommand implements PresenterAware
 {
-    private $presenter;
+    private Presenter $presenter;
 
     /**
      * PresenterAware interface.
@@ -71,6 +73,10 @@ protected function configure()
      */
     protected function execute(InputInterface $input, OutputInterface $output): int
     {
+        if (!$output instanceof ShellOutput) {
+            throw new RuntimeException('DumpCommand requires a ShellOutput');
+        }
+
         $depth = $input->getOption('depth');
         $target = $this->resolveCode($input->getArgument('target'));
         $output->page($this->presenter->present($target, $depth, $input->getOption('all') ? Presenter::VERBOSE : 0));
diff --git a/app/vendor/psy/psysh/src/Command/EditCommand.php b/app/vendor/psy/psysh/src/Command/EditCommand.php
index 7612b3de9..7fbb78c1b 100644
--- a/app/vendor/psy/psysh/src/Command/EditCommand.php
+++ b/app/vendor/psy/psysh/src/Command/EditCommand.php
@@ -11,6 +11,7 @@
 
 namespace Psy\Command;
 
+use Psy\ConfigPaths;
 use Psy\Context;
 use Psy\ContextAware;
 use Symfony\Component\Console\Input\InputArgument;
@@ -20,15 +21,8 @@
 
 class EditCommand extends Command implements ContextAware
 {
-    /**
-     * @var string
-     */
-    private $runtimeDir = '';
-
-    /**
-     * @var Context
-     */
-    private $context;
+    private string $runtimeDir = '';
+    private Context $context;
 
     /**
      * Constructor.
@@ -97,6 +91,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
         $shouldRemoveFile = false;
 
         if ($filePath === null) {
+            ConfigPaths::ensureDir($this->runtimeDir);
             $filePath = \tempnam($this->runtimeDir, 'psysh-edit-command');
             $shouldRemoveFile = true;
         }
@@ -104,7 +99,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
         $editedContent = $this->editFile($filePath, $shouldRemoveFile);
 
         if ($execute) {
-            $this->getApplication()->addInput($editedContent);
+            $this->getShell()->addInput($editedContent);
         }
 
         return 0;
@@ -115,7 +110,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
      * @param bool        $noExecOption
      * @param string|null $filePath
      */
-    private function shouldExecuteFile(bool $execOption, bool $noExecOption, string $filePath = null): bool
+    private function shouldExecuteFile(bool $execOption, bool $noExecOption, ?string $filePath = null): bool
     {
         if ($execOption) {
             return true;
@@ -136,7 +131,7 @@ private function shouldExecuteFile(bool $execOption, bool $noExecOption, string
      *
      * @throws \InvalidArgumentException If the variable is not found in the current context
      */
-    private function extractFilePath(string $fileArgument = null)
+    private function extractFilePath(?string $fileArgument = null)
     {
         // If the file argument was a variable, get it from the context
         if ($fileArgument !== null &&
diff --git a/app/vendor/psy/psysh/src/Command/HelpCommand.php b/app/vendor/psy/psysh/src/Command/HelpCommand.php
index 13ea34831..c7296f49d 100644
--- a/app/vendor/psy/psysh/src/Command/HelpCommand.php
+++ b/app/vendor/psy/psysh/src/Command/HelpCommand.php
@@ -23,7 +23,7 @@
  */
 class HelpCommand extends Command
 {
-    private $command;
+    private ?Command $command = null;
 
     /**
      * {@inheritdoc}
diff --git a/app/vendor/psy/psysh/src/Command/HistoryCommand.php b/app/vendor/psy/psysh/src/Command/HistoryCommand.php
index cf5f29b9d..b40595939 100644
--- a/app/vendor/psy/psysh/src/Command/HistoryCommand.php
+++ b/app/vendor/psy/psysh/src/Command/HistoryCommand.php
@@ -26,8 +26,8 @@
  */
 class HistoryCommand extends Command
 {
-    private $filter;
-    private $readline;
+    private FilterOptions $filter;
+    private Readline $readline;
 
     /**
      * {@inheritdoc}
@@ -135,7 +135,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int
 
             $count = \count($history);
             $output->writeln(\sprintf('Replaying %d line%s of history', $count, ($count !== 1) ? 's' : ''));
-            $this->getApplication()->addInput($history);
+
+            $this->getShell()->addInput($history);
         } elseif ($input->getOption('clear')) {
             $this->clearHistory();
             $output->writeln('History cleared.');
@@ -156,12 +157,12 @@ protected function execute(InputInterface $input, OutputInterface $output): int
      *
      * @param string $range
      *
-     * @return array [ start, end ]
+     * @return int[] [ start, end ]
      */
     private function extractRange(string $range): array
     {
         if (\preg_match('/^\d+$/', $range)) {
-            return [$range, $range + 1];
+            return [(int) $range, (int) $range + 1];
         }
 
         $matches = [];
@@ -206,7 +207,7 @@ private function getHistorySlice($show, $head, $tail): array
                 throw new \InvalidArgumentException('Please specify an integer argument for --tail');
             }
 
-            $start = \count($history) - $tail;
+            $start = \count($history) - (int) $tail;
             $length = (int) $tail + 1;
         } else {
             return $history;
diff --git a/app/vendor/psy/psysh/src/Command/ListCommand.php b/app/vendor/psy/psysh/src/Command/ListCommand.php
index 1982aa4c1..4f084f5b1 100644
--- a/app/vendor/psy/psysh/src/Command/ListCommand.php
+++ b/app/vendor/psy/psysh/src/Command/ListCommand.php
@@ -35,8 +35,8 @@
  */
 class ListCommand extends ReflectingCommand implements PresenterAware
 {
-    protected $presenter;
-    protected $enumerators;
+    protected Presenter $presenter;
+    protected array $enumerators;
 
     /**
      * PresenterAware interface.
diff --git a/app/vendor/psy/psysh/src/Command/ListCommand/ClassConstantEnumerator.php b/app/vendor/psy/psysh/src/Command/ListCommand/ClassConstantEnumerator.php
index 803a02e14..9bc56748f 100644
--- a/app/vendor/psy/psysh/src/Command/ListCommand/ClassConstantEnumerator.php
+++ b/app/vendor/psy/psysh/src/Command/ListCommand/ClassConstantEnumerator.php
@@ -21,7 +21,7 @@ class ClassConstantEnumerator extends Enumerator
     /**
      * {@inheritdoc}
      */
-    protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null): array
+    protected function listItems(InputInterface $input, ?\Reflector $reflector = null, $target = null): array
     {
         // only list constants when a Reflector is present.
         if ($reflector === null) {
diff --git a/app/vendor/psy/psysh/src/Command/ListCommand/ClassEnumerator.php b/app/vendor/psy/psysh/src/Command/ListCommand/ClassEnumerator.php
index cf80ba726..b0edf0353 100644
--- a/app/vendor/psy/psysh/src/Command/ListCommand/ClassEnumerator.php
+++ b/app/vendor/psy/psysh/src/Command/ListCommand/ClassEnumerator.php
@@ -22,7 +22,7 @@ class ClassEnumerator extends Enumerator
     /**
      * {@inheritdoc}
      */
-    protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null): array
+    protected function listItems(InputInterface $input, ?\Reflector $reflector = null, $target = null): array
     {
         // if we have a reflector, ensure that it's a namespace reflector
         if (($target !== null || $reflector !== null) && !$reflector instanceof ReflectionNamespace) {
@@ -66,7 +66,7 @@ protected function listItems(InputInterface $input, \Reflector $reflector = null
      *
      * @return array
      */
-    protected function filterClasses(string $key, array $classes, bool $internal, bool $user, string $prefix = null): array
+    protected function filterClasses(string $key, array $classes, bool $internal, bool $user, ?string $prefix = null): array
     {
         $ret = [];
 
diff --git a/app/vendor/psy/psysh/src/Command/ListCommand/ConstantEnumerator.php b/app/vendor/psy/psysh/src/Command/ListCommand/ConstantEnumerator.php
index c8346e946..c0f7c617d 100644
--- a/app/vendor/psy/psysh/src/Command/ListCommand/ConstantEnumerator.php
+++ b/app/vendor/psy/psysh/src/Command/ListCommand/ConstantEnumerator.php
@@ -20,7 +20,7 @@
 class ConstantEnumerator extends Enumerator
 {
     // Because `Json` is ugly.
-    private static $categoryLabels = [
+    private const CATEGORY_LABELS = [
         'libxml'   => 'libxml',
         'openssl'  => 'OpenSSL',
         'pcre'     => 'PCRE',
@@ -49,7 +49,7 @@ class ConstantEnumerator extends Enumerator
     /**
      * {@inheritdoc}
      */
-    protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null): array
+    protected function listItems(InputInterface $input, ?\Reflector $reflector = null, $target = null): array
     {
         // if we have a reflector, ensure that it's a namespace reflector
         if (($target !== null || $reflector !== null) && !$reflector instanceof ReflectionNamespace) {
@@ -88,7 +88,7 @@ protected function listItems(InputInterface $input, \Reflector $reflector = null
         }
 
         if ($category) {
-            $caseCategory = \array_key_exists($category, self::$categoryLabels) ? self::$categoryLabels[$category] : \ucfirst($category);
+            $caseCategory = \array_key_exists($category, self::CATEGORY_LABELS) ? self::CATEGORY_LABELS[$category] : \ucfirst($category);
             $label = $caseCategory.' Constants';
             $ret[$label] = $this->getConstants($category);
         }
@@ -122,7 +122,7 @@ protected function listItems(InputInterface $input, \Reflector $reflector = null
      *
      * @return array
      */
-    protected function getConstants(string $category = null): array
+    protected function getConstants(?string $category = null): array
     {
         if (!$category) {
             return \get_defined_constants();
diff --git a/app/vendor/psy/psysh/src/Command/ListCommand/Enumerator.php b/app/vendor/psy/psysh/src/Command/ListCommand/Enumerator.php
index ecc4613f8..4cc336c51 100644
--- a/app/vendor/psy/psysh/src/Command/ListCommand/Enumerator.php
+++ b/app/vendor/psy/psysh/src/Command/ListCommand/Enumerator.php
@@ -31,8 +31,8 @@ abstract class Enumerator
     const IS_CLASS = 'class';
     const IS_FUNCTION = 'function';
 
-    private $filter;
-    private $presenter;
+    private FilterOptions $filter;
+    private Presenter $presenter;
 
     /**
      * Enumerator constructor.
@@ -54,7 +54,7 @@ public function __construct(Presenter $presenter)
      *
      * @return array
      */
-    public function enumerate(InputInterface $input, \Reflector $reflector = null, $target = null): array
+    public function enumerate(InputInterface $input, ?\Reflector $reflector = null, $target = null): array
     {
         $this->filter->bind($input);
 
@@ -82,7 +82,7 @@ public function enumerate(InputInterface $input, \Reflector $reflector = null, $
      *
      * @return array
      */
-    abstract protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null): array;
+    abstract protected function listItems(InputInterface $input, ?\Reflector $reflector = null, $target = null): array;
 
     protected function showItem($name)
     {
diff --git a/app/vendor/psy/psysh/src/Command/ListCommand/FunctionEnumerator.php b/app/vendor/psy/psysh/src/Command/ListCommand/FunctionEnumerator.php
index beccb4bdc..fe3891a59 100644
--- a/app/vendor/psy/psysh/src/Command/ListCommand/FunctionEnumerator.php
+++ b/app/vendor/psy/psysh/src/Command/ListCommand/FunctionEnumerator.php
@@ -22,7 +22,7 @@ class FunctionEnumerator extends Enumerator
     /**
      * {@inheritdoc}
      */
-    protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null): array
+    protected function listItems(InputInterface $input, ?\Reflector $reflector = null, $target = null): array
     {
         // if we have a reflector, ensure that it's a namespace reflector
         if (($target !== null || $reflector !== null) && !$reflector instanceof ReflectionNamespace) {
@@ -67,7 +67,7 @@ protected function listItems(InputInterface $input, \Reflector $reflector = null
      *
      * @return array
      */
-    protected function getFunctions(string $type = null): array
+    protected function getFunctions(?string $type = null): array
     {
         $funcs = \get_defined_functions();
 
@@ -86,7 +86,7 @@ protected function getFunctions(string $type = null): array
      *
      * @return array
      */
-    protected function prepareFunctions(array $functions, string $prefix = null): array
+    protected function prepareFunctions(array $functions, ?string $prefix = null): array
     {
         \natcasesort($functions);
 
diff --git a/app/vendor/psy/psysh/src/Command/ListCommand/GlobalVariableEnumerator.php b/app/vendor/psy/psysh/src/Command/ListCommand/GlobalVariableEnumerator.php
index fab59704d..81be16e53 100644
--- a/app/vendor/psy/psysh/src/Command/ListCommand/GlobalVariableEnumerator.php
+++ b/app/vendor/psy/psysh/src/Command/ListCommand/GlobalVariableEnumerator.php
@@ -21,7 +21,7 @@ class GlobalVariableEnumerator extends Enumerator
     /**
      * {@inheritdoc}
      */
-    protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null): array
+    protected function listItems(InputInterface $input, ?\Reflector $reflector = null, $target = null): array
     {
         // only list globals when no Reflector is present.
         if ($reflector !== null || $target !== null) {
diff --git a/app/vendor/psy/psysh/src/Command/ListCommand/MethodEnumerator.php b/app/vendor/psy/psysh/src/Command/ListCommand/MethodEnumerator.php
index 68c74dd4f..e7b4503fd 100644
--- a/app/vendor/psy/psysh/src/Command/ListCommand/MethodEnumerator.php
+++ b/app/vendor/psy/psysh/src/Command/ListCommand/MethodEnumerator.php
@@ -21,7 +21,7 @@ class MethodEnumerator extends Enumerator
     /**
      * {@inheritdoc}
      */
-    protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null): array
+    protected function listItems(InputInterface $input, ?\Reflector $reflector = null, $target = null): array
     {
         // only list methods when a Reflector is present.
         if ($reflector === null) {
diff --git a/app/vendor/psy/psysh/src/Command/ListCommand/PropertyEnumerator.php b/app/vendor/psy/psysh/src/Command/ListCommand/PropertyEnumerator.php
index dfde8eafd..17661455a 100644
--- a/app/vendor/psy/psysh/src/Command/ListCommand/PropertyEnumerator.php
+++ b/app/vendor/psy/psysh/src/Command/ListCommand/PropertyEnumerator.php
@@ -21,7 +21,7 @@ class PropertyEnumerator extends Enumerator
     /**
      * {@inheritdoc}
      */
-    protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null): array
+    protected function listItems(InputInterface $input, ?\Reflector $reflector = null, $target = null): array
     {
         // only list properties when a Reflector is present.
 
diff --git a/app/vendor/psy/psysh/src/Command/ListCommand/VariableEnumerator.php b/app/vendor/psy/psysh/src/Command/ListCommand/VariableEnumerator.php
index 38f3f6023..133a188d4 100644
--- a/app/vendor/psy/psysh/src/Command/ListCommand/VariableEnumerator.php
+++ b/app/vendor/psy/psysh/src/Command/ListCommand/VariableEnumerator.php
@@ -21,7 +21,7 @@
 class VariableEnumerator extends Enumerator
 {
     // n.b. this array is the order in which special variables will be listed
-    private static $specialNames = [
+    private const SPECIAL_NAMES = [
         '_', '_e', '__out', '__function', '__method', '__class', '__namespace', '__file', '__line', '__dir',
     ];
 
@@ -45,7 +45,7 @@ public function __construct(Presenter $presenter, Context $context)
     /**
      * {@inheritdoc}
      */
-    protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null): array
+    protected function listItems(InputInterface $input, ?\Reflector $reflector = null, $target = null): array
     {
         // only list variables when no Reflector is present.
         if ($reflector !== null || $target !== null) {
@@ -80,8 +80,8 @@ protected function getVariables(bool $showAll): array
     {
         $scopeVars = $this->context->getAll();
         \uksort($scopeVars, function ($a, $b) {
-            $aIndex = \array_search($a, self::$specialNames);
-            $bIndex = \array_search($b, self::$specialNames);
+            $aIndex = \array_search($a, self::SPECIAL_NAMES);
+            $bIndex = \array_search($b, self::SPECIAL_NAMES);
 
             if ($aIndex !== false) {
                 if ($bIndex !== false) {
@@ -100,7 +100,7 @@ protected function getVariables(bool $showAll): array
 
         $ret = [];
         foreach ($scopeVars as $name => $val) {
-            if (!$showAll && \in_array($name, self::$specialNames)) {
+            if (!$showAll && \in_array($name, self::SPECIAL_NAMES)) {
                 continue;
             }
 
@@ -126,7 +126,7 @@ protected function prepareVariables(array $variables): array
                 $fname = '$'.$name;
                 $ret[$fname] = [
                     'name'  => $fname,
-                    'style' => \in_array($name, self::$specialNames) ? self::IS_PRIVATE : self::IS_PUBLIC,
+                    'style' => \in_array($name, self::SPECIAL_NAMES) ? self::IS_PRIVATE : self::IS_PUBLIC,
                     'value' => $this->presentRef($val),
                 ];
             }
diff --git a/app/vendor/psy/psysh/src/Command/ParseCommand.php b/app/vendor/psy/psysh/src/Command/ParseCommand.php
index d97c751ac..550f42bfb 100644
--- a/app/vendor/psy/psysh/src/Command/ParseCommand.php
+++ b/app/vendor/psy/psysh/src/Command/ParseCommand.php
@@ -12,6 +12,7 @@
 namespace Psy\Command;
 
 use PhpParser\Node;
+use PhpParser\Parser;
 use Psy\Context;
 use Psy\ContextAware;
 use Psy\Input\CodeArgument;
@@ -28,15 +29,9 @@
  */
 class ParseCommand extends Command implements ContextAware, PresenterAware
 {
-    /**
-     * Context instance (for ContextAware interface).
-     *
-     * @var Context
-     */
-    protected $context;
-
-    private $presenter;
-    private $parser;
+    protected Context $context;
+    private Presenter $presenter;
+    private Parser $parser;
 
     /**
      * {@inheritdoc}
@@ -90,9 +85,9 @@ protected function configure()
         $this
             ->setName('parse')
             ->setDefinition([
-            new CodeArgument('code', CodeArgument::REQUIRED, 'PHP code to parse.'),
-            new InputOption('depth', '', InputOption::VALUE_REQUIRED, 'Depth to parse.', 10),
-        ])
+                new CodeArgument('code', CodeArgument::REQUIRED, 'PHP code to parse.'),
+                new InputOption('depth', '', InputOption::VALUE_REQUIRED, 'Depth to parse.', 10),
+            ])
             ->setDescription('Parse PHP code and show the abstract syntax tree.')
             ->setHelp(
                 <<<'HELP'
@@ -114,7 +109,6 @@ protected function configure()
     protected function execute(InputInterface $input, OutputInterface $output): int
     {
         $code = $input->getArgument('code');
-        $parserKind = $input->getOption('kind');
         $depth = $input->getOption('depth');
 
         $nodes = $this->parser->parse($code);
diff --git a/app/vendor/psy/psysh/src/Command/ReflectingCommand.php b/app/vendor/psy/psysh/src/Command/ReflectingCommand.php
index 55b9fbf2c..6f055b7ac 100644
--- a/app/vendor/psy/psysh/src/Command/ReflectingCommand.php
+++ b/app/vendor/psy/psysh/src/Command/ReflectingCommand.php
@@ -33,16 +33,10 @@ abstract class ReflectingCommand extends Command implements ContextAware
     const CLASS_STATIC = '/^([\\\\\w]+)::\$(\w+)$/';
     const INSTANCE_MEMBER = '/^(\$\w+)(::|->)(\w+)$/';
 
-    /**
-     * Context instance (for ContextAware interface).
-     *
-     * @var Context
-     */
-    protected $context;
-
-    private $parser;
-    private $traverser;
-    private $printer;
+    protected Context $context;
+    private CodeArgumentParser $parser;
+    private NodeTraverser $traverser;
+    private Printer $printer;
 
     /**
      * {@inheritdoc}
@@ -51,6 +45,7 @@ public function __construct($name = null)
     {
         $this->parser = new CodeArgumentParser();
 
+        // @todo Pass visitor directly to once we drop support for PHP-Parser 4.x
         $this->traverser = new NodeTraverser();
         $this->traverser->addVisitor(new SudoVisitor());
 
@@ -116,7 +111,7 @@ protected function getTarget(string $valueName): array
      */
     protected function resolveName(string $name, bool $includeFunctions = false): string
     {
-        $shell = $this->getApplication();
+        $shell = $this->getShell();
 
         // While not *technically* 100% accurate, let's treat `self` and `static` as equivalent.
         if (\in_array(\strtolower($name), ['self', 'static'])) {
@@ -194,7 +189,7 @@ protected function resolveCode(string $code)
             // Add an implicit `sudo` to target resolution.
             $nodes = $this->traverser->traverse($this->parser->parse($code));
             $sudoCode = $this->printer->prettyPrint($nodes);
-            $value = $this->getApplication()->execute($sudoCode, true);
+            $value = $this->getShell()->execute($sudoCode, true);
         } catch (\Throwable $e) {
             // Swallow all exceptions?
         }
diff --git a/app/vendor/psy/psysh/src/Command/ShowCommand.php b/app/vendor/psy/psysh/src/Command/ShowCommand.php
index 4d721d72b..35703e666 100644
--- a/app/vendor/psy/psysh/src/Command/ShowCommand.php
+++ b/app/vendor/psy/psysh/src/Command/ShowCommand.php
@@ -26,8 +26,8 @@
  */
 class ShowCommand extends ReflectingCommand
 {
-    private $lastException;
-    private $lastExceptionIndex;
+    private ?\Throwable $lastException = null;
+    private ?int $lastExceptionIndex = null;
 
     /**
      * {@inheritdoc}
@@ -46,7 +46,7 @@ protected function configure()
 Show the code for an object, class, constant, method or property, or the context
 of the last exception.
 
-cat --ex defaults to showing the lines surrounding the location of the last
+show --ex defaults to showing the lines surrounding the location of the last
 exception. Invoking it more than once travels up the exception's stack trace,
 and providing a number shows the context of the given index of the trace.
 
@@ -167,7 +167,7 @@ private function writeExceptionContext(InputInterface $input, OutputInterface $o
         $this->lastException = $exception;
         $this->lastExceptionIndex = $index;
 
-        $output->writeln($this->getApplication()->formatException($exception));
+        $output->writeln($this->getShell()->formatException($exception));
         $output->writeln('--');
         $this->writeTraceLine($output, $trace, $index);
         $this->writeTraceCodeSnippet($output, $trace, $index);
diff --git a/app/vendor/psy/psysh/src/Command/SudoCommand.php b/app/vendor/psy/psysh/src/Command/SudoCommand.php
index bd08d14ba..b84fbdc55 100644
--- a/app/vendor/psy/psysh/src/Command/SudoCommand.php
+++ b/app/vendor/psy/psysh/src/Command/SudoCommand.php
@@ -24,10 +24,10 @@
  */
 class SudoCommand extends Command
 {
-    private $readline;
-    private $parser;
-    private $traverser;
-    private $printer;
+    private Readline $readline;
+    private CodeArgumentParser $parser;
+    private NodeTraverser $traverser;
+    private Printer $printer;
 
     /**
      * {@inheritdoc}
@@ -36,6 +36,7 @@ public function __construct($name = null)
     {
         $this->parser = new CodeArgumentParser();
 
+        // @todo Pass visitor directly to once we drop support for PHP-Parser 4.x
         $this->traverser = new NodeTraverser();
         $this->traverser->addVisitor(new SudoVisitor());
 
@@ -112,7 +113,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int
         $nodes = $this->traverser->traverse($this->parser->parse($code));
 
         $sudoCode = $this->printer->prettyPrint($nodes);
-        $shell = $this->getApplication();
+
+        $shell = $this->getShell();
         $shell->addCode($sudoCode, !$shell->hasCode());
 
         return 0;
diff --git a/app/vendor/psy/psysh/src/Command/ThrowUpCommand.php b/app/vendor/psy/psysh/src/Command/ThrowUpCommand.php
index 8e5979147..0c0042541 100644
--- a/app/vendor/psy/psysh/src/Command/ThrowUpCommand.php
+++ b/app/vendor/psy/psysh/src/Command/ThrowUpCommand.php
@@ -29,8 +29,8 @@
  */
 class ThrowUpCommand extends Command
 {
-    private $parser;
-    private $printer;
+    private CodeArgumentParser $parser;
+    private Printer $printer;
 
     /**
      * {@inheritdoc}
@@ -82,7 +82,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
         $throwStmt = new Expression(new Throw_(new New_(new FullyQualifiedName(ThrowUpException::class), $args)));
         $throwCode = $this->printer->prettyPrint([$throwStmt]);
 
-        $shell = $this->getApplication();
+        $shell = $this->getShell();
         $shell->addCode($throwCode, !$shell->hasCode());
 
         return 0;
@@ -99,7 +99,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
      *
      * @return Arg[]
      */
-    private function prepareArgs(string $code = null): array
+    private function prepareArgs(?string $code = null): array
     {
         if (!$code) {
             // Default to last exception if nothing else was supplied
diff --git a/app/vendor/psy/psysh/src/Command/TimeitCommand.php b/app/vendor/psy/psysh/src/Command/TimeitCommand.php
index 3a2efee14..964697df7 100644
--- a/app/vendor/psy/psysh/src/Command/TimeitCommand.php
+++ b/app/vendor/psy/psysh/src/Command/TimeitCommand.php
@@ -28,12 +28,12 @@ class TimeitCommand extends Command
     const AVG_RESULT_MSG = 'Command took %.6f seconds on average (%.6f median; %.6f total) to complete.';
 
     // All times stored as nanoseconds!
-    private static $start = null;
-    private static $times = [];
+    private static ?int $start = null;
+    private static array $times = [];
 
-    private $parser;
-    private $traverser;
-    private $printer;
+    private CodeArgumentParser $parser;
+    private NodeTraverser $traverser;
+    private Printer $printer;
 
     /**
      * {@inheritdoc}
@@ -42,6 +42,7 @@ public function __construct($name = null)
     {
         $this->parser = new CodeArgumentParser();
 
+        // @todo Pass visitor directly to once we drop support for PHP-Parser 4.x
         $this->traverser = new NodeTraverser();
         $this->traverser->addVisitor(new TimeitVisitor());
 
@@ -82,7 +83,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int
     {
         $code = $input->getArgument('code');
         $num = (int) ($input->getOption('num') ?: 1);
-        $shell = $this->getApplication();
+
+        $shell = $this->getShell();
 
         $instrumentedCode = $this->instrumentCode($code);
 
diff --git a/app/vendor/psy/psysh/src/Command/TimeitCommand/TimeitVisitor.php b/app/vendor/psy/psysh/src/Command/TimeitCommand/TimeitVisitor.php
index 68948ee93..e2817affc 100644
--- a/app/vendor/psy/psysh/src/Command/TimeitCommand/TimeitVisitor.php
+++ b/app/vendor/psy/psysh/src/Command/TimeitCommand/TimeitVisitor.php
@@ -31,7 +31,7 @@
  */
 class TimeitVisitor extends NodeVisitorAbstract
 {
-    private $functionDepth;
+    private int $functionDepth = 0;
 
     /**
      * {@inheritdoc}
@@ -120,7 +120,7 @@ private function getStartCall(): StaticCall
      *
      * @param Expr|null $arg
      */
-    private function getEndCall(Expr $arg = null): StaticCall
+    private function getEndCall(?Expr $arg = null): StaticCall
     {
         if ($arg === null) {
             $arg = NoReturnValue::create();
diff --git a/app/vendor/psy/psysh/src/Command/TraceCommand.php b/app/vendor/psy/psysh/src/Command/TraceCommand.php
index 411237e11..04a2beb0c 100644
--- a/app/vendor/psy/psysh/src/Command/TraceCommand.php
+++ b/app/vendor/psy/psysh/src/Command/TraceCommand.php
@@ -92,7 +92,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
      *
      * @return array Formatted stacktrace lines
      */
-    protected function getBacktrace(\Throwable $e, int $count = null, bool $includePsy = true): array
+    protected function getBacktrace(\Throwable $e, ?int $count = null, bool $includePsy = true): array
     {
         return TraceFormatter::formatTrace($e, $this->filter, $count, $includePsy);
     }
diff --git a/app/vendor/psy/psysh/src/Command/WhereamiCommand.php b/app/vendor/psy/psysh/src/Command/WhereamiCommand.php
index b7d569bea..68f4c4e2a 100644
--- a/app/vendor/psy/psysh/src/Command/WhereamiCommand.php
+++ b/app/vendor/psy/psysh/src/Command/WhereamiCommand.php
@@ -23,7 +23,7 @@
  */
 class WhereamiCommand extends Command
 {
-    private $backtrace;
+    private array $backtrace;
 
     public function __construct()
     {
diff --git a/app/vendor/psy/psysh/src/Command/WtfCommand.php b/app/vendor/psy/psysh/src/Command/WtfCommand.php
index 6e2472c00..1b4c7c27b 100644
--- a/app/vendor/psy/psysh/src/Command/WtfCommand.php
+++ b/app/vendor/psy/psysh/src/Command/WtfCommand.php
@@ -25,12 +25,7 @@
  */
 class WtfCommand extends TraceCommand implements ContextAware
 {
-    /**
-     * Context instance (for ContextAware interface).
-     *
-     * @var Context
-     */
-    protected $context;
+    protected Context $context;
 
     /**
      * ContextAware interface.
@@ -96,8 +91,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int
         $exception = $this->context->getLastException();
         $count = $input->getOption('all') ? \PHP_INT_MAX : \max(3, \pow(2, \strlen($incredulity) + 1));
 
-        $shell = $this->getApplication();
-
         if ($output instanceof ShellOutput) {
             $output->startPaging();
         }
@@ -113,7 +106,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
             $trace = $this->getBacktrace($exception, $showLines);
             $moreLines = $traceCount - \count($trace);
 
-            $output->writeln($shell->formatException($exception));
+            $output->writeln($this->getShell()->formatException($exception));
             $output->writeln('--');
             $output->write($trace, true, ShellOutput::NUMBER_LINES);
             $output->writeln('');
diff --git a/app/vendor/psy/psysh/src/ConfigPaths.php b/app/vendor/psy/psysh/src/ConfigPaths.php
index a091d203a..2d2ffa2c3 100644
--- a/app/vendor/psy/psysh/src/ConfigPaths.php
+++ b/app/vendor/psy/psysh/src/ConfigPaths.php
@@ -16,10 +16,10 @@
  */
 class ConfigPaths
 {
-    private $configDir;
-    private $dataDir;
-    private $runtimeDir;
-    private $env;
+    private ?string $configDir = null;
+    private ?string $dataDir = null;
+    private ?string $runtimeDir = null;
+    private EnvInterface $env;
 
     /**
      * ConfigPaths constructor.
@@ -31,7 +31,7 @@ class ConfigPaths
      * @param string[]     $overrides Directory overrides
      * @param EnvInterface $env
      */
-    public function __construct(array $overrides = [], EnvInterface $env = null)
+    public function __construct(array $overrides = [], ?EnvInterface $env = null)
     {
         $this->overrideDirs($overrides);
 
@@ -63,10 +63,8 @@ public function overrideDirs(array $overrides)
 
     /**
      * Get the current home directory.
-     *
-     * @return string|null
      */
-    public function homeDir()
+    public function homeDir(): ?string
     {
         if ($homeDir = $this->getEnv('HOME') ?: $this->windowsHomeDir()) {
             return \strtr($homeDir, '\\', '/');
@@ -75,7 +73,7 @@ public function homeDir()
         return null;
     }
 
-    private function windowsHomeDir()
+    private function windowsHomeDir(): ?string
     {
         if (\defined('PHP_WINDOWS_VERSION_MAJOR')) {
             $homeDrive = $this->getEnv('HOMEDRIVE');
@@ -88,13 +86,16 @@ private function windowsHomeDir()
         return null;
     }
 
-    private function homeConfigDir()
+    private function homeConfigDir(): ?string
     {
         if ($homeConfigDir = $this->getEnv('XDG_CONFIG_HOME')) {
             return $homeConfigDir;
         }
 
         $homeDir = $this->homeDir();
+        if ($homeDir === null) {
+            return null;
+        }
 
         return $homeDir === '/' ? $homeDir.'.config' : $homeDir.'/.config';
     }
@@ -130,7 +131,7 @@ public function configDirs(): array
      *
      * @see self::homeConfigDir
      */
-    public function currentConfigDir(): string
+    public function currentConfigDir(): ?string
     {
         if ($this->configDir !== null) {
             return $this->configDir;
@@ -144,7 +145,7 @@ public function currentConfigDir(): string
             }
         }
 
-        return $configDirs[0];
+        return $configDirs[0] ?? null;
     }
 
     /**
@@ -231,11 +232,13 @@ public function pathDirs(): array
      * If $PATH is unset/empty it defaults to '/usr/sbin:/usr/bin:/sbin:/bin'.
      *
      * @param string $command the executable to locate
-     *
-     * @return string
      */
-    public function which($command)
+    public function which($command): ?string
     {
+        if (!\is_string($command) || $command === '') {
+            return null;
+        }
+
         foreach ($this->pathDirs() as $path) {
             $fullpath = $path.\DIRECTORY_SEPARATOR.$command;
             if (@\is_file($fullpath) && @\is_executable($fullpath)) {
@@ -259,6 +262,7 @@ public function which($command)
      */
     private function allDirNames(array $baseDirs): array
     {
+        $baseDirs = \array_filter($baseDirs);
         $dirs = \array_map(function ($dir) {
             return \strtr($dir, '\\', '/').'/psysh';
         }, $baseDirs);
@@ -362,12 +366,12 @@ public static function touchFileWithMkdir(string $file)
         return $file;
     }
 
-    private function getEnv($key)
+    private function getEnv(string $key)
     {
         return $this->env->get($key);
     }
 
-    private function getEnvArray($key)
+    private function getEnvArray(string $key)
     {
         if ($value = $this->getEnv($key)) {
             return \explode(\PATH_SEPARATOR, $value);
diff --git a/app/vendor/psy/psysh/src/Configuration.php b/app/vendor/psy/psysh/src/Configuration.php
index c6d0bb576..e2fa79fca 100644
--- a/app/vendor/psy/psysh/src/Configuration.php
+++ b/app/vendor/psy/psysh/src/Configuration.php
@@ -47,7 +47,7 @@ class Configuration
     const VERBOSITY_VERY_VERBOSE = 'very_verbose';
     const VERBOSITY_DEBUG = 'debug';
 
-    private static $AVAILABLE_OPTIONS = [
+    private const AVAILABLE_OPTIONS = [
         'codeCleaner',
         'colorMode',
         'configDir',
@@ -80,58 +80,57 @@ class Configuration
         'yolo',
     ];
 
-    private $defaultIncludes;
-    private $configDir;
-    private $dataDir;
-    private $runtimeDir;
-    private $configFile;
-    /** @var string|false */
+    private ?array $defaultIncludes = null;
+    private ?string $configDir = null;
+    private ?string $dataDir = null;
+    private ?string $runtimeDir = null;
+    private ?string $configFile = null;
+    /** @var string|false|null */
     private $historyFile;
-    private $historySize;
-    private $eraseDuplicates;
-    private $manualDbFile;
-    private $hasReadline;
-    private $useReadline;
-    private $useBracketedPaste;
-    private $hasPcntl;
-    private $usePcntl;
-    private $newCommands = [];
-    private $pipedInput;
-    private $pipedOutput;
-    private $rawOutput = false;
-    private $requireSemicolons = false;
-    private $strictTypes = false;
-    private $useUnicode;
-    private $useTabCompletion;
-    private $newMatchers = [];
-    private $errorLoggingLevel = \E_ALL;
-    private $warnOnMultipleConfigs = false;
-    private $colorMode = self::COLOR_MODE_AUTO;
-    private $interactiveMode = self::INTERACTIVE_MODE_AUTO;
-    private $updateCheck;
-    private $startupMessage;
-    private $forceArrayIndexes = false;
+    private int $historySize = 0;
+    private ?bool $eraseDuplicates = null;
+    private ?string $manualDbFile = null;
+    private bool $hasReadline;
+    private ?bool $useReadline = null;
+    private bool $useBracketedPaste = false;
+    private bool $hasPcntl;
+    private ?bool $usePcntl = null;
+    private array $newCommands = [];
+    private ?bool $pipedInput = null;
+    private ?bool $pipedOutput = null;
+    private bool $rawOutput = false;
+    private bool $requireSemicolons = false;
+    private bool $strictTypes = false;
+    private ?bool $useUnicode = null;
+    private ?bool $useTabCompletion = null;
+    private array $newMatchers = [];
+    private int $errorLoggingLevel = \E_ALL;
+    private bool $warnOnMultipleConfigs = false;
+    private string $colorMode = self::COLOR_MODE_AUTO;
+    private string $interactiveMode = self::INTERACTIVE_MODE_AUTO;
+    private ?string $updateCheck = null;
+    private ?string $startupMessage = null;
+    private bool $forceArrayIndexes = false;
     /** @deprecated */
-    private $formatterStyles = [];
-    private $verbosity = self::VERBOSITY_NORMAL;
-    private $yolo = false;
-    /** @var Theme */
-    private $theme;
+    private array $formatterStyles = [];
+    private string $verbosity = self::VERBOSITY_NORMAL;
+    private bool $yolo = false;
+    private ?Theme $theme = null;
 
     // services
-    private $readline;
-    /** @var ShellOutput */
-    private $output;
-    private $shell;
-    private $cleaner;
-    private $pager;
-    private $manualDb;
-    private $presenter;
-    private $autoCompleter;
-    private $checker;
+    private ?Readline\Readline $readline = null;
+    private ?ShellOutput $output = null;
+    private ?Shell $shell = null;
+    private ?CodeCleaner $cleaner = null;
+    /** @var string|OutputPager|false|null */
+    private $pager = null;
+    private ?\PDO $manualDb = null;
+    private ?Presenter $presenter = null;
+    private ?AutoCompleter $autoCompleter = null;
+    private ?Checker $checker = null;
     /** @deprecated */
-    private $prompt;
-    private $configPaths;
+    private ?string $prompt = null;
+    private ConfigPaths $configPaths;
 
     /**
      * Construct a Configuration instance.
@@ -310,6 +309,11 @@ private static function getVerbosityFromInput(InputInterface $input)
                     return self::VERBOSITY_VERY_VERBOSE;
                 case '3':
                 case 'vv': // `-vvv`
+                case 'vvv':
+                case 'vvvv':
+                case 'vvvvv':
+                case 'vvvvvv':
+                case 'vvvvvvv':
                     return self::VERBOSITY_DEBUG;
                 default: // implicitly normal, config file default wins
                     return;
@@ -461,7 +465,7 @@ public function getLocalConfigFile()
      */
     public function loadConfig(array $options)
     {
-        foreach (self::$AVAILABLE_OPTIONS as $option) {
+        foreach (self::AVAILABLE_OPTIONS as $option) {
             if (isset($options[$option])) {
                 $method = 'set'.\ucfirst($option);
                 $this->$method($options[$option]);
@@ -618,17 +622,19 @@ public function setRuntimeDir(string $dir)
     /**
      * Get the shell's temporary directory location.
      *
-     * Defaults to  `/psysh` inside the system's temp dir unless explicitly
+     * Defaults to `/psysh` inside the system's temp dir unless explicitly
      * overridden.
      *
      * @throws RuntimeException if no temporary directory is set and it is not possible to create one
+     *
+     * @param bool $create False to suppress directory creation if it does not exist
      */
-    public function getRuntimeDir(): string
+    public function getRuntimeDir($create = true): string
     {
         $runtimeDir = $this->configPaths->runtimeDir();
 
-        if (!\is_dir($runtimeDir)) {
-            if (!@\mkdir($runtimeDir, 0700, true)) {
+        if ($create) {
+            if (!@ConfigPaths::ensureDir($runtimeDir)) {
                 throw new RuntimeException(\sprintf('Unable to create PsySH runtime directory. Make sure PHP is able to write to %s in order to continue.', \dirname($runtimeDir)));
             }
         }
@@ -652,7 +658,7 @@ public function setHistoryFile(string $file)
      * Defaults to `/history` inside the shell's base config dir unless
      * explicitly overridden.
      */
-    public function getHistoryFile(): string
+    public function getHistoryFile(): ?string
     {
         if (isset($this->historyFile)) {
             return $this->historyFile;
@@ -669,7 +675,12 @@ public function getHistoryFile(): string
             $this->setHistoryFile($files[0]);
         } else {
             // fallback: create our own history file
-            $this->setHistoryFile($this->configPaths->currentConfigDir().'/psysh_history');
+            $configDir = $this->configPaths->currentConfigDir();
+            if ($configDir === null) {
+                return null;
+            }
+
+            $this->setHistoryFile($configDir.'/psysh_history');
         }
 
         return $this->historyFile;
@@ -702,7 +713,7 @@ public function getHistorySize()
      */
     public function setEraseDuplicates(bool $value)
     {
-        $this->eraseDuplicates = (bool) $value;
+        $this->eraseDuplicates = $value;
     }
 
     /**
@@ -808,7 +819,7 @@ public function getReadline(): Readline\Readline
             $this->readline = new $className(
                 $this->getHistoryFile(),
                 $this->getHistorySize(),
-                $this->getEraseDuplicates()
+                $this->getEraseDuplicates() ?? false
             );
         }
 
@@ -1018,7 +1029,11 @@ public function useUnicode(): bool
      */
     public function setErrorLoggingLevel($errorLoggingLevel)
     {
-        $this->errorLoggingLevel = (\E_ALL | \E_STRICT) & $errorLoggingLevel;
+        if (\PHP_VERSION_ID < 80400) {
+            $this->errorLoggingLevel = (\E_ALL | \E_STRICT) & $errorLoggingLevel;
+        } else {
+            $this->errorLoggingLevel = \E_ALL & $errorLoggingLevel;
+        }
     }
 
     /**
@@ -1253,6 +1268,18 @@ public function getPager()
                 $this->pager = $pager;
             } elseif ($less = $this->configPaths->which('less')) {
                 // check for the presence of less...
+
+                // n.b. The busybox less implementation is a bit broken, so
+                // let's not use it by default.
+                //
+                // See https://github.com/bobthecow/psysh/issues/778
+                if (@\is_link($less)) {
+                    $link = @\readlink($less);
+                    if ($link !== false && \strpos($link, 'busybox') !== false) {
+                        return false;
+                    }
+                }
+
                 $this->pager = $less.' -R -F -X';
             }
         }
@@ -1631,7 +1658,12 @@ public function setUpdateCheck(string $interval)
      */
     public function getUpdateCheckCacheFile()
     {
-        return ConfigPaths::touchFileWithMkdir($this->configPaths->currentConfigDir().'/update_check.json');
+        $configDir = $this->configPaths->currentConfigDir();
+        if ($configDir === null) {
+            return false;
+        }
+
+        return ConfigPaths::touchFileWithMkdir($configDir.'/update_check.json');
     }
 
     /**
diff --git a/app/vendor/psy/psysh/src/Context.php b/app/vendor/psy/psysh/src/Context.php
index da698da30..1062448e7 100644
--- a/app/vendor/psy/psysh/src/Context.php
+++ b/app/vendor/psy/psysh/src/Context.php
@@ -19,29 +19,28 @@
  */
 class Context
 {
-    private static $specialNames = ['_', '_e', '__out', '__psysh__', 'this'];
+    private const SPECIAL_NAMES = ['_', '_e', '__out', '__psysh__', 'this'];
 
     // Include a very limited number of command-scope magic variable names.
     // This might be a bad idea, but future me can sort it out.
-    private static $commandScopeNames = [
+    private const COMMAND_SCOPE_NAMES = [
         '__function', '__method', '__class', '__namespace', '__file', '__line', '__dir',
     ];
 
-    private $scopeVariables = [];
-    private $commandScopeVariables = [];
-    private $returnValue;
-    private $lastException;
-    private $lastStdout;
-    private $boundObject;
-    private $boundClass;
+    private array $scopeVariables = [];
+    private array $commandScopeVariables = [];
+    /** @var mixed */
+    private $returnValue = null;
+    private ?\Throwable $lastException = null;
+    private ?string $lastStdout = null;
+    private ?object $boundObject = null;
+    private ?string $boundClass = null;
 
     /**
      * Get a context variable.
      *
      * @throws \InvalidArgumentException If the variable is not found in the current context
      *
-     * @param string $name
-     *
      * @return mixed
      */
     public function get(string $name)
@@ -127,16 +126,14 @@ public function getSpecialVariables(): array
      *
      * This method does *not* set any of the magic variables: $_, $_e, $__out,
      * $__class, $__file, etc.
-     *
-     * @param array $vars
      */
     public function setAll(array $vars)
     {
-        foreach (self::$specialNames as $key) {
+        foreach (self::SPECIAL_NAMES as $key) {
             unset($vars[$key]);
         }
 
-        foreach (self::$commandScopeNames as $key) {
+        foreach (self::COMMAND_SCOPE_NAMES as $key) {
             unset($vars[$key]);
         }
 
@@ -191,8 +188,6 @@ public function getLastException()
 
     /**
      * Set the most recent output from evaluated code.
-     *
-     * @param string $lastStdout
      */
     public function setLastStdout(string $lastStdout)
     {
@@ -263,15 +258,13 @@ public function getBoundClass()
 
     /**
      * Set command-scope magic variables: $__class, $__file, etc.
-     *
-     * @param array $commandScopeVariables
      */
     public function setCommandScopeVariables(array $commandScopeVariables)
     {
         $vars = [];
         foreach ($commandScopeVariables as $key => $value) {
             // kind of type check
-            if (\is_scalar($value) && \in_array($key, self::$commandScopeNames)) {
+            if (\is_scalar($value) && \in_array($key, self::COMMAND_SCOPE_NAMES)) {
                 $vars[$key] = $value;
             }
         }
@@ -297,16 +290,14 @@ public function getCommandScopeVariables(): array
      */
     public function getUnusedCommandScopeVariableNames(): array
     {
-        return \array_diff(self::$commandScopeNames, \array_keys($this->commandScopeVariables));
+        return \array_diff(self::COMMAND_SCOPE_NAMES, \array_keys($this->commandScopeVariables));
     }
 
     /**
      * Check whether a variable name is a magic variable.
-     *
-     * @param string $name
      */
     public static function isSpecialVariableName(string $name): bool
     {
-        return \in_array($name, self::$specialNames) || \in_array($name, self::$commandScopeNames);
+        return \in_array($name, self::SPECIAL_NAMES) || \in_array($name, self::COMMAND_SCOPE_NAMES);
     }
 }
diff --git a/app/vendor/psy/psysh/src/Exception/BreakException.php b/app/vendor/psy/psysh/src/Exception/BreakException.php
index 4061442a8..1b84a83a9 100644
--- a/app/vendor/psy/psysh/src/Exception/BreakException.php
+++ b/app/vendor/psy/psysh/src/Exception/BreakException.php
@@ -16,12 +16,12 @@
  */
 class BreakException extends \Exception implements Exception
 {
-    private $rawMessage;
+    private string $rawMessage;
 
     /**
      * {@inheritdoc}
      */
-    public function __construct($message = '', $code = 0, \Throwable $previous = null)
+    public function __construct($message = '', $code = 0, ?\Throwable $previous = null)
     {
         $this->rawMessage = $message;
         parent::__construct(\sprintf('Exit:  %s', $message), $code, $previous);
diff --git a/app/vendor/psy/psysh/src/Exception/ErrorException.php b/app/vendor/psy/psysh/src/Exception/ErrorException.php
index 26e886a87..f32da850d 100644
--- a/app/vendor/psy/psysh/src/Exception/ErrorException.php
+++ b/app/vendor/psy/psysh/src/Exception/ErrorException.php
@@ -16,7 +16,7 @@
  */
 class ErrorException extends \ErrorException implements Exception
 {
-    private $rawMessage;
+    private string $rawMessage;
 
     /**
      * Construct a Psy ErrorException.
@@ -28,7 +28,7 @@ class ErrorException extends \ErrorException implements Exception
      * @param int|null        $lineno   (default: null)
      * @param \Throwable|null $previous (default: null)
      */
-    public function __construct($message = '', $code = 0, $severity = 1, $filename = null, $lineno = null, \Throwable $previous = null)
+    public function __construct($message = '', $code = 0, $severity = 1, $filename = null, $lineno = null, ?\Throwable $previous = null)
     {
         $this->rawMessage = $message;
 
@@ -37,10 +37,6 @@ public function __construct($message = '', $code = 0, $severity = 1, $filename =
         }
 
         switch ($severity) {
-            case \E_STRICT:
-                $type = 'Strict error';
-                break;
-
             case \E_NOTICE:
             case \E_USER_NOTICE:
                 $type = 'Notice';
@@ -63,6 +59,10 @@ public function __construct($message = '', $code = 0, $severity = 1, $filename =
                 break;
 
             default:
+                if (\PHP_VERSION_ID < 80400 && $severity === \E_STRICT) {
+                    $type = 'Strict error';
+                    break;
+                }
                 $type = 'Error';
                 break;
         }
diff --git a/app/vendor/psy/psysh/src/Exception/FatalErrorException.php b/app/vendor/psy/psysh/src/Exception/FatalErrorException.php
index 21b223488..b8af5bbe3 100644
--- a/app/vendor/psy/psysh/src/Exception/FatalErrorException.php
+++ b/app/vendor/psy/psysh/src/Exception/FatalErrorException.php
@@ -16,7 +16,7 @@
  */
 class FatalErrorException extends \ErrorException implements Exception
 {
-    private $rawMessage;
+    private string $rawMessage;
 
     /**
      * Create a fatal error.
@@ -28,7 +28,7 @@ class FatalErrorException extends \ErrorException implements Exception
      * @param int|null        $lineno   (default: null)
      * @param \Throwable|null $previous (default: null)
      */
-    public function __construct($message = '', $code = 0, $severity = 1, $filename = null, $lineno = null, \Throwable $previous = null)
+    public function __construct($message = '', $code = 0, $severity = 1, $filename = null, $lineno = null, ?\Throwable $previous = null)
     {
         // Since these are basically always PHP Parser Node line numbers, treat -1 as null.
         if ($lineno === -1) {
diff --git a/app/vendor/psy/psysh/src/Exception/RuntimeException.php b/app/vendor/psy/psysh/src/Exception/RuntimeException.php
index 6228813b0..b8ea38790 100644
--- a/app/vendor/psy/psysh/src/Exception/RuntimeException.php
+++ b/app/vendor/psy/psysh/src/Exception/RuntimeException.php
@@ -16,7 +16,7 @@
  */
 class RuntimeException extends \RuntimeException implements Exception
 {
-    private $rawMessage;
+    private string $rawMessage;
 
     /**
      * Make this bad boy.
@@ -25,7 +25,7 @@ class RuntimeException extends \RuntimeException implements Exception
      * @param int             $code     (default: 0)
      * @param \Throwable|null $previous (default: null)
      */
-    public function __construct(string $message = '', int $code = 0, \Throwable $previous = null)
+    public function __construct(string $message = '', int $code = 0, ?\Throwable $previous = null)
     {
         $this->rawMessage = $message;
         parent::__construct($message, $code, $previous);
diff --git a/app/vendor/psy/psysh/src/Exception/UnexpectedTargetException.php b/app/vendor/psy/psysh/src/Exception/UnexpectedTargetException.php
index 9d2b70d11..b5c0d15c8 100644
--- a/app/vendor/psy/psysh/src/Exception/UnexpectedTargetException.php
+++ b/app/vendor/psy/psysh/src/Exception/UnexpectedTargetException.php
@@ -13,6 +13,7 @@
 
 class UnexpectedTargetException extends RuntimeException
 {
+    /** @var mixed */
     private $target;
 
     /**
@@ -21,7 +22,7 @@ class UnexpectedTargetException extends RuntimeException
      * @param int             $code     (default: 0)
      * @param \Throwable|null $previous (default: null)
      */
-    public function __construct($target, string $message = '', int $code = 0, \Throwable $previous = null)
+    public function __construct($target, string $message = '', int $code = 0, ?\Throwable $previous = null)
     {
         $this->target = $target;
         parent::__construct($message, $code, $previous);
diff --git a/app/vendor/psy/psysh/src/ExecutionClosure.php b/app/vendor/psy/psysh/src/ExecutionClosure.php
index 837e931be..5ae354acd 100644
--- a/app/vendor/psy/psysh/src/ExecutionClosure.php
+++ b/app/vendor/psy/psysh/src/ExecutionClosure.php
@@ -18,7 +18,7 @@ class ExecutionClosure
 {
     const NOOP_INPUT = 'return null;';
 
-    private $closure;
+    private \Closure $closure;
 
     /**
      * @param Shell $__psysh__
diff --git a/app/vendor/psy/psysh/src/ExecutionLoop/ProcessForker.php b/app/vendor/psy/psysh/src/ExecutionLoop/ProcessForker.php
index 3d61693c4..308b71d77 100644
--- a/app/vendor/psy/psysh/src/ExecutionLoop/ProcessForker.php
+++ b/app/vendor/psy/psysh/src/ExecutionLoop/ProcessForker.php
@@ -23,10 +23,11 @@
  */
 class ProcessForker extends AbstractListener
 {
-    private $savegame;
+    private ?int $savegame = null;
+    /** @var resource */
     private $up;
 
-    private static $pcntlFunctions = [
+    private const PCNTL_FUNCTIONS = [
         'pcntl_fork',
         'pcntl_signal_dispatch',
         'pcntl_signal',
@@ -34,7 +35,7 @@ class ProcessForker extends AbstractListener
         'pcntl_wexitstatus',
     ];
 
-    private static $posixFunctions = [
+    private const POSIX_FUNCTIONS = [
         'posix_getpid',
         'posix_kill',
     ];
@@ -52,7 +53,7 @@ public static function isSupported(): bool
      */
     public static function isPcntlSupported(): bool
     {
-        foreach (self::$pcntlFunctions as $func) {
+        foreach (self::PCNTL_FUNCTIONS as $func) {
             if (!\function_exists($func)) {
                 return false;
             }
@@ -66,7 +67,7 @@ public static function isPcntlSupported(): bool
      */
     public static function disabledPcntlFunctions()
     {
-        return self::checkDisabledFunctions(self::$pcntlFunctions);
+        return self::checkDisabledFunctions(self::PCNTL_FUNCTIONS);
     }
 
     /**
@@ -74,7 +75,7 @@ public static function disabledPcntlFunctions()
      */
     public static function isPosixSupported(): bool
     {
-        foreach (self::$posixFunctions as $func) {
+        foreach (self::POSIX_FUNCTIONS as $func) {
             if (!\function_exists($func)) {
                 return false;
             }
@@ -88,7 +89,7 @@ public static function isPosixSupported(): bool
      */
     public static function disabledPosixFunctions()
     {
-        return self::checkDisabledFunctions(self::$posixFunctions);
+        return self::checkDisabledFunctions(self::POSIX_FUNCTIONS);
     }
 
     private static function checkDisabledFunctions(array $functions): array
diff --git a/app/vendor/psy/psysh/src/ExecutionLoop/RunkitReloader.php b/app/vendor/psy/psysh/src/ExecutionLoop/RunkitReloader.php
index 987fb1cb4..4ba996a54 100644
--- a/app/vendor/psy/psysh/src/ExecutionLoop/RunkitReloader.php
+++ b/app/vendor/psy/psysh/src/ExecutionLoop/RunkitReloader.php
@@ -11,6 +11,7 @@
 
 namespace Psy\ExecutionLoop;
 
+use PhpParser\Parser;
 use Psy\Exception\ParseErrorException;
 use Psy\ParserFactory;
 use Psy\Shell;
@@ -22,8 +23,8 @@
  */
 class RunkitReloader extends AbstractListener
 {
-    private $parser;
-    private $timestamps = [];
+    private Parser $parser;
+    private array $timestamps = [];
 
     /**
      * Only enabled if Runkit is installed.
diff --git a/app/vendor/psy/psysh/src/Formatter/CodeFormatter.php b/app/vendor/psy/psysh/src/Formatter/CodeFormatter.php
index aa70f1bbf..98db81e3a 100644
--- a/app/vendor/psy/psysh/src/Formatter/CodeFormatter.php
+++ b/app/vendor/psy/psysh/src/Formatter/CodeFormatter.php
@@ -35,7 +35,7 @@ class CodeFormatter implements ReflectorFormatter
     const HIGHLIGHT_COMMENT = 'code_comment';
     const HIGHLIGHT_INLINE_HTML = 'inline_html';
 
-    private static $tokenMap = [
+    private const TOKEN_MAP = [
         // Not highlighted
         \T_OPEN_TAG           => self::HIGHLIGHT_DEFAULT,
         \T_OPEN_TAG_WITH_ECHO => self::HIGHLIGHT_DEFAULT,
@@ -103,7 +103,7 @@ public static function format(\Reflector $reflector): string
      *
      * @return string formatted code
      */
-    public static function formatCode(string $code, int $startLine = 1, int $endLine = null, int $markLine = null): string
+    public static function formatCode(string $code, int $startLine = 1, ?int $endLine = null, ?int $markLine = null): string
     {
         $spans = self::tokenizeSpans($code);
         $lines = self::splitLines($spans, $startLine, $endLine);
@@ -187,8 +187,8 @@ private static function nextHighlightType($token, $currentType)
                 return $currentType;
             }
 
-            if (\array_key_exists($token[0], self::$tokenMap)) {
-                return self::$tokenMap[$token[0]];
+            if (\array_key_exists($token[0], self::TOKEN_MAP)) {
+                return self::TOKEN_MAP[$token[0]];
             }
         }
 
@@ -206,7 +206,7 @@ private static function nextHighlightType($token, $currentType)
      *
      * @return \Generator lines, each an array of [$spanType, $spanText] pairs
      */
-    private static function splitLines(\Generator $spans, int $startLine = 1, int $endLine = null): \Generator
+    private static function splitLines(\Generator $spans, int $startLine = 1, ?int $endLine = null): \Generator
     {
         $lineNum = 1;
         $buffer = [];
@@ -273,7 +273,7 @@ private static function formatLines(\Generator $spanLines): \Generator
      *
      * @return \Generator Numbered, formatted lines
      */
-    private static function numberLines(\Generator $lines, int $markLine = null): \Generator
+    private static function numberLines(\Generator $lines, ?int $markLine = null): \Generator
     {
         $lines = \iterator_to_array($lines);
 
diff --git a/app/vendor/psy/psysh/src/Formatter/DocblockFormatter.php b/app/vendor/psy/psysh/src/Formatter/DocblockFormatter.php
index 282f463e2..9a526d1a9 100644
--- a/app/vendor/psy/psysh/src/Formatter/DocblockFormatter.php
+++ b/app/vendor/psy/psysh/src/Formatter/DocblockFormatter.php
@@ -19,7 +19,7 @@
  */
 class DocblockFormatter implements ReflectorFormatter
 {
-    private static $vectorParamTemplates = [
+    private const VECTOR_PARAM_TEMPLATES = [
         'type' => 'info',
         'var'  => 'strong',
     ];
@@ -134,11 +134,11 @@ private static function formatTags(array $skip, array $tags): string
      */
     private static function getVectorParamTemplate(string $type, int $max): string
     {
-        if (!isset(self::$vectorParamTemplates[$type])) {
+        if (!isset(self::VECTOR_PARAM_TEMPLATES[$type])) {
             return \sprintf('%%-%ds', $max);
         }
 
-        return \sprintf('<%s>%%-%ds', self::$vectorParamTemplates[$type], $max, self::$vectorParamTemplates[$type]);
+        return \sprintf('<%s>%%-%ds', self::VECTOR_PARAM_TEMPLATES[$type], $max, self::VECTOR_PARAM_TEMPLATES[$type]);
     }
 
     /**
diff --git a/app/vendor/psy/psysh/src/Formatter/SignatureFormatter.php b/app/vendor/psy/psysh/src/Formatter/SignatureFormatter.php
index 182816b00..de29f2c27 100644
--- a/app/vendor/psy/psysh/src/Formatter/SignatureFormatter.php
+++ b/app/vendor/psy/psysh/src/Formatter/SignatureFormatter.php
@@ -266,7 +266,7 @@ private static function formatFunctionParams(\ReflectionFunctionAbstract $reflec
             try {
                 if (\method_exists($param, 'getType')) {
                     // Only include the inquisitive nullable type iff param default value is not null.
-                    $defaultIsNull = $param->isOptional() && $param->isDefaultValueAvailable() && $param->getDefaultValue() === null;
+                    $defaultIsNull = $param->isOptional() && $param->isDefaultValueAvailable() && @$param->getDefaultValue() === null;
                     $hint = self::formatReflectionType($param->getType(), !$defaultIsNull);
                 } else {
                     if ($param->isArray()) {
@@ -296,7 +296,7 @@ private static function formatFunctionParams(\ReflectionFunctionAbstract $reflec
                     $value = 'unknown';
                     $typeStyle = 'urgent';
                 } else {
-                    $value = $param->getDefaultValue();
+                    $value = @$param->getDefaultValue();
                     $typeStyle = self::getTypeStyle($value);
                     $value = \is_array($value) ? '[]' : ($value === null ? 'null' : \var_export($value, true));
                 }
diff --git a/app/vendor/psy/psysh/src/Formatter/TraceFormatter.php b/app/vendor/psy/psysh/src/Formatter/TraceFormatter.php
index f9859225b..a30b4b8c3 100644
--- a/app/vendor/psy/psysh/src/Formatter/TraceFormatter.php
+++ b/app/vendor/psy/psysh/src/Formatter/TraceFormatter.php
@@ -29,7 +29,7 @@ class TraceFormatter
      *
      * @return string[] Formatted stacktrace lines
      */
-    public static function formatTrace(\Throwable $throwable, FilterOptions $filter = null, int $count = null, bool $includePsy = true): array
+    public static function formatTrace(\Throwable $throwable, ?FilterOptions $filter = null, ?int $count = null, bool $includePsy = true): array
     {
         if ($cwd = \getcwd()) {
             $cwd = \rtrim($cwd, \DIRECTORY_SEPARATOR).\DIRECTORY_SEPARATOR;
diff --git a/app/vendor/psy/psysh/src/Input/CodeArgument.php b/app/vendor/psy/psysh/src/Input/CodeArgument.php
index c41534782..2654c9437 100644
--- a/app/vendor/psy/psysh/src/Input/CodeArgument.php
+++ b/app/vendor/psy/psysh/src/Input/CodeArgument.php
@@ -39,7 +39,7 @@ class CodeArgument extends InputArgument
      *
      * @throws \InvalidArgumentException When argument mode is not valid
      */
-    public function __construct(string $name, int $mode = null, string $description = '', $default = null)
+    public function __construct(string $name, ?int $mode = null, string $description = '', $default = null)
     {
         if ($mode & InputArgument::IS_ARRAY) {
             throw new \InvalidArgumentException('Argument mode IS_ARRAY is not valid');
diff --git a/app/vendor/psy/psysh/src/Input/FilterOptions.php b/app/vendor/psy/psysh/src/Input/FilterOptions.php
index 64eee3f80..db79c3455 100644
--- a/app/vendor/psy/psysh/src/Input/FilterOptions.php
+++ b/app/vendor/psy/psysh/src/Input/FilterOptions.php
@@ -21,10 +21,10 @@
  */
 class FilterOptions
 {
-    private $filter = false;
-    private $pattern;
-    private $insensitive;
-    private $invert;
+    private bool $filter = false;
+    private ?string $pattern = null;
+    private bool $insensitive = false;
+    private bool $invert = false;
 
     /**
      * Get input option definitions for filtering.
@@ -85,7 +85,7 @@ public function hasFilter(): bool
      * @param string $string
      * @param array  $matches
      */
-    public function match(string $string, array &$matches = null): bool
+    public function match(string $string, ?array &$matches = null): bool
     {
         return $this->filter === false || (\preg_match($this->pattern, $string, $matches) xor $this->invert);
     }
diff --git a/app/vendor/psy/psysh/src/Input/ShellInput.php b/app/vendor/psy/psysh/src/Input/ShellInput.php
index 9b8bf81d7..17a39fc6f 100644
--- a/app/vendor/psy/psysh/src/Input/ShellInput.php
+++ b/app/vendor/psy/psysh/src/Input/ShellInput.php
@@ -21,14 +21,14 @@ class ShellInput extends StringInput
 {
     public const REGEX_STRING = '([^\s]+?)(?:\s|(?getPipe();
         if (false === @\fwrite($pipe, $message.($newline ? \PHP_EOL : ''))) {
             // @codeCoverageIgnoreStart
-            // should never happen
+            // When the message is sufficiently long, writing to the pipe fails
+            // if the pager process is closed before the entire message is read.
+            //
+            // This is a normal condition, so we just close the pipe and return.
             $this->close();
-            throw new \RuntimeException('Unable to write output');
+
+            return;
             // @codeCoverageIgnoreEnd
         }
 
diff --git a/app/vendor/psy/psysh/src/Output/ShellOutput.php b/app/vendor/psy/psysh/src/Output/ShellOutput.php
index 2ef575dce..6dd91a47a 100644
--- a/app/vendor/psy/psysh/src/Output/ShellOutput.php
+++ b/app/vendor/psy/psysh/src/Output/ShellOutput.php
@@ -22,13 +22,9 @@ class ShellOutput extends ConsoleOutput
 {
     const NUMBER_LINES = 128;
 
-    private $paging = 0;
-
-    /** @var OutputPager */
-    private $pager;
-
-    /** @var Theme */
-    private $theme;
+    private int $paging = 0;
+    private OutputPager $pager;
+    private Theme $theme;
 
     /**
      * Construct a ShellOutput instance.
@@ -38,7 +34,7 @@ class ShellOutput extends ConsoleOutput
      * @param OutputFormatterInterface|null $formatter (default: null)
      * @param string|OutputPager|null       $pager     (default: null)
      */
-    public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null, OutputFormatterInterface $formatter = null, $pager = null, $theme = null)
+    public function __construct($verbosity = self::VERBOSITY_NORMAL, $decorated = null, ?OutputFormatterInterface $formatter = null, $pager = null, $theme = null)
     {
         parent::__construct($verbosity, $decorated, $formatter);
 
@@ -156,7 +152,8 @@ public function write($messages, $newline = false, $type = 0): void
      */
     public function doWrite($message, $newline): void
     {
-        if ($this->paging > 0) {
+        // @todo Update OutputPager interface to require doWrite
+        if ($this->paging > 0 && $this->pager instanceof ProcOutputPager) {
             $this->pager->doWrite($message, $newline);
         } else {
             parent::doWrite($message, $newline);
diff --git a/app/vendor/psy/psysh/src/Output/Theme.php b/app/vendor/psy/psysh/src/Output/Theme.php
index 01023f2ec..3c84041e0 100644
--- a/app/vendor/psy/psysh/src/Output/Theme.php
+++ b/app/vendor/psy/psysh/src/Output/Theme.php
@@ -74,16 +74,16 @@ class Theme
 
     const ERROR_STYLES = ['info', 'warning', 'error', 'whisper', 'class'];
 
-    private $compact = false;
+    private bool $compact = false;
 
-    private $prompt = '> ';
-    private $bufferPrompt = '. ';
-    private $replayPrompt = '- ';
-    private $returnValue = '= ';
+    private string $prompt = '> ';
+    private string $bufferPrompt = '. ';
+    private string $replayPrompt = '- ';
+    private string $returnValue = '= ';
 
-    private $grayFallback = 'blue';
+    private string $grayFallback = 'blue';
 
-    private $styles = [];
+    private array $styles = [];
 
     /**
      * @param string|array $config theme name or config options
diff --git a/app/vendor/psy/psysh/src/Readline/GNUReadline.php b/app/vendor/psy/psysh/src/Readline/GNUReadline.php
index 877e1a309..52aa9e822 100644
--- a/app/vendor/psy/psysh/src/Readline/GNUReadline.php
+++ b/app/vendor/psy/psysh/src/Readline/GNUReadline.php
@@ -22,10 +22,9 @@ class GNUReadline implements Readline
 {
     /** @var string|false */
     protected $historyFile;
-    /** @var int */
-    protected $historySize;
-    /** @var bool */
-    protected $eraseDups;
+    protected int $historySize;
+    // @todo better type for this
+    protected ?bool $eraseDups;
 
     /**
      * GNU Readline is supported iff `readline_list_history` is defined. PHP
@@ -105,7 +104,7 @@ public function readHistory(): bool
     /**
      * {@inheritdoc}
      */
-    public function readline(string $prompt = null)
+    public function readline(?string $prompt = null)
     {
         return \readline($prompt);
     }
diff --git a/app/vendor/psy/psysh/src/Readline/Hoa/AutocompleterPath.php b/app/vendor/psy/psysh/src/Readline/Hoa/AutocompleterPath.php
index a922b7898..f1eaca0ea 100644
--- a/app/vendor/psy/psysh/src/Readline/Hoa/AutocompleterPath.php
+++ b/app/vendor/psy/psysh/src/Readline/Hoa/AutocompleterPath.php
@@ -62,8 +62,8 @@ class AutocompleterPath implements Autocompleter
      * Constructor.
      */
     public function __construct(
-        string $root = null,
-        \Closure $iteratorFactory = null
+        ?string $root = null,
+        ?\Closure $iteratorFactory = null
     ) {
         if (null === $root) {
             $root = static::PWD;
diff --git a/app/vendor/psy/psysh/src/Readline/Hoa/ConsoleCursor.php b/app/vendor/psy/psysh/src/Readline/Hoa/ConsoleCursor.php
index 6745e257a..8828d8b6a 100644
--- a/app/vendor/psy/psysh/src/Readline/Hoa/ConsoleCursor.php
+++ b/app/vendor/psy/psysh/src/Readline/Hoa/ConsoleCursor.php
@@ -154,7 +154,7 @@ public static function move(string $steps, int $repeat = 1)
      * Move to the line X and the column Y.
      * If null, use the current coordinate.
      */
-    public static function moveTo(int $x = null, int $y = null)
+    public static function moveTo(?int $x = null, ?int $y = null)
     {
         if (null === $x || null === $y) {
             $position = static::getPosition();
diff --git a/app/vendor/psy/psysh/src/Readline/Hoa/ConsoleInput.php b/app/vendor/psy/psysh/src/Readline/Hoa/ConsoleInput.php
index faa5ce18e..6b00e2ad5 100644
--- a/app/vendor/psy/psysh/src/Readline/Hoa/ConsoleInput.php
+++ b/app/vendor/psy/psysh/src/Readline/Hoa/ConsoleInput.php
@@ -53,7 +53,7 @@ class ConsoleInput implements StreamIn
     /**
      * Wraps an `Hoa\Stream\IStream\In` stream.
      */
-    public function __construct(StreamIn $input = null)
+    public function __construct(?StreamIn $input = null)
     {
         if (null === $input) {
             if (\defined('STDIN') &&
diff --git a/app/vendor/psy/psysh/src/Readline/Hoa/ConsoleOutput.php b/app/vendor/psy/psysh/src/Readline/Hoa/ConsoleOutput.php
index fbba894c9..b7ed27951 100644
--- a/app/vendor/psy/psysh/src/Readline/Hoa/ConsoleOutput.php
+++ b/app/vendor/psy/psysh/src/Readline/Hoa/ConsoleOutput.php
@@ -57,7 +57,7 @@ class ConsoleOutput implements StreamOut
     /**
      * Wraps an `Hoa\Stream\IStream\Out` stream.
      */
-    public function __construct(StreamOut $output = null)
+    public function __construct(?StreamOut $output = null)
     {
         $this->_output = $output;
 
diff --git a/app/vendor/psy/psysh/src/Readline/Hoa/ConsoleProcessus.php b/app/vendor/psy/psysh/src/Readline/Hoa/ConsoleProcessus.php
index 69bf1ddb1..da7298547 100644
--- a/app/vendor/psy/psysh/src/Readline/Hoa/ConsoleProcessus.php
+++ b/app/vendor/psy/psysh/src/Readline/Hoa/ConsoleProcessus.php
@@ -245,10 +245,10 @@ class ConsoleProcessus extends Stream implements StreamIn, StreamOut, StreamPath
      */
     public function __construct(
         string $command,
-        array $options = null,
-        array $descriptors = null,
-        string $cwd = null,
-        array $environment = null,
+        ?array $options = null,
+        ?array $descriptors = null,
+        ?string $cwd = null,
+        ?array $environment = null,
         int $timeout = 30
     ) {
         $this->setCommand($command);
@@ -285,7 +285,7 @@ public function __construct(
     /**
      * Open the stream and return the associated resource.
      */
-    protected function &_open(string $streamName, StreamContext $context = null)
+    protected function &_open(string $streamName, ?StreamContext $context = null)
     {
         $out = @\proc_open(
             $streamName,
@@ -527,7 +527,7 @@ public function readFloat(int $length = 1, int $pipe = 1)
      * Read an array.
      * Alias of the $this->scanf() method.
      */
-    public function readArray(string $format = null, int $pipe = 1)
+    public function readArray(?string $format = null, int $pipe = 1)
     {
         return $this->scanf($format, $pipe);
     }
diff --git a/app/vendor/psy/psysh/src/Readline/Hoa/Exception.php b/app/vendor/psy/psysh/src/Readline/Hoa/Exception.php
index e0b8bc8ca..0a08f7a9b 100644
--- a/app/vendor/psy/psysh/src/Readline/Hoa/Exception.php
+++ b/app/vendor/psy/psysh/src/Readline/Hoa/Exception.php
@@ -52,7 +52,7 @@ public function __construct(
         string $message,
         int $code = 0,
         $arguments = [],
-        \Throwable $previous = null
+        ?\Throwable $previous = null
     ) {
         parent::__construct($message, $code, $arguments, $previous);
 
diff --git a/app/vendor/psy/psysh/src/Readline/Hoa/ExceptionIdle.php b/app/vendor/psy/psysh/src/Readline/Hoa/ExceptionIdle.php
index 1d44c4350..29497f06e 100644
--- a/app/vendor/psy/psysh/src/Readline/Hoa/ExceptionIdle.php
+++ b/app/vendor/psy/psysh/src/Readline/Hoa/ExceptionIdle.php
@@ -79,7 +79,7 @@ public function __construct(
         string $message,
         int $code = 0,
         $arguments = [],
-        \Exception $previous = null
+        ?\Exception $previous = null
     ) {
         $this->_tmpArguments = $arguments;
         parent::__construct($message, $code, $previous);
diff --git a/app/vendor/psy/psysh/src/Readline/Hoa/File.php b/app/vendor/psy/psysh/src/Readline/Hoa/File.php
index 96b8c4d54..1db395da5 100644
--- a/app/vendor/psy/psysh/src/Readline/Hoa/File.php
+++ b/app/vendor/psy/psysh/src/Readline/Hoa/File.php
@@ -105,7 +105,7 @@ abstract class File extends FileGeneric implements StreamBufferable, StreamLocka
     public function __construct(
         string $streamName,
         string $mode,
-        string $context = null,
+        ?string $context = null,
         bool $wait = false
     ) {
         $this->setMode($mode);
@@ -140,7 +140,7 @@ public function __construct(
     /**
      * Open the stream and return the associated resource.
      */
-    protected function &_open(string $streamName, StreamContext $context = null)
+    protected function &_open(string $streamName, ?StreamContext $context = null)
     {
         if (\substr($streamName, 0, 4) === 'file' &&
             false === \is_dir(\dirname($streamName))) {
@@ -181,7 +181,7 @@ protected function _close(): bool
      * Start a new buffer.
      * The callable acts like a light filter.
      */
-    public function newBuffer($callable = null, int $size = null): int
+    public function newBuffer($callable = null, ?int $size = null): int
     {
         $this->setStreamBuffer($size);
 
diff --git a/app/vendor/psy/psysh/src/Readline/Hoa/FileDirectory.php b/app/vendor/psy/psysh/src/Readline/Hoa/FileDirectory.php
index e7191410e..31adb00f3 100644
--- a/app/vendor/psy/psysh/src/Readline/Hoa/FileDirectory.php
+++ b/app/vendor/psy/psysh/src/Readline/Hoa/FileDirectory.php
@@ -66,7 +66,7 @@ class FileDirectory extends FileGeneric
     public function __construct(
         string $streamName,
         string $mode = self::MODE_READ,
-        string $context = null,
+        ?string $context = null,
         bool $wait = false
     ) {
         $this->setMode($mode);
@@ -78,7 +78,7 @@ public function __construct(
     /**
      * Open the stream and return the associated resource.
      */
-    protected function &_open(string $streamName, StreamContext $context = null)
+    protected function &_open(string $streamName, ?StreamContext $context = null)
     {
         if (false === \is_dir($streamName)) {
             if ($this->getMode() === self::MODE_READ) {
@@ -185,7 +185,7 @@ public function delete(): bool
     public static function create(
         string $name,
         string $mode = self::MODE_CREATE_RECURSIVE,
-        string $context = null
+        ?string $context = null
     ): bool {
         if (true === \is_dir($name)) {
             return true;
diff --git a/app/vendor/psy/psysh/src/Readline/Hoa/FileGeneric.php b/app/vendor/psy/psysh/src/Readline/Hoa/FileGeneric.php
index aa3b70cf7..767b8045d 100644
--- a/app/vendor/psy/psysh/src/Readline/Hoa/FileGeneric.php
+++ b/app/vendor/psy/psysh/src/Readline/Hoa/FileGeneric.php
@@ -229,7 +229,7 @@ public static function clearAllStatisticCaches()
     /**
      * Set access and modification time of file.
      */
-    public function touch(int $time = null, int $atime = null): bool
+    public function touch(?int $time = null, ?int $atime = null): bool
     {
         if (null === $time) {
             $time = \time();
@@ -333,7 +333,7 @@ public function changeOwner($user): bool
     /**
      * Change the current umask.
      */
-    public static function umask(int $umask = null): int
+    public static function umask(?int $umask = null): int
     {
         if (null === $umask) {
             return \umask();
diff --git a/app/vendor/psy/psysh/src/Readline/Hoa/FileLink.php b/app/vendor/psy/psysh/src/Readline/Hoa/FileLink.php
index 21a4485f9..e48a41115 100644
--- a/app/vendor/psy/psysh/src/Readline/Hoa/FileLink.php
+++ b/app/vendor/psy/psysh/src/Readline/Hoa/FileLink.php
@@ -49,7 +49,7 @@ class FileLink extends File
     public function __construct(
         string $streamName,
         string $mode,
-        string $context = null,
+        ?string $context = null,
         bool $wait = false
     ) {
         if (!\is_link($streamName)) {
diff --git a/app/vendor/psy/psysh/src/Readline/Hoa/FileLinkRead.php b/app/vendor/psy/psysh/src/Readline/Hoa/FileLinkRead.php
index 37bb514cb..ffa4ebcf0 100644
--- a/app/vendor/psy/psysh/src/Readline/Hoa/FileLinkRead.php
+++ b/app/vendor/psy/psysh/src/Readline/Hoa/FileLinkRead.php
@@ -57,7 +57,7 @@ class FileLinkRead extends FileLink implements StreamIn
     public function __construct(
         string $streamName,
         string $mode = parent::MODE_READ,
-        string $context = null,
+        ?string $context = null,
         bool $wait = false
     ) {
         parent::__construct($streamName, $mode, $context, $wait);
@@ -76,7 +76,7 @@ public function __construct(
      * @throws \Hoa\File\Exception\FileDoesNotExist
      * @throws \Hoa\File\Exception
      */
-    protected function &_open(string $streamName, StreamContext $context = null)
+    protected function &_open(string $streamName, ?StreamContext $context = null)
     {
         static $createModes = [
             parent::MODE_READ,
@@ -190,7 +190,7 @@ public function readFloat(int $length = 1)
      *
      * @return array
      */
-    public function readArray(string $format = null)
+    public function readArray(?string $format = null)
     {
         return $this->scanf($format);
     }
diff --git a/app/vendor/psy/psysh/src/Readline/Hoa/FileLinkReadWrite.php b/app/vendor/psy/psysh/src/Readline/Hoa/FileLinkReadWrite.php
index 0d16585cf..e930d9197 100644
--- a/app/vendor/psy/psysh/src/Readline/Hoa/FileLinkReadWrite.php
+++ b/app/vendor/psy/psysh/src/Readline/Hoa/FileLinkReadWrite.php
@@ -49,7 +49,7 @@ class FileLinkReadWrite extends FileLink implements StreamIn, StreamOut
     public function __construct(
         string $streamName,
         string $mode = parent::MODE_APPEND_READ_WRITE,
-        string $context = null,
+        ?string $context = null,
         bool $wait = false
     ) {
         parent::__construct($streamName, $mode, $context, $wait);
@@ -60,7 +60,7 @@ public function __construct(
     /**
      * Open the stream and return the associated resource.
      */
-    protected function &_open(string $streamName, StreamContext $context = null)
+    protected function &_open(string $streamName, ?StreamContext $context = null)
     {
         static $createModes = [
             parent::MODE_READ_WRITE,
@@ -150,7 +150,7 @@ public function readFloat(int $length = 1)
      * Read an array.
      * Alias of the $this->scanf() method.
      */
-    public function readArray(string $format = null)
+    public function readArray(?string $format = null)
     {
         return $this->scanf($format);
     }
diff --git a/app/vendor/psy/psysh/src/Readline/Hoa/FileRead.php b/app/vendor/psy/psysh/src/Readline/Hoa/FileRead.php
index 9e10fe692..f737ba5d2 100644
--- a/app/vendor/psy/psysh/src/Readline/Hoa/FileRead.php
+++ b/app/vendor/psy/psysh/src/Readline/Hoa/FileRead.php
@@ -49,7 +49,7 @@ class FileRead extends File implements StreamIn
     public function __construct(
         string $streamName,
         string $mode = parent::MODE_READ,
-        string $context = null,
+        ?string $context = null,
         bool $wait = false
     ) {
         parent::__construct($streamName, $mode, $context, $wait);
@@ -60,7 +60,7 @@ public function __construct(
     /**
      * Open the stream and return the associated resource.
      */
-    protected function &_open(string $streamName, StreamContext $context = null)
+    protected function &_open(string $streamName, ?StreamContext $context = null)
     {
         static $createModes = [
             parent::MODE_READ,
@@ -146,7 +146,7 @@ public function readFloat(int $length = 1)
      * Read an array.
      * Alias of the $this->scanf() method.
      */
-    public function readArray(string $format = null)
+    public function readArray(?string $format = null)
     {
         return $this->scanf($format);
     }
diff --git a/app/vendor/psy/psysh/src/Readline/Hoa/FileReadWrite.php b/app/vendor/psy/psysh/src/Readline/Hoa/FileReadWrite.php
index 406b6aa73..d97aa174d 100644
--- a/app/vendor/psy/psysh/src/Readline/Hoa/FileReadWrite.php
+++ b/app/vendor/psy/psysh/src/Readline/Hoa/FileReadWrite.php
@@ -49,7 +49,7 @@ class FileReadWrite extends File implements StreamIn, StreamOut
     public function __construct(
         string $streamName,
         string $mode = parent::MODE_APPEND_READ_WRITE,
-        string $context = null,
+        ?string $context = null,
         bool $wait = false
     ) {
         parent::__construct($streamName, $mode, $context, $wait);
@@ -60,7 +60,7 @@ public function __construct(
     /**
      * Open the stream and return the associated resource.
      */
-    protected function &_open(string $streamName, StreamContext $context = null)
+    protected function &_open(string $streamName, ?StreamContext $context = null)
     {
         static $createModes = [
             parent::MODE_READ_WRITE,
@@ -150,7 +150,7 @@ public function readFloat(int $length = 1)
      * Read an array.
      * Alias of the $this->scanf() method.
      */
-    public function readArray(string $format = null)
+    public function readArray(?string $format = null)
     {
         return $this->scanf($format);
     }
diff --git a/app/vendor/psy/psysh/src/Readline/Hoa/IteratorFileSystem.php b/app/vendor/psy/psysh/src/Readline/Hoa/IteratorFileSystem.php
index f0fc5c575..2ed843154 100644
--- a/app/vendor/psy/psysh/src/Readline/Hoa/IteratorFileSystem.php
+++ b/app/vendor/psy/psysh/src/Readline/Hoa/IteratorFileSystem.php
@@ -53,7 +53,7 @@ class IteratorFileSystem extends \FilesystemIterator
      * Please, see \FileSystemIterator::__construct() method.
      * We add the $splFileInfoClass parameter.
      */
-    public function __construct(string $path, int $flags = null, string $splFileInfoClass = null)
+    public function __construct(string $path, ?int $flags = null, ?string $splFileInfoClass = null)
     {
         $this->_splFileInfoClass = $splFileInfoClass;
 
diff --git a/app/vendor/psy/psysh/src/Readline/Hoa/IteratorRecursiveDirectory.php b/app/vendor/psy/psysh/src/Readline/Hoa/IteratorRecursiveDirectory.php
index ad6951233..80fd02acf 100644
--- a/app/vendor/psy/psysh/src/Readline/Hoa/IteratorRecursiveDirectory.php
+++ b/app/vendor/psy/psysh/src/Readline/Hoa/IteratorRecursiveDirectory.php
@@ -58,7 +58,7 @@ class IteratorRecursiveDirectory extends \RecursiveDirectoryIterator
      * Please, see \RecursiveDirectoryIterator::__construct() method.
      * We add the $splFileInfoClass parameter.
      */
-    public function __construct(string $path, int $flags = null, string $splFileInfoClass = null)
+    public function __construct(string $path, ?int $flags = null, ?string $splFileInfoClass = null)
     {
         if (null === $flags) {
             parent::__construct($path);
diff --git a/app/vendor/psy/psysh/src/Readline/Hoa/IteratorSplFileInfo.php b/app/vendor/psy/psysh/src/Readline/Hoa/IteratorSplFileInfo.php
index 3cf54b845..61fa08068 100644
--- a/app/vendor/psy/psysh/src/Readline/Hoa/IteratorSplFileInfo.php
+++ b/app/vendor/psy/psysh/src/Readline/Hoa/IteratorSplFileInfo.php
@@ -56,7 +56,7 @@ class IteratorSplFileInfo extends \SplFileInfo
     /**
      * Construct.
      */
-    public function __construct(string $filename, string $relativePath = null)
+    public function __construct(string $filename, ?string $relativePath = null)
     {
         parent::__construct($filename);
 
diff --git a/app/vendor/psy/psysh/src/Readline/Hoa/ProtocolNode.php b/app/vendor/psy/psysh/src/Readline/Hoa/ProtocolNode.php
index 78812d7ec..4a82cf497 100644
--- a/app/vendor/psy/psysh/src/Readline/Hoa/ProtocolNode.php
+++ b/app/vendor/psy/psysh/src/Readline/Hoa/ProtocolNode.php
@@ -62,7 +62,7 @@ class ProtocolNode implements \ArrayAccess, \IteratorAggregate
      * overload the `$_name` attribute), we can set the `$_name` attribute
      * dynamically. This is useful to create a node on-the-fly.
      */
-    public function __construct(string $name = null, string $reach = null, array $children = [])
+    public function __construct(?string $name = null, ?string $reach = null, array $children = [])
     {
         if (null !== $name) {
             $this->_name = $name;
@@ -133,7 +133,7 @@ public function offsetUnset($name)
      * Resolve a path, i.e. iterate the nodes tree and reach the queue of
      * the path.
      */
-    protected function _resolve(string $path, &$accumulator, string $id = null)
+    protected function _resolve(string $path, &$accumulator, ?string $id = null)
     {
         if (\substr($path, 0, 6) === 'hoa://') {
             $path = \substr($path, 6);
@@ -246,7 +246,7 @@ protected function _resolveChoice($reach, &$accumulator)
      * Queue of the node.
      * Generic one. Must be overrided in children classes.
      */
-    public function reach(string $queue = null)
+    public function reach(?string $queue = null)
     {
         return empty($queue) ? $this->_reach : $queue;
     }
diff --git a/app/vendor/psy/psysh/src/Readline/Hoa/ProtocolNodeLibrary.php b/app/vendor/psy/psysh/src/Readline/Hoa/ProtocolNodeLibrary.php
index 0719374c0..023f0300c 100644
--- a/app/vendor/psy/psysh/src/Readline/Hoa/ProtocolNodeLibrary.php
+++ b/app/vendor/psy/psysh/src/Readline/Hoa/ProtocolNodeLibrary.php
@@ -44,7 +44,7 @@ class ProtocolNodeLibrary extends ProtocolNode
     /**
      * Queue of the component.
      */
-    public function reach(string $queue = null)
+    public function reach(?string $queue = null)
     {
         $withComposer = \class_exists('Composer\Autoload\ClassLoader', false) ||
             ('cli' === \PHP_SAPI && \file_exists(__DIR__.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'..'.\DIRECTORY_SEPARATOR.'autoload.php'));
diff --git a/app/vendor/psy/psysh/src/Readline/Hoa/Readline.php b/app/vendor/psy/psysh/src/Readline/Hoa/Readline.php
index 0338c9026..614ce52a1 100644
--- a/app/vendor/psy/psysh/src/Readline/Hoa/Readline.php
+++ b/app/vendor/psy/psysh/src/Readline/Hoa/Readline.php
@@ -137,7 +137,7 @@ public function __construct()
     /**
      * Read a line from the input.
      */
-    public function readLine(string $prefix = null)
+    public function readLine(?string $prefix = null)
     {
         $input = Console::getInput();
 
@@ -270,7 +270,7 @@ public function addMapping(string $key, $mapping)
     /**
      * Add an entry in the history.
      */
-    public function addHistory(string $line = null)
+    public function addHistory(?string $line = null)
     {
         if (empty($line)) {
             return;
@@ -294,7 +294,7 @@ public function clearHistory()
     /**
      * Get an entry in the history.
      */
-    public function getHistory(int $i = null)
+    public function getHistory(?int $i = null)
     {
         if (null === $i) {
             $i = $this->_historyCurrent;
diff --git a/app/vendor/psy/psysh/src/Readline/Hoa/Stream.php b/app/vendor/psy/psysh/src/Readline/Hoa/Stream.php
index 62e56ce3f..7a7bd8e43 100644
--- a/app/vendor/psy/psysh/src/Readline/Hoa/Stream.php
+++ b/app/vendor/psy/psysh/src/Readline/Hoa/Stream.php
@@ -110,7 +110,7 @@ abstract class Stream implements IStream, EventListenable
      * If not exists in the register, try to call the
      * `$this->_open()` method. Please, see the `self::_getStream()` method.
      */
-    public function __construct(string $streamName, string $context = null, bool $wait = false)
+    public function __construct(string $streamName, ?string $context = null, bool $wait = false)
     {
         $this->_streamName = $streamName;
         $this->_context = $context;
@@ -150,7 +150,7 @@ public function __construct(string $streamName, string $context = null, bool $wa
     private static function &_getStream(
         string $streamName,
         self $handler,
-        string $context = null
+        ?string $context = null
     ): array {
         $name = \md5($streamName);
 
@@ -195,7 +195,7 @@ private static function &_getStream(
      * Note: This method is protected, but do not forget that it could be
      * overloaded into a public context.
      */
-    abstract protected function &_open(string $streamName, StreamContext $context = null);
+    abstract protected function &_open(string $streamName, ?StreamContext $context = null);
 
     /**
      * Close the current stream.
diff --git a/app/vendor/psy/psysh/src/Readline/Hoa/StreamBufferable.php b/app/vendor/psy/psysh/src/Readline/Hoa/StreamBufferable.php
index e431021a8..6a0c363e1 100644
--- a/app/vendor/psy/psysh/src/Readline/Hoa/StreamBufferable.php
+++ b/app/vendor/psy/psysh/src/Readline/Hoa/StreamBufferable.php
@@ -49,7 +49,7 @@ interface StreamBufferable extends IStream
      * Start a new buffer.
      * The callable acts like a light filter.
      */
-    public function newBuffer($callable = null, int $size = null): int;
+    public function newBuffer($callable = null, ?int $size = null): int;
 
     /**
      * Flush the buffer.
diff --git a/app/vendor/psy/psysh/src/Readline/Hoa/StreamTouchable.php b/app/vendor/psy/psysh/src/Readline/Hoa/StreamTouchable.php
index 08b75255f..f1b50d52b 100644
--- a/app/vendor/psy/psysh/src/Readline/Hoa/StreamTouchable.php
+++ b/app/vendor/psy/psysh/src/Readline/Hoa/StreamTouchable.php
@@ -106,5 +106,5 @@ public function changeOwner($user): bool;
     /**
      * Change the current umask.
      */
-    public static function umask(int $umask = null): int;
+    public static function umask(?int $umask = null): int;
 }
diff --git a/app/vendor/psy/psysh/src/Readline/Libedit.php b/app/vendor/psy/psysh/src/Readline/Libedit.php
index 953ed2afd..3ae8d6e29 100644
--- a/app/vendor/psy/psysh/src/Readline/Libedit.php
+++ b/app/vendor/psy/psysh/src/Readline/Libedit.php
@@ -25,7 +25,7 @@
  */
 class Libedit extends GNUReadline
 {
-    private $hasWarnedOwnership = false;
+    private bool $hasWarnedOwnership = false;
 
     /**
      * Let's emulate GNU Readline by manually reading and parsing the history file!
@@ -48,6 +48,10 @@ public static function supportsBracketedPaste(): bool
      */
     public function listHistory(): array
     {
+        if ($this->historyFile === false) {
+            return [];
+        }
+
         $history = \file_get_contents($this->historyFile);
         if (!$history) {
             return [];
@@ -63,6 +67,7 @@ public function listHistory(): array
 
         // decode the line
         $history = \array_map([$this, 'parseHistoryLine'], $history);
+
         // filter empty lines & comments
         return \array_values(\array_filter($history));
     }
diff --git a/app/vendor/psy/psysh/src/Readline/Readline.php b/app/vendor/psy/psysh/src/Readline/Readline.php
index e9b45b3c7..429b2b1ff 100644
--- a/app/vendor/psy/psysh/src/Readline/Readline.php
+++ b/app/vendor/psy/psysh/src/Readline/Readline.php
@@ -70,7 +70,7 @@ public function readHistory(): bool;
      *
      * @return false|string
      */
-    public function readline(string $prompt = null);
+    public function readline(?string $prompt = null);
 
     /**
      * Redraw readline to redraw the display.
diff --git a/app/vendor/psy/psysh/src/Readline/Transient.php b/app/vendor/psy/psysh/src/Readline/Transient.php
index 43eb28519..e5bb9ba11 100644
--- a/app/vendor/psy/psysh/src/Readline/Transient.php
+++ b/app/vendor/psy/psysh/src/Readline/Transient.php
@@ -18,9 +18,10 @@
  */
 class Transient implements Readline
 {
-    private $history;
-    private $historySize;
-    private $eraseDups;
+    private array $history;
+    private int $historySize;
+    private bool $eraseDups;
+    /** @var resource */
     private $stdin;
 
     /**
@@ -49,7 +50,7 @@ public function __construct($historyFile = null, $historySize = 0, $eraseDups =
         // don't do anything with the history file...
         $this->history = [];
         $this->historySize = $historySize;
-        $this->eraseDups = $eraseDups;
+        $this->eraseDups = $eraseDups ?? false;
     }
 
     /**
@@ -110,7 +111,7 @@ public function readHistory(): bool
      *
      * @return false|string
      */
-    public function readline(string $prompt = null)
+    public function readline(?string $prompt = null)
     {
         echo $prompt;
 
diff --git a/app/vendor/psy/psysh/src/Readline/Userland.php b/app/vendor/psy/psysh/src/Readline/Userland.php
index 62018b770..18d2a2aa4 100644
--- a/app/vendor/psy/psysh/src/Readline/Userland.php
+++ b/app/vendor/psy/psysh/src/Readline/Userland.php
@@ -25,15 +25,11 @@
  */
 class Userland implements Readline
 {
-    /** @var HoaReadline */
-    private $hoaReadline;
-
-    /** @var string|null */
-    private $lastPrompt;
-
-    private $tput;
-    private $input;
-    private $output;
+    private HoaReadline $hoaReadline;
+    private ?string $lastPrompt = null;
+    private HoaConsoleTput $tput;
+    private HoaConsoleInput $input;
+    private HoaConsoleOutput $output;
 
     public static function isSupported(): bool
     {
@@ -138,7 +134,7 @@ public function readHistory(): bool
      *
      * @return string
      */
-    public function readline(string $prompt = null)
+    public function readline(?string $prompt = null)
     {
         $this->lastPrompt = $prompt;
 
diff --git a/app/vendor/psy/psysh/src/Reflection/ReflectionConstant.php b/app/vendor/psy/psysh/src/Reflection/ReflectionConstant.php
index 763011ff7..246aedc28 100644
--- a/app/vendor/psy/psysh/src/Reflection/ReflectionConstant.php
+++ b/app/vendor/psy/psysh/src/Reflection/ReflectionConstant.php
@@ -19,9 +19,10 @@
 class ReflectionConstant implements \Reflector
 {
     public $name;
+    /** @var mixed */
     private $value;
 
-    private static $magicConstants = [
+    private const MAGIC_CONSTANTS = [
         '__LINE__',
         '__FILE__',
         '__DIR__',
@@ -75,7 +76,7 @@ public static function export(string $name, bool $return = false)
 
     public static function isMagicConstant($name)
     {
-        return \in_array($name, self::$magicConstants);
+        return \in_array($name, self::MAGIC_CONSTANTS);
     }
 
     /**
diff --git a/app/vendor/psy/psysh/src/Reflection/ReflectionLanguageConstruct.php b/app/vendor/psy/psysh/src/Reflection/ReflectionLanguageConstruct.php
index 890221469..e7be671b1 100644
--- a/app/vendor/psy/psysh/src/Reflection/ReflectionLanguageConstruct.php
+++ b/app/vendor/psy/psysh/src/Reflection/ReflectionLanguageConstruct.php
@@ -21,7 +21,7 @@ class ReflectionLanguageConstruct extends \ReflectionFunctionAbstract
     /**
      * Language construct parameter definitions.
      */
-    private static $languageConstructs = [
+    private const LANGUAGE_CONSTRUCTS = [
         'isset' => [
             'var' => [],
             '...' => [
@@ -117,7 +117,7 @@ public function returnsReference(): bool
     public function getParameters(): array
     {
         $params = [];
-        foreach (self::$languageConstructs[$this->keyword] as $parameter => $opts) {
+        foreach (self::LANGUAGE_CONSTRUCTS[$this->keyword] as $parameter => $opts) {
             $params[] = new ReflectionLanguageConstructParameter($this->keyword, $parameter, $opts);
         }
 
@@ -154,6 +154,6 @@ public function __toString(): string
      */
     public static function isLanguageConstruct(string $keyword): bool
     {
-        return \array_key_exists($keyword, self::$languageConstructs);
+        return \array_key_exists($keyword, self::LANGUAGE_CONSTRUCTS);
     }
 }
diff --git a/app/vendor/psy/psysh/src/Reflection/ReflectionLanguageConstructParameter.php b/app/vendor/psy/psysh/src/Reflection/ReflectionLanguageConstructParameter.php
index 756dfd8ae..c06530cc2 100644
--- a/app/vendor/psy/psysh/src/Reflection/ReflectionLanguageConstructParameter.php
+++ b/app/vendor/psy/psysh/src/Reflection/ReflectionLanguageConstructParameter.php
@@ -18,10 +18,17 @@
  */
 class ReflectionLanguageConstructParameter extends \ReflectionParameter
 {
+    /** @var string|array|object */
     private $function;
+    /** @var int|string */
     private $parameter;
-    private $opts;
+    private array $opts;
 
+    /**
+     * @param string|array|object $function
+     * @param int|string          $parameter
+     * @param array               $opts
+     */
     public function __construct($function, $parameter, array $opts)
     {
         $this->function = $function;
diff --git a/app/vendor/psy/psysh/src/Reflection/ReflectionNamespace.php b/app/vendor/psy/psysh/src/Reflection/ReflectionNamespace.php
index 3c8b330c0..ba2e6a19b 100644
--- a/app/vendor/psy/psysh/src/Reflection/ReflectionNamespace.php
+++ b/app/vendor/psy/psysh/src/Reflection/ReflectionNamespace.php
@@ -16,7 +16,7 @@
  */
 class ReflectionNamespace implements \Reflector
 {
-    private $name;
+    private string $name;
 
     /**
      * Construct a ReflectionNamespace object.
diff --git a/app/vendor/psy/psysh/src/Shell.php b/app/vendor/psy/psysh/src/Shell.php
index 104699c29..665fa0bb4 100644
--- a/app/vendor/psy/psysh/src/Shell.php
+++ b/app/vendor/psy/psysh/src/Shell.php
@@ -23,7 +23,10 @@
 use Psy\Input\ShellInput;
 use Psy\Input\SilentInput;
 use Psy\Output\ShellOutput;
+use Psy\Readline\Readline;
+use Psy\TabCompletion\AutoCompleter;
 use Psy\TabCompletion\Matcher;
+use Psy\TabCompletion\Matcher\CommandsMatcher;
 use Psy\VarDumper\PresenterAware;
 use Symfony\Component\Console\Application;
 use Symfony\Component\Console\Command\Command as BaseCommand;
@@ -50,36 +53,37 @@
  */
 class Shell extends Application
 {
-    const VERSION = 'v0.12.0';
-
-    private $config;
-    private $cleaner;
-    private $output;
-    private $originalVerbosity;
-    private $readline;
-    private $inputBuffer;
-    private $code;
-    private $codeBuffer;
-    private $codeBufferOpen;
-    private $codeStack;
-    private $stdoutBuffer;
-    private $context;
-    private $includes;
-    private $outputWantsNewline = false;
-    private $loopListeners;
-    private $autoCompleter;
-    private $matchers = [];
-    private $commandsMatcher;
-    private $lastExecSuccess = true;
-    private $nonInteractive = false;
-    private $errorReporting;
+    const VERSION = 'v0.12.9';
+
+    private Configuration $config;
+    private CodeCleaner $cleaner;
+    private OutputInterface $output;
+    private ?int $originalVerbosity = null;
+    private Readline $readline;
+    private array $inputBuffer;
+    /** @var string|false|null */
+    private $code = null;
+    private array $codeBuffer = [];
+    private bool $codeBufferOpen = false;
+    private array $codeStack;
+    private string $stdoutBuffer;
+    private Context $context;
+    private array $includes;
+    private bool $outputWantsNewline = false;
+    private array $loopListeners;
+    private ?AutoCompleter $autoCompleter = null;
+    private array $matchers = [];
+    private ?CommandsMatcher $commandsMatcher = null;
+    private bool $lastExecSuccess = true;
+    private bool $nonInteractive = false;
+    private ?int $errorReporting = null;
 
     /**
      * Create a new Psy Shell.
      *
      * @param Configuration|null $config (default: null)
      */
-    public function __construct(Configuration $config = null)
+    public function __construct(?Configuration $config = null)
     {
         $this->config = $config ?: new Configuration();
         $this->cleaner = $this->config->getCodeCleaner();
@@ -214,7 +218,7 @@ protected function getDefaultCommands(): array
             new Command\TraceCommand(),
             new Command\BufferCommand(),
             new Command\ClearCommand(),
-            new Command\EditCommand($this->config->getRuntimeDir()),
+            new Command\EditCommand($this->config->getRuntimeDir(false)),
             // new Command\PsyVersionCommand(),
             $sudo,
             $hist,
@@ -229,7 +233,7 @@ protected function getDefaultMatchers(): array
     {
         // Store the Commands Matcher for later. If more commands are added,
         // we'll update the Commands Matcher too.
-        $this->commandsMatcher = new Matcher\CommandsMatcher($this->all());
+        $this->commandsMatcher = new CommandsMatcher($this->all());
 
         return [
             $this->commandsMatcher,
@@ -313,7 +317,7 @@ public function setOutput(OutputInterface $output)
      *
      * @return int 0 if everything went fine, or an error code
      */
-    public function run(InputInterface $input = null, OutputInterface $output = null): int
+    public function run(?InputInterface $input = null, ?OutputInterface $output = null): int
     {
         // We'll just ignore the input passed in, and set up our own!
         $input = new ArrayInput([]);
@@ -919,17 +923,58 @@ protected function runCommand(string $input)
 
         $input = new ShellInput(\str_replace('\\', '\\\\', \rtrim($input, " \t\n\r\0\x0B;")));
 
-        if ($input->hasParameterOption(['--help', '-h'])) {
-            $helpCommand = $this->get('help');
-            if (!$helpCommand instanceof Command\HelpCommand) {
-                throw new RuntimeException('Invalid help command instance');
+        if (!$input->hasParameterOption(['--help', '-h'])) {
+            try {
+                return $command->run($input, $this->output);
+            } catch (\Exception $e) {
+                if (!self::needsInputHelp($e)) {
+                    throw $e;
+                }
+
+                $this->writeException($e);
+
+                $this->output->writeln('--');
+                if (!$this->config->theme()->compact()) {
+                    $this->output->writeln('');
+                }
             }
-            $helpCommand->setCommand($command);
+        }
 
-            return $helpCommand->run(new StringInput(''), $this->output);
+        $helpCommand = $this->get('help');
+        if (!$helpCommand instanceof Command\HelpCommand) {
+            throw new RuntimeException('Invalid help command instance');
         }
+        $helpCommand->setCommand($command);
 
-        return $command->run($input, $this->output);
+        return $helpCommand->run(new StringInput(''), $this->output);
+    }
+
+    /**
+     * Check whether a given input error would benefit from --help.
+     *
+     * @return bool
+     */
+    private static function needsInputHelp(\Exception $e): bool
+    {
+        if (!($e instanceof \RuntimeException || $e instanceof SymfonyConsoleException)) {
+            return false;
+        }
+
+        $inputErrors = [
+            'Not enough arguments',
+            'option does not accept a value',
+            'option does not exist',
+            'option requires a value',
+        ];
+
+        $msg = $e->getMessage();
+        foreach ($inputErrors as $errorMsg) {
+            if (\strpos($msg, $errorMsg) !== false) {
+                return true;
+            }
+        }
+
+        return false;
     }
 
     /**
@@ -1261,10 +1306,13 @@ protected function getSeverity(\ErrorException $e): string
                 case \E_USER_NOTICE:
                 case \E_USER_DEPRECATED:
                 case \E_DEPRECATED:
-                case \E_STRICT:
                     return 'warning';
 
                 default:
+                    if ((\PHP_VERSION_ID < 80400) && $severity === \E_STRICT) {
+                        return 'warning';
+                    }
+
                     return 'error';
             }
         } else {
@@ -1509,7 +1557,7 @@ protected function readline(bool $interactive = true)
      */
     protected function getHeader(): string
     {
-        return \sprintf('%s by Justin Hileman', $this->getVersion());
+        return \sprintf('%s by Justin Hileman', self::getVersionHeader($this->config->useUnicode()));
     }
 
     /**
diff --git a/app/vendor/psy/psysh/src/Sudo.php b/app/vendor/psy/psysh/src/Sudo.php
index a84f31da2..54016f933 100644
--- a/app/vendor/psy/psysh/src/Sudo.php
+++ b/app/vendor/psy/psysh/src/Sudo.php
@@ -136,6 +136,11 @@ public static function fetchClassConst($class, string $const)
     {
         $refl = new \ReflectionClass($class);
 
+        // Special case the ::class magic constant, because `getConstant` does the wrong thing here.
+        if ($const === 'class') {
+            return $refl->getName();
+        }
+
         do {
             if ($refl->hasConstant($const)) {
                 return $refl->getConstant($const);
diff --git a/app/vendor/psy/psysh/src/TabCompletion/AutoCompleter.php b/app/vendor/psy/psysh/src/TabCompletion/AutoCompleter.php
index 400b797ab..1be9caa99 100644
--- a/app/vendor/psy/psysh/src/TabCompletion/AutoCompleter.php
+++ b/app/vendor/psy/psysh/src/TabCompletion/AutoCompleter.php
@@ -74,7 +74,7 @@ public function processCallback(string $input, int $index, array $info = []): ar
         $matches = [];
         foreach ($this->matchers as $matcher) {
             if ($matcher->hasMatched($tokens)) {
-                $matches = \array_merge($matcher->getMatches($tokens), $matches);
+                $matches = \array_merge($matcher->getMatches($tokens, $info), $matches);
             }
         }
 
diff --git a/app/vendor/psy/psysh/src/TabCompletion/Matcher/ClassNamesMatcher.php b/app/vendor/psy/psysh/src/TabCompletion/Matcher/ClassNamesMatcher.php
index ca2515d6c..32a34640e 100644
--- a/app/vendor/psy/psysh/src/TabCompletion/Matcher/ClassNamesMatcher.php
+++ b/app/vendor/psy/psysh/src/TabCompletion/Matcher/ClassNamesMatcher.php
@@ -36,6 +36,7 @@ function ($className) use ($class) {
                 // get the number of namespace separators
                 $nsPos = \substr_count($class, '\\');
                 $pieces = \explode('\\', $className);
+
                 // $methods = Mirror::get($class);
                 return \implode('\\', \array_slice($pieces, $nsPos, \count($pieces)));
             },
diff --git a/app/vendor/psy/psysh/src/Util/Mirror.php b/app/vendor/psy/psysh/src/Util/Mirror.php
index 3aa180796..9dd0c1b06 100644
--- a/app/vendor/psy/psysh/src/Util/Mirror.php
+++ b/app/vendor/psy/psysh/src/Util/Mirror.php
@@ -42,7 +42,7 @@ class Mirror
      *
      * @return \Reflector
      */
-    public static function get($value, string $member = null, int $filter = 15): \Reflector
+    public static function get($value, ?string $member = null, int $filter = 15): \Reflector
     {
         if ($member === null && \is_string($value)) {
             if (\function_exists($value)) {
diff --git a/app/vendor/psy/psysh/src/Util/Str.php b/app/vendor/psy/psysh/src/Util/Str.php
index 032520dcf..dd126d1b4 100644
--- a/app/vendor/psy/psysh/src/Util/Str.php
+++ b/app/vendor/psy/psysh/src/Util/Str.php
@@ -60,6 +60,7 @@ class Str
     public static function unvis(string $input): string
     {
         $output = \preg_replace_callback(self::UNVIS_RX, [self::class, 'unvisReplace'], $input);
+
         // other escapes & octal are handled by stripcslashes
         return \stripcslashes($output);
     }
diff --git a/app/vendor/psy/psysh/src/VarDumper/Cloner.php b/app/vendor/psy/psysh/src/VarDumper/Cloner.php
index e0aaab972..a2fc6ad98 100644
--- a/app/vendor/psy/psysh/src/VarDumper/Cloner.php
+++ b/app/vendor/psy/psysh/src/VarDumper/Cloner.php
@@ -21,7 +21,7 @@
  */
 class Cloner extends VarCloner
 {
-    private $filter = 0;
+    private int $filter = 0;
 
     /**
      * {@inheritdoc}
diff --git a/app/vendor/psy/psysh/src/VarDumper/Dumper.php b/app/vendor/psy/psysh/src/VarDumper/Dumper.php
index def61d4a1..54b5ac2d0 100644
--- a/app/vendor/psy/psysh/src/VarDumper/Dumper.php
+++ b/app/vendor/psy/psysh/src/VarDumper/Dumper.php
@@ -20,8 +20,8 @@
  */
 class Dumper extends CliDumper
 {
-    private $formatter;
-    private $forceArrayIndexes;
+    private OutputFormatter $formatter;
+    private bool $forceArrayIndexes;
 
     private const ONLY_CONTROL_CHARS = '/^[\x00-\x1F\x7F]+$/';
     private const CONTROL_CHARS = '/([\x00-\x1F\x7F]+)/';
diff --git a/app/vendor/psy/psysh/src/VarDumper/Presenter.php b/app/vendor/psy/psysh/src/VarDumper/Presenter.php
index 7e54dac05..b76aed335 100644
--- a/app/vendor/psy/psysh/src/VarDumper/Presenter.php
+++ b/app/vendor/psy/psysh/src/VarDumper/Presenter.php
@@ -22,16 +22,18 @@ class Presenter
 {
     const VERBOSE = 1;
 
-    private $cloner;
-    private $dumper;
-    private $exceptionsImportants = [
+    private Cloner $cloner;
+    private Dumper $dumper;
+
+    private const IMPORTANT_EXCEPTIONS = [
         "\0*\0message",
         "\0*\0code",
         "\0*\0file",
         "\0*\0line",
         "\0Exception\0previous",
     ];
-    private $styles = [
+
+    private const STYLES = [
         'num'       => 'number',
         'integer'   => 'integer',
         'float'     => 'float',
@@ -55,7 +57,7 @@ public function __construct(OutputFormatter $formatter, $forceArrayIndexes = fal
         \setlocale(\LC_NUMERIC, 'C');
 
         $this->dumper = new Dumper($formatter, $forceArrayIndexes);
-        $this->dumper->setStyles($this->styles);
+        $this->dumper->setStyles(self::STYLES);
 
         // Now put the locale back
         \setlocale(\LC_NUMERIC, $oldLocale);
@@ -64,7 +66,7 @@ public function __construct(OutputFormatter $formatter, $forceArrayIndexes = fal
         $this->cloner->addCasters(['*' => function ($obj, array $a, Stub $stub, $isNested, $filter = 0) {
             if ($filter || $isNested) {
                 if ($obj instanceof \Throwable) {
-                    $a = Caster::filter($a, Caster::EXCLUDE_NOT_IMPORTANT | Caster::EXCLUDE_EMPTY, $this->exceptionsImportants);
+                    $a = Caster::filter($a, Caster::EXCLUDE_NOT_IMPORTANT | Caster::EXCLUDE_EMPTY, self::IMPORTANT_EXCEPTIONS);
                 } else {
                     $a = Caster::filter($a, Caster::EXCLUDE_PROTECTED | Caster::EXCLUDE_PRIVATE);
                 }
@@ -105,7 +107,7 @@ public function presentRef($value): string
      * @param int   $depth   (default: null)
      * @param int   $options One of Presenter constants
      */
-    public function present($value, int $depth = null, int $options = 0): string
+    public function present($value, ?int $depth = null, int $options = 0): string
     {
         $data = $this->cloner->cloneVar($value, !($options & self::VERBOSE) ? Caster::EXCLUDE_VERBOSE : 0);
 
diff --git a/app/vendor/psy/psysh/src/VersionUpdater/Downloader/CurlDownloader.php b/app/vendor/psy/psysh/src/VersionUpdater/Downloader/CurlDownloader.php
index 14ca1d875..5b40917b2 100644
--- a/app/vendor/psy/psysh/src/VersionUpdater/Downloader/CurlDownloader.php
+++ b/app/vendor/psy/psysh/src/VersionUpdater/Downloader/CurlDownloader.php
@@ -12,13 +12,14 @@
 namespace Psy\VersionUpdater\Downloader;
 
 use Psy\Exception\ErrorException;
+use Psy\Exception\RuntimeException;
 use Psy\Shell;
 use Psy\VersionUpdater\Downloader;
 
 class CurlDownloader implements Downloader
 {
-    private $tempDir = null;
-    private $outputFile = null;
+    private ?string $tempDir = null;
+    private ?string $outputFile = null;
 
     /** {@inheritDoc} */
     public function setTempDir(string $tempDir)
@@ -71,13 +72,17 @@ public function download(string $url): bool
     /** {@inheritDoc} */
     public function getFilename(): string
     {
+        if ($this->outputFile === null) {
+            throw new RuntimeException('Call download() first');
+        }
+
         return $this->outputFile;
     }
 
     /** {@inheritDoc} */
     public function cleanup()
     {
-        if (\file_exists($this->outputFile)) {
+        if ($this->outputFile !== null && \file_exists($this->outputFile)) {
             \unlink($this->outputFile);
         }
     }
diff --git a/app/vendor/psy/psysh/src/VersionUpdater/Downloader/FileDownloader.php b/app/vendor/psy/psysh/src/VersionUpdater/Downloader/FileDownloader.php
index 4bf381167..2af6f6964 100644
--- a/app/vendor/psy/psysh/src/VersionUpdater/Downloader/FileDownloader.php
+++ b/app/vendor/psy/psysh/src/VersionUpdater/Downloader/FileDownloader.php
@@ -11,12 +11,13 @@
 
 namespace Psy\VersionUpdater\Downloader;
 
+use Psy\Exception\RuntimeException;
 use Psy\VersionUpdater\Downloader;
 
 class FileDownloader implements Downloader
 {
-    private $tempDir = null;
-    private $outputFile = null;
+    private ?string $tempDir = null;
+    private ?string $outputFile = null;
 
     /** {@inheritDoc} */
     public function setTempDir(string $tempDir)
@@ -43,13 +44,17 @@ public function download(string $url): bool
     /** {@inheritDoc} */
     public function getFilename(): string
     {
+        if ($this->outputFile === null) {
+            throw new RuntimeException('Call download() first');
+        }
+
         return $this->outputFile;
     }
 
     /** {@inheritDoc} */
     public function cleanup()
     {
-        if (\file_exists($this->outputFile)) {
+        if ($this->outputFile !== null && \file_exists($this->outputFile)) {
             \unlink($this->outputFile);
         }
     }
diff --git a/app/vendor/psy/psysh/src/VersionUpdater/GitHubChecker.php b/app/vendor/psy/psysh/src/VersionUpdater/GitHubChecker.php
index e1fc7cea7..62209d2e7 100644
--- a/app/vendor/psy/psysh/src/VersionUpdater/GitHubChecker.php
+++ b/app/vendor/psy/psysh/src/VersionUpdater/GitHubChecker.php
@@ -17,7 +17,7 @@ class GitHubChecker implements Checker
 {
     const URL = 'https://api.github.com/repos/bobthecow/psysh/releases/latest';
 
-    private $latest;
+    private ?string $latest = null;
 
     public function isLatest(): bool
     {
@@ -37,18 +37,12 @@ public function getLatest(): string
         return $this->latest;
     }
 
-    /**
-     * @param string $version
-     */
     public function setLatest(string $version)
     {
         $this->latest = $version;
     }
 
-    /**
-     * @return string|null
-     */
-    private function getVersionFromTag()
+    private function getVersionFromTag(): ?string
     {
         $contents = $this->fetchLatestRelease();
         if (!$contents || !isset($contents->tag_name)) {
diff --git a/app/vendor/psy/psysh/src/VersionUpdater/Installer.php b/app/vendor/psy/psysh/src/VersionUpdater/Installer.php
index eb20cb865..c346799aa 100644
--- a/app/vendor/psy/psysh/src/VersionUpdater/Installer.php
+++ b/app/vendor/psy/psysh/src/VersionUpdater/Installer.php
@@ -25,7 +25,7 @@ class Installer
      */
     protected $tempDirectory;
 
-    public function __construct(string $tempDirectory = null)
+    public function __construct(?string $tempDirectory = null)
     {
         $this->tempDirectory = $tempDirectory ?: \sys_get_temp_dir();
         $this->installLocation = \Phar::running(false);
@@ -57,8 +57,6 @@ public function isTempDirectoryWritable(): bool
 
     /**
      * Verifies the downloaded archive can be extracted with \PharData.
-     *
-     * @param string $sourceArchive
      */
     public function isValidSource(string $sourceArchive): bool
     {
@@ -72,8 +70,6 @@ public function isValidSource(string $sourceArchive): bool
 
     /**
      * Extract the "psysh" phar from the archive and move it, replacing the currently installed phar.
-     *
-     * @param string $sourceArchive
      */
     public function install(string $sourceArchive): bool
     {
@@ -97,8 +93,6 @@ public function install(string $sourceArchive): bool
 
     /**
      * Create a backup of the currently installed PsySH phar in the temporary directory with a version number postfix.
-     *
-     * @param string $version
      */
     public function createBackup(string $version): bool
     {
@@ -114,8 +108,6 @@ public function createBackup(string $version): bool
     /**
      * Restore the backup file to the original PsySH install location.
      *
-     * @param string $version
-     *
      * @throws ErrorException If the backup file could not be found
      */
     public function restoreFromBackup(string $version): bool
@@ -131,8 +123,6 @@ public function restoreFromBackup(string $version): bool
 
     /**
      * Get the full path for the backup target file location.
-     *
-     * @param string $version
      */
     public function getBackupFilename(string $version): string
     {
diff --git a/app/vendor/psy/psysh/src/VersionUpdater/IntervalChecker.php b/app/vendor/psy/psysh/src/VersionUpdater/IntervalChecker.php
index 06a67775a..4833fbddf 100644
--- a/app/vendor/psy/psysh/src/VersionUpdater/IntervalChecker.php
+++ b/app/vendor/psy/psysh/src/VersionUpdater/IntervalChecker.php
@@ -13,8 +13,8 @@
 
 class IntervalChecker extends GitHubChecker
 {
-    private $cacheFile;
-    private $interval;
+    private string $cacheFile;
+    private string $interval;
 
     public function __construct($cacheFile, $interval)
     {
diff --git a/app/vendor/psy/psysh/src/VersionUpdater/SelfUpdate.php b/app/vendor/psy/psysh/src/VersionUpdater/SelfUpdate.php
index dbda8716c..b970d18ac 100644
--- a/app/vendor/psy/psysh/src/VersionUpdater/SelfUpdate.php
+++ b/app/vendor/psy/psysh/src/VersionUpdater/SelfUpdate.php
@@ -27,14 +27,9 @@ class SelfUpdate
     const SUCCESS = 0;
     const FAILURE = 1;
 
-    /** @var Checker */
-    private $checker;
-
-    /** @var Installer */
-    private $installer;
-
-    /** @var Downloader */
-    private $downloader;
+    private Checker $checker;
+    private Installer $installer;
+    private ?Downloader $downloader = null;
 
     public function __construct(Checker $checker, Installer $installer)
     {
@@ -45,8 +40,6 @@ public function __construct(Checker $checker, Installer $installer)
     /**
      * Allow the downloader to be injected for testing.
      *
-     * @param Downloader $downloader
-     *
      * @return void
      */
     public function setDownloader(Downloader $downloader)
@@ -73,8 +66,6 @@ private function getDownloader(): Downloader
      *
      * The file name used in the URL will include the flavour postfix extracted from the current version
      * if it's present
-     *
-     * @param string $latestVersion
      */
     private function getAssetUrl(string $latestVersion): string
     {
@@ -92,9 +83,6 @@ private function getAssetUrl(string $latestVersion): string
     /**
      * Execute the self-update process.
      *
-     * @param InputInterface  $input
-     * @param OutputInterface $output
-     *
      * @throws ErrorException if the current version is not restored when installation fails
      */
     public function run(InputInterface $input, OutputInterface $output): int
diff --git a/app/vendor/psy/psysh/src/functions.php b/app/vendor/psy/psysh/src/functions.php
index 4b6419a1f..7b58344eb 100644
--- a/app/vendor/psy/psysh/src/functions.php
+++ b/app/vendor/psy/psysh/src/functions.php
@@ -128,7 +128,7 @@ function debug(array $vars = [], $bindTo = null): array
      *
      * @return array|null
      */
-    function info(Configuration $config = null)
+    function info(?Configuration $config = null)
     {
         static $lastConfig;
         if ($config !== null) {
diff --git a/app/vendor/react/promise/CHANGELOG.md b/app/vendor/react/promise/CHANGELOG.md
index ae5bbebe1..c5d730359 100644
--- a/app/vendor/react/promise/CHANGELOG.md
+++ b/app/vendor/react/promise/CHANGELOG.md
@@ -1,5 +1,16 @@
 # Changelog
 
+## 3.2.0 (2024-05-24)
+
+*   Feature: Improve PHP 8.4+ support by avoiding implicitly nullable type declarations.
+    (#260 by @Ayesh)
+
+*   Feature: Include previous exceptions when reporting unhandled promise rejections.
+    (#262 by @clue)
+
+*   Update test suite to improve PHP 8.4+ support.
+    (#261 by @SimonFrings)
+
 ## 3.1.0 (2023-11-16)
 
 *   Feature: Full PHP 8.3 compatibility.
diff --git a/app/vendor/react/promise/README.md b/app/vendor/react/promise/README.md
index 5cb6f7df1..2108d982e 100644
--- a/app/vendor/react/promise/README.md
+++ b/app/vendor/react/promise/README.md
@@ -664,7 +664,7 @@ This project follows [SemVer](https://semver.org/).
 This will install the latest supported version from this branch:
 
 ```bash
-composer require react/promise:^3.1
+composer require react/promise:^3.2
 ```
 
 See also the [CHANGELOG](CHANGELOG.md) for details about version upgrades.
diff --git a/app/vendor/react/promise/src/Deferred.php b/app/vendor/react/promise/src/Deferred.php
index dac6b2b8f..80b8fcfbd 100644
--- a/app/vendor/react/promise/src/Deferred.php
+++ b/app/vendor/react/promise/src/Deferred.php
@@ -21,7 +21,7 @@ final class Deferred
     /**
      * @param (callable(callable(T):void,callable(\Throwable):void):void)|null $canceller
      */
-    public function __construct(callable $canceller = null)
+    public function __construct(?callable $canceller = null)
     {
         $this->promise = new Promise(function ($resolve, $reject): void {
             $this->resolveCallback = $resolve;
diff --git a/app/vendor/react/promise/src/Internal/FulfilledPromise.php b/app/vendor/react/promise/src/Internal/FulfilledPromise.php
index 3c02b4343..8664ffdb6 100644
--- a/app/vendor/react/promise/src/Internal/FulfilledPromise.php
+++ b/app/vendor/react/promise/src/Internal/FulfilledPromise.php
@@ -34,7 +34,7 @@ public function __construct($value = null)
      * @param ?(callable((T is void ? null : T)): (PromiseInterface|TFulfilled)) $onFulfilled
      * @return PromiseInterface<($onFulfilled is null ? T : TFulfilled)>
      */
-    public function then(callable $onFulfilled = null, callable $onRejected = null): PromiseInterface
+    public function then(?callable $onFulfilled = null, ?callable $onRejected = null): PromiseInterface
     {
         if (null === $onFulfilled) {
             return $this;
diff --git a/app/vendor/react/promise/src/Internal/RejectedPromise.php b/app/vendor/react/promise/src/Internal/RejectedPromise.php
index 348ca6d22..aa1dff308 100644
--- a/app/vendor/react/promise/src/Internal/RejectedPromise.php
+++ b/app/vendor/react/promise/src/Internal/RejectedPromise.php
@@ -37,8 +37,7 @@ public function __destruct()
 
         $handler = set_rejection_handler(null);
         if ($handler === null) {
-            $message = 'Unhandled promise rejection with ' . \get_class($this->reason) . ': ' . $this->reason->getMessage() . ' in ' . $this->reason->getFile() . ':' . $this->reason->getLine() . PHP_EOL;
-            $message .= 'Stack trace:' . PHP_EOL . $this->reason->getTraceAsString();
+            $message = 'Unhandled promise rejection with ' . $this->reason;
 
             \error_log($message);
             return;
@@ -47,8 +46,9 @@ public function __destruct()
         try {
             $handler($this->reason);
         } catch (\Throwable $e) {
-            $message = 'Fatal error: Uncaught ' . \get_class($e) . ' from unhandled promise rejection handler: ' . $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine() . PHP_EOL;
-            $message .= 'Stack trace:' . PHP_EOL . $e->getTraceAsString();
+            \preg_match('/^([^:\s]++)(.*+)$/sm', (string) $e, $match);
+            \assert(isset($match[1], $match[2]));
+            $message = 'Fatal error: Uncaught ' . $match[1] . ' from unhandled promise rejection handler' . $match[2];
 
             \error_log($message);
             exit(255);
@@ -61,7 +61,7 @@ public function __destruct()
      * @param ?(callable(\Throwable): (PromiseInterface|TRejected)) $onRejected
      * @return PromiseInterface<($onRejected is null ? never : TRejected)>
      */
-    public function then(callable $onFulfilled = null, callable $onRejected = null): PromiseInterface
+    public function then(?callable $onFulfilled = null, ?callable $onRejected = null): PromiseInterface
     {
         if (null === $onRejected) {
             return $this;
diff --git a/app/vendor/react/promise/src/Promise.php b/app/vendor/react/promise/src/Promise.php
index c46b41f06..4ac27007c 100644
--- a/app/vendor/react/promise/src/Promise.php
+++ b/app/vendor/react/promise/src/Promise.php
@@ -29,7 +29,7 @@ final class Promise implements PromiseInterface
      * @param callable(callable(T):void,callable(\Throwable):void):void $resolver
      * @param (callable(callable(T):void,callable(\Throwable):void):void)|null $canceller
      */
-    public function __construct(callable $resolver, callable $canceller = null)
+    public function __construct(callable $resolver, ?callable $canceller = null)
     {
         $this->canceller = $canceller;
 
@@ -41,7 +41,7 @@ public function __construct(callable $resolver, callable $canceller = null)
         $this->call($cb);
     }
 
-    public function then(callable $onFulfilled = null, callable $onRejected = null): PromiseInterface
+    public function then(?callable $onFulfilled = null, ?callable $onRejected = null): PromiseInterface
     {
         if (null !== $this->result) {
             return $this->result->then($onFulfilled, $onRejected);
@@ -166,7 +166,7 @@ public function always(callable $onFulfilledOrRejected): PromiseInterface
         return $this->finally($onFulfilledOrRejected);
     }
 
-    private function resolver(callable $onFulfilled = null, callable $onRejected = null): callable
+    private function resolver(?callable $onFulfilled = null, ?callable $onRejected = null): callable
     {
         return function (callable $resolve, callable $reject) use ($onFulfilled, $onRejected): void {
             $this->handlers[] = static function (PromiseInterface $promise) use ($onFulfilled, $onRejected, $resolve, $reject): void {
diff --git a/app/vendor/sebastian/resource-operations/.gitattributes b/app/vendor/sebastian/resource-operations/.gitattributes
deleted file mode 100644
index 85e55ebca..000000000
--- a/app/vendor/sebastian/resource-operations/.gitattributes
+++ /dev/null
@@ -1,7 +0,0 @@
-/.github        export-ignore
-/.php_cs.dist   export-ignore
-/build.xml      export-ignore
-/phpunit.xml    export-ignore
-/tests          export-ignore
-
-*.php diff=php
diff --git a/app/vendor/sebastian/resource-operations/.gitignore b/app/vendor/sebastian/resource-operations/.gitignore
deleted file mode 100644
index a086c7819..000000000
--- a/app/vendor/sebastian/resource-operations/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-/.idea
-/.php_cs.cache
-/build/FunctionSignatureMap.php
-/composer.lock
-/vendor
-/.phpunit.result.cache
diff --git a/app/vendor/sebastian/resource-operations/ChangeLog.md b/app/vendor/sebastian/resource-operations/ChangeLog.md
index e6dc73922..eae062908 100644
--- a/app/vendor/sebastian/resource-operations/ChangeLog.md
+++ b/app/vendor/sebastian/resource-operations/ChangeLog.md
@@ -2,6 +2,10 @@
 
 All notable changes are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles.
 
+## [3.0.4] - 2024-03-14
+
+No functional changes.
+
 ## [3.0.3] - 2020-09-28
 
 ### Changed
@@ -46,6 +50,7 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt
 
 * Initial release
 
+[3.0.4]: https://github.com/sebastianbergmann/comparator/resource-operations/3.0.3...3.0.4
 [3.0.3]: https://github.com/sebastianbergmann/comparator/resource-operations/3.0.2...3.0.3
 [3.0.2]: https://github.com/sebastianbergmann/comparator/resource-operations/3.0.1...3.0.2
 [3.0.1]: https://github.com/sebastianbergmann/comparator/resource-operations/3.0.0...3.0.1
diff --git a/app/vendor/sebastian/resource-operations/SECURITY.md b/app/vendor/sebastian/resource-operations/SECURITY.md
new file mode 100644
index 000000000..d88ff0019
--- /dev/null
+++ b/app/vendor/sebastian/resource-operations/SECURITY.md
@@ -0,0 +1,30 @@
+# Security Policy
+
+If you believe you have found a security vulnerability in the library that is developed in this repository, please report it to us through coordinated disclosure.
+
+**Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.**
+
+Instead, please email `sebastian@phpunit.de`.
+
+Please include as much of the information listed below as you can to help us better understand and resolve the issue:
+
+* The type of issue
+* Full paths of source file(s) related to the manifestation of the issue
+* The location of the affected source code (tag/branch/commit or direct URL)
+* Any special configuration required to reproduce the issue
+* Step-by-step instructions to reproduce the issue
+* Proof-of-concept or exploit code (if possible)
+* Impact of the issue, including how an attacker might exploit the issue
+
+This information will help us triage your report more quickly.
+
+## Web Context
+
+The library that is developed in this repository was either extracted from [PHPUnit](https://github.com/sebastianbergmann/phpunit) or developed specifically as a dependency for PHPUnit.
+
+The library is developed with a focus on development environments and the command-line. No specific testing or hardening with regard to using the library in an HTTP or web context or with untrusted input data is performed. The library might also contain functionality that intentionally exposes internal application data for debugging purposes.
+
+If the library is used in a web application, the application developer is responsible for filtering inputs or escaping outputs as necessary and for verifying that the used functionality is safe for use within the intended context.
+
+Vulnerabilities specific to the use outside a development context will be fixed as applicable, provided that the fix does not have an averse effect on the primary use case for development purposes.
+
diff --git a/app/vendor/sebastian/resource-operations/composer.json b/app/vendor/sebastian/resource-operations/composer.json
index 870be3c12..77e4baee9 100644
--- a/app/vendor/sebastian/resource-operations/composer.json
+++ b/app/vendor/sebastian/resource-operations/composer.json
@@ -30,8 +30,9 @@
     },
     "extra": {
         "branch-alias": {
-            "dev-master": "3.0-dev"
+            "dev-main": "3.0-dev"
         }
-    }
+    },
+    "abandoned": false
 }
 
diff --git a/app/vendor/seld/jsonlint/README.md b/app/vendor/seld/jsonlint/README.md
index ab4346dee..e658f7223 100644
--- a/app/vendor/seld/jsonlint/README.md
+++ b/app/vendor/seld/jsonlint/README.md
@@ -35,6 +35,7 @@ You can also pass additional flags to `JsonParser::lint/parse` that tweak the fu
 - `JsonParser::ALLOW_DUPLICATE_KEYS` collects duplicate keys. e.g. if you have two `foo` keys they will end up as `foo` and `foo.2`.
 - `JsonParser::PARSE_TO_ASSOC` parses to associative arrays instead of stdClass objects.
 - `JsonParser::ALLOW_COMMENTS` parses while allowing (and ignoring) inline `//` and multiline `/* */` comments in the JSON document.
+- `JsonParser::ALLOW_DUPLICATE_KEYS_TO_ARRAY` collects duplicate keys. e.g. if you have two `foo` keys the `foo` key will become an object (or array in assoc mode) with all `foo` values accessible as an array in `$result->foo->__duplicates__` (or `$result['foo']['__duplicates__']` in assoc mode).
 
 Example:
 
diff --git a/app/vendor/seld/jsonlint/composer.json b/app/vendor/seld/jsonlint/composer.json
index 3f8afc56f..dbc48e304 100644
--- a/app/vendor/seld/jsonlint/composer.json
+++ b/app/vendor/seld/jsonlint/composer.json
@@ -16,7 +16,7 @@
     },
     "require-dev": {
         "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0 || ^8.5.13",
-        "phpstan/phpstan": "^1.5"
+        "phpstan/phpstan": "^1.11"
     },
     "autoload": {
         "psr-4": { "Seld\\JsonLint\\": "src/Seld/JsonLint/" }
diff --git a/app/vendor/seld/jsonlint/src/Seld/JsonLint/JsonParser.php b/app/vendor/seld/jsonlint/src/Seld/JsonLint/JsonParser.php
index 420c0fda3..cec4a87c2 100644
--- a/app/vendor/seld/jsonlint/src/Seld/JsonLint/JsonParser.php
+++ b/app/vendor/seld/jsonlint/src/Seld/JsonLint/JsonParser.php
@@ -31,6 +31,7 @@ class JsonParser
     const ALLOW_DUPLICATE_KEYS = 2;
     const PARSE_TO_ASSOC = 4;
     const ALLOW_COMMENTS = 8;
+    const ALLOW_DUPLICATE_KEYS_TO_ARRAY = 16;
 
     /** @var Lexer */
     private $lexer;
@@ -201,6 +202,10 @@ public function lint($input, $flags = 0)
      */
     public function parse($input, $flags = 0)
     {
+        if (($flags & self::ALLOW_DUPLICATE_KEYS_TO_ARRAY) && ($flags & self::ALLOW_DUPLICATE_KEYS)) {
+            throw new \InvalidArgumentException('Only one of ALLOW_DUPLICATE_KEYS and ALLOW_DUPLICATE_KEYS_TO_ARRAY can be used, you passed in both.');
+        }
+
         $this->failOnBOM($input);
 
         $this->flags = $flags;
@@ -334,7 +339,7 @@ public function parse($input, $flags = 0)
             }
 
             // this shouldn't happen, unless resolve defaults are off
-            if (\is_array($action[0]) && \count($action) > 1) { // @phpstan-ignore-line
+            if (\is_array($action[0]) && \count($action) > 1) {
                 throw new ParsingException('Parse Error: multiple actions possible at state: ' . $state . ', token: ' . $symbol);
             }
 
@@ -484,14 +489,21 @@ private function performAction($currentToken, $yytext, $yyleng, $yylineno, $yyst
                     $errStr .= $this->lexer->showPosition() . "\n";
                     $errStr .= "Duplicate key: ".$this->vstack[$len][0];
                     throw new DuplicateKeyException($errStr, $this->vstack[$len][0], array('line' => $yylineno+1));
-                } elseif (($this->flags & self::ALLOW_DUPLICATE_KEYS) && isset($this->vstack[$len-2][$key])) {
+                }
+                if (($this->flags & self::ALLOW_DUPLICATE_KEYS) && isset($this->vstack[$len-2][$key])) {
                     $duplicateCount = 1;
                     do {
                         $duplicateKey = $key . '.' . $duplicateCount++;
                     } while (isset($this->vstack[$len-2][$duplicateKey]));
-                    $key = $duplicateKey;
+                    $this->vstack[$len-2][$duplicateKey] = $this->vstack[$len][1];
+                } elseif (($this->flags & self::ALLOW_DUPLICATE_KEYS_TO_ARRAY) && isset($this->vstack[$len-2][$key])) {
+                    if (!isset($this->vstack[$len-2][$key]['__duplicates__']) || !is_array($this->vstack[$len-2][$key]['__duplicates__'])) {
+                        $this->vstack[$len-2][$key] = array('__duplicates__' => array($this->vstack[$len-2][$key]));
+                    }
+                    $this->vstack[$len-2][$key]['__duplicates__'][] = $this->vstack[$len][1];
+                } else {
+                    $this->vstack[$len-2][$key] = $this->vstack[$len][1];
                 }
-                $this->vstack[$len-2][$key] = $this->vstack[$len][1];
             } else {
                 assert($this->vstack[$len-2] instanceof stdClass);
                 $token = $this->vstack[$len-2];
@@ -500,19 +512,26 @@ private function performAction($currentToken, $yytext, $yyleng, $yylineno, $yyst
                 } else {
                     $key = $this->vstack[$len][0];
                 }
-                if (($this->flags & self::DETECT_KEY_CONFLICTS) && isset($this->vstack[$len-2]->{$key})) {
+                if (($this->flags & self::DETECT_KEY_CONFLICTS) && isset($this->vstack[$len-2]->$key)) {
                     $errStr = 'Parse error on line ' . ($yylineno+1) . ":\n";
                     $errStr .= $this->lexer->showPosition() . "\n";
                     $errStr .= "Duplicate key: ".$this->vstack[$len][0];
                     throw new DuplicateKeyException($errStr, $this->vstack[$len][0], array('line' => $yylineno+1));
-                } elseif (($this->flags & self::ALLOW_DUPLICATE_KEYS) && isset($this->vstack[$len-2]->{$key})) {
+                }
+                if (($this->flags & self::ALLOW_DUPLICATE_KEYS) && isset($this->vstack[$len-2]->$key)) {
                     $duplicateCount = 1;
                     do {
                         $duplicateKey = $key . '.' . $duplicateCount++;
                     } while (isset($this->vstack[$len-2]->$duplicateKey));
-                    $key = $duplicateKey;
+                    $this->vstack[$len-2]->$duplicateKey = $this->vstack[$len][1];
+                } elseif (($this->flags & self::ALLOW_DUPLICATE_KEYS_TO_ARRAY) && isset($this->vstack[$len-2]->$key)) {
+                    if (!isset($this->vstack[$len-2]->$key->__duplicates__)) {
+                        $this->vstack[$len-2]->$key = (object) array('__duplicates__' => array($this->vstack[$len-2]->$key));
+                    }
+                    $this->vstack[$len-2]->$key->__duplicates__[] = $this->vstack[$len][1];
+                } else {
+                    $this->vstack[$len-2]->$key = $this->vstack[$len][1];
                 }
-                $this->vstack[$len-2]->$key = $this->vstack[$len][1];
             }
             break;
         case 18:
diff --git a/app/vendor/slevomat/coding-standard/.typos.toml b/app/vendor/slevomat/coding-standard/.typos.toml
new file mode 100644
index 000000000..5f43f72e5
--- /dev/null
+++ b/app/vendor/slevomat/coding-standard/.typos.toml
@@ -0,0 +1,10 @@
+[files]
+extend-exclude = [
+    ".git/",
+]
+ignore-hidden = false
+
+[default]
+extend-ignore-re = [
+    "const BA =",
+]
diff --git a/app/vendor/slevomat/coding-standard/README.md b/app/vendor/slevomat/coding-standard/README.md
index 46fadddc8..38369031d 100644
--- a/app/vendor/slevomat/coding-standard/README.md
+++ b/app/vendor/slevomat/coding-standard/README.md
@@ -2,11 +2,11 @@
 
 [![Latest version](https://img.shields.io/packagist/v/slevomat/coding-standard.svg?colorB=007EC6)](https://packagist.org/packages/slevomat/coding-standard)
 [![Downloads](https://img.shields.io/packagist/dt/slevomat/coding-standard.svg?colorB=007EC6)](https://packagist.org/packages/slevomat/coding-standard)
-[![Build status](https://github.com/slevomat/coding-standard/workflows/Build/badge.svg?branch=master)](https://github.com/slevomat/coding-standard/actions?query=workflow%3ABuild+branch%3Amaster)
+[![Build status](https://github.com/slevomat/coding-standard/actions/workflows/build.yml/badge.svg?branch=master)](https://github.com/slevomat/coding-standard/actions?query=workflow%3ABuild+branch%3Amaster)
 [![Code coverage](https://codecov.io/gh/slevomat/coding-standard/branch/master/graph/badge.svg)](https://codecov.io/gh/slevomat/coding-standard)
 ![PHPStan](https://img.shields.io/badge/style-level%207-brightgreen.svg?&label=phpstan)
 
-Slevomat Coding Standard for [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) provides sniffs that fall into three categories:
+Slevomat Coding Standard for [PHP_CodeSniffer](https://github.com/PHPCSStandards/PHP_CodeSniffer) provides sniffs that fall into three categories:
 
 * Functional - improving the safety and behaviour of code
 * Cleaning - detecting dead code
@@ -30,10 +30,10 @@ Slevomat Coding Standard for [PHP_CodeSniffer](https://github.com/squizlabs/PHP_
 🚧 = [Sniff check can be suppressed locally](#suppressing-sniffs-locally)
 
  - [SlevomatCodingStandard.Arrays.AlphabeticallySortedByKeys](doc/arrays.md#slevomatcodingstandardarrayalphabeticallysortedbykeys) 🔧
+ - [SlevomatCodingStandard.Arrays.ArrayAccess](doc/arrays.md#slevomatcodingstandardarraysarrayaccess-) 🔧
  - [SlevomatCodingStandard.Arrays.DisallowImplicitArrayCreation](doc/arrays.md#slevomatcodingstandardarraysdisallowimplicitarraycreation)
  - [SlevomatCodingStandard.Arrays.DisallowPartiallyKeyed](doc/arrays.md#slevomatcodingstandardarraysdisallowpartiallykeyed) 🚧
  - [SlevomatCodingStandard.Arrays.MultiLineArrayEndBracketPlacement](doc/arrays.md#slevomatcodingstandardarraysmultilinearrayendbracketplacement-) 🔧
- - [SlevomatCodingStandard.Arrays.ArrayAccessSniff.php](doc/arrays.md#slevomatcodingstandardarraysarrayaccess-) 🔧
  - [SlevomatCodingStandard.Arrays.SingleLineArrayWhitespace](doc/arrays.md#slevomatcodingstandardarrayssinglelinearraywhitespace-) 🔧
  - [SlevomatCodingStandard.Arrays.TrailingArrayComma](doc/arrays.md#slevomatcodingstandardarraystrailingarraycomma-) 🔧
  - [SlevomatCodingStandard.Attributes.AttributeAndTargetSpacing](doc/attributes.md#slevomatcodingstandardattributesattributeandtargetspacing-) 🔧
@@ -175,9 +175,11 @@ Slevomat Coding Standard for [PHP_CodeSniffer](https://github.com/squizlabs/PHP_
  - [SlevomatCodingStandard.PHP.UselessParentheses](doc/php.md#slevomatcodingstandardphpuselessparentheses-) 🔧
  - [SlevomatCodingStandard.PHP.UselessSemicolon](doc/php.md#slevomatcodingstandardphpuselesssemicolon-) 🔧
  - [SlevomatCodingStandard.Strings.DisallowVariableParsing](doc/strings.md#slevomatcodingstandardstringsdisallowvariableparsing)
+ - [SlevomatCodingStandard.TypeHints.ClassConstantTypeHint](doc/type-hints.md#slevomatcodingstandardtypehintsclassconstanttypehint-) 🔧
  - [SlevomatCodingStandard.TypeHints.DeclareStrictTypes](doc/type-hints.md#slevomatcodingstandardtypehintsdeclarestricttypes-) 🔧
  - [SlevomatCodingStandard.TypeHints.DisallowArrayTypeHintSyntax](doc/type-hints.md#slevomatcodingstandardtypehintsdisallowarraytypehintsyntax-) 🔧
  - [SlevomatCodingStandard.TypeHints.DisallowMixedTypeHint](doc/type-hints.md#slevomatcodingstandardtypehintsdisallowmixedtypehint)
+ - [SlevomatCodingStandard.TypeHints.DNFTypeHintFormat](doc/type-hints.md#slevomatcodingstandardtypehintsdnftypehintformat-) 🔧
  - [SlevomatCodingStandard.TypeHints.LongTypeHints](doc/type-hints.md#slevomatcodingstandardtypehintslongtypehints-) 🔧
  - [SlevomatCodingStandard.TypeHints.NullTypeHintOnLastPosition](doc/type-hints.md#slevomatcodingstandardtypehintsnulltypehintonlastposition-) 🔧
  - [SlevomatCodingStandard.TypeHints.NullableTypeForNullDefaultValue](doc/type-hints.md#slevomatcodingstandardtypehintsnullabletypefornulldefaultvalue-) 🔧🚧
@@ -249,7 +251,7 @@ However it is not a recommended way to use Slevomat Coding Standard, because you
 
 ## Fixing errors automatically
 
-Sniffs in this standard marked by the 🔧 symbol support [automatic fixing of coding standard violations](https://github.com/squizlabs/PHP_CodeSniffer/wiki/Fixing-Errors-Automatically). To fix your code automatically, run phpcbf instead of phpcs:
+Sniffs in this standard marked by the 🔧 symbol support [automatic fixing of coding standard violations](https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki/Fixing-Errors-Automatically). To fix your code automatically, run phpcbf instead of phpcs:
 
 ```
 vendor/bin/phpcbf --standard=ruleset.xml --extensions=php --tab-width=4 -sp src tests
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/Annotation.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/Annotation.php
index d5b6343c0..99a91837a 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/Annotation.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/Annotation.php
@@ -13,14 +13,11 @@
 class Annotation
 {
 
-	/** @var PhpDocTagNode */
-	private $node;
+	private PhpDocTagNode $node;
 
-	/** @var int */
-	private $startPointer;
+	private int $startPointer;
 
-	/** @var int */
-	private $endPointer;
+	private int $endPointer;
 
 	public function __construct(PhpDocTagNode $node, int $startPointer, int $endPointer)
 	{
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/AnnotationHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/AnnotationHelper.php
index f6081af13..78973122e 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/AnnotationHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/AnnotationHelper.php
@@ -9,7 +9,6 @@
 use PHPStan\PhpDocParser\Ast\NodeTraverser;
 use PHPStan\PhpDocParser\Ast\PhpDoc\Doctrine\DoctrineArgument;
 use PHPStan\PhpDocParser\Ast\PhpDoc\ParamTagValueNode;
-use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
 use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTagNode;
 use PHPStan\PhpDocParser\Ast\PhpDoc\ReturnTagValueNode;
 use PHPStan\PhpDocParser\Ast\PhpDoc\TypelessParamTagValueNode;
@@ -68,20 +67,21 @@ static function () use ($phpcsFile, $docCommentOpenPointer, $name): array {
 							$annotations[] = new Annotation(
 								$node,
 								$annotationStartPointer,
-								$parsedDocComment->getNodeEndPointer($phpcsFile, $node, $annotationStartPointer)
+								$parsedDocComment->getNodeEndPointer($phpcsFile, $node, $annotationStartPointer),
 							);
 						}
 					}
 				}
 
 				return $annotations;
-			}
+			},
 		);
 	}
 
 	/**
-	 * @param class-string $type
-	 * @return list
+	 * @template T
+	 * @param class-string $type
+	 * @return list
 	 */
 	public static function getAnnotationNodesByType(Node $node, string $type): array
 	{
@@ -92,13 +92,13 @@ public static function getAnnotationNodesByType(Node $node, string $type): array
 			$visitor = new class extends AbstractNodeVisitor {
 
 				/** @var class-string */
-				private $type;
+				private string $type;
 
 				/** @var list */
-				private $nodes = [];
+				private array $nodes = [];
 
 				/** @var list */
-				private $nodesToIgnore = [];
+				private array $nodesToIgnore = [];
 
 				/**
 				 * @return Node|list|NodeTraverser::*|null
@@ -166,7 +166,6 @@ public static function fixAnnotation(
 	{
 		$originalNode = $annotation->getNode();
 
-		/** @var PhpDocNode $newPhpDocNode */
 		$newPhpDocNode = PhpDocParserHelper::cloneNode($parsedDocComment->getNode());
 
 		foreach ($newPhpDocNode->getTags() as $node) {
@@ -179,12 +178,12 @@ public static function fixAnnotation(
 		return PhpDocParserHelper::getPrinter()->printFormatPreserving(
 			$newPhpDocNode,
 			$parsedDocComment->getNode(),
-			$parsedDocComment->getTokens()
+			$parsedDocComment->getTokens(),
 		);
 	}
 
 	/**
-	 * @param array $traversableTypeHints
+	 * @param list $traversableTypeHints
 	 */
 	public static function isAnnotationUseless(
 		File $phpcsFile,
@@ -216,15 +215,21 @@ public static function isAnnotationUseless(
 			return true;
 		}
 
-		if (TypeHintHelper::isTraversableType(
-			TypeHintHelper::getFullyQualifiedTypeHint($phpcsFile, $functionPointer, $typeHint->getTypeHintWithoutNullabilitySymbol()),
-			$traversableTypeHints
-		)) {
+		$annotationType = $annotationValue->type;
+
+		if (
+			TypeHintHelper::isTraversableType(
+				TypeHintHelper::getFullyQualifiedTypeHint($phpcsFile, $functionPointer, $typeHint->getTypeHintWithoutNullabilitySymbol()),
+				$traversableTypeHints,
+			)
+			&& !(
+				$annotationType instanceof IdentifierTypeNode
+				&& TypeHintHelper::isSimpleIterableTypeHint(strtolower($annotationType->name))
+			)
+		) {
 			return false;
 		}
 
-		$annotationType = $annotationValue->type;
-
 		if (AnnotationTypeHelper::containsStaticOrThisType($annotationType)) {
 			return false;
 		}
@@ -251,7 +256,7 @@ public static function isAnnotationUseless(
 				$phpcsFile,
 				$functionPointer,
 				$typeHint->getTypeHint(),
-				$annotationTypeHint
+				$annotationTypeHint,
 			);
 		}
 
@@ -283,7 +288,7 @@ public static function isAnnotationUseless(
 			if (in_array(
 				strtolower($annotationType->name),
 				['true', 'false', 'null'],
-				true
+				true,
 			)) {
 				return $enableStandaloneNullTrueFalseTypeHints;
 			}
@@ -291,7 +296,7 @@ public static function isAnnotationUseless(
 			if (in_array(
 				strtolower($annotationType->name),
 				['class-string', 'trait-string', 'callable-string', 'numeric-string', 'non-empty-string', 'non-falsy-string', 'literal-string', 'positive-int', 'negative-int'],
-				true
+				true,
 			)) {
 				return false;
 			}
@@ -302,7 +307,7 @@ public static function isAnnotationUseless(
 			$phpcsFile,
 			$functionPointer,
 			$typeHint->getTypeHintWithoutNullabilitySymbol(),
-			$annotationTypeHint
+			$annotationTypeHint,
 		);
 	}
 
@@ -314,16 +319,11 @@ private static function changeAnnotationNode(PhpDocTagNode $tagNode, Node $nodeT
 		if ($visitor === null) {
 			$visitor = new class extends AbstractNodeVisitor {
 
-				/** @var Node */
-				private $nodeToChange;
+				private Node $nodeToChange;
 
-				/** @var Node */
-				private $changedNode;
+				private Node $changedNode;
 
-				/**
-				 * @return Node|list|NodeTraverser::*|null
-				 */
-				public function enterNode(Node $node)
+				public function enterNode(Node $node): ?Node
 				{
 					if ($node->getAttribute(Attribute::ORIGINAL_NODE) === $this->nodeToChange) {
 						return $this->changedNode;
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/AnnotationTypeHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/AnnotationTypeHelper.php
index 058c5b33e..43cf1e216 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/AnnotationTypeHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/AnnotationTypeHelper.php
@@ -123,7 +123,7 @@ public static function containsJustTwoTypes(TypeNode $typeNode): bool
 	}
 
 	/**
-	 * @param array $traversableTypeHints
+	 * @param list $traversableTypeHints
 	 */
 	public static function containsTraversableType(TypeNode $typeNode, File $phpcsFile, int $pointer, array $traversableTypeHints): bool
 	{
@@ -170,7 +170,7 @@ public static function containsTraversableType(TypeNode $typeNode, File $phpcsFi
 	}
 
 	/**
-	 * @param array $traversableTypeHints
+	 * @param list $traversableTypeHints
 	 */
 	public static function containsItemsSpecificationForTraversable(
 		TypeNode $typeNode,
@@ -190,14 +190,14 @@ public static function containsItemsSpecificationForTraversable(
 			return true;
 		}
 
-		if ($typeNode instanceof ArrayShapeNode) {
-			foreach ($typeNode->items as $arrayShapeItemNode) {
+		if ($typeNode instanceof ArrayShapeNode || $typeNode instanceof ObjectShapeNode) {
+			foreach ($typeNode->items as $innerItemNode) {
 				if (!self::containsItemsSpecificationForTraversable(
-					$arrayShapeItemNode->valueType,
+					$innerItemNode->valueType,
 					$phpcsFile,
 					$pointer,
 					$traversableTypeHints,
-					true
+					true,
 				)) {
 					return false;
 				}
@@ -222,7 +222,7 @@ public static function containsItemsSpecificationForTraversable(
 
 			return !TypeHintHelper::isTraversableType(
 				TypeHintHelper::getFullyQualifiedTypeHint($phpcsFile, $pointer, $typeNode->name),
-				$traversableTypeHints
+				$traversableTypeHints,
 			);
 		}
 
@@ -256,7 +256,7 @@ public static function containsItemsSpecificationForTraversable(
 					$phpcsFile,
 					$pointer,
 					$traversableTypeHints,
-					$inTraversable
+					$inTraversable,
 				)) {
 					return true;
 				}
@@ -271,7 +271,7 @@ public static function containsItemsSpecificationForTraversable(
 					$phpcsFile,
 					$pointer,
 					$traversableTypeHints,
-					$inTraversable
+					$inTraversable,
 				);
 		}
 
@@ -310,7 +310,7 @@ public static function getTypeHintFromOneType(
 			if (in_array(
 				strtolower($typeNode->name),
 				['class-string', 'trait-string', 'callable-string', 'numeric-string', 'non-empty-string', 'non-falsy-string', 'literal-string'],
-				true
+				true,
 			)) {
 				return 'string';
 			}
@@ -353,7 +353,7 @@ public static function getTypeHintFromOneType(
 
 	/**
 	 * @param UnionTypeNode|IntersectionTypeNode $typeNode
-	 * @param array $traversableTypeHints
+	 * @param list $traversableTypeHints
 	 * @return list
 	 */
 	public static function getTraversableTypeHintsFromType(
@@ -383,7 +383,7 @@ public static function getTraversableTypeHintsFromType(
 		foreach ($typeHints as $typeHint) {
 			if (!TypeHintHelper::isTraversableType(
 				TypeHintHelper::getFullyQualifiedTypeHint($phpcsFile, $pointer, $typeHint),
-				$traversableTypeHints
+				$traversableTypeHints,
 			)) {
 				return [];
 			}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ArrayHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ArrayHelper.php
index 8bf354b48..e0e21bf52 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ArrayHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ArrayHelper.php
@@ -44,7 +44,7 @@ public static function parse(File $phpcsFile, int $arrayPointer): array
 		for ($i = $arrayKeyValueStartPointer; $i < $arrayCloserPointer; $i++) {
 			$token = $tokens[$i];
 
-			if (in_array($token['code'], TokenHelper::$arrayTokenCodes, true)) {
+			if (in_array($token['code'], TokenHelper::ARRAY_TOKEN_CODES, true)) {
 				$i = self::openClosePointers($token)[1];
 				continue;
 			}
@@ -213,7 +213,7 @@ private static function getValueEndPointer(File $phpcsFile, int $endPointer, int
 
 			$nextNonWhitespacePointer = TokenHelper::findNextNonWhitespace($phpcsFile, $i);
 
-			if (!in_array($tokens[$nextNonWhitespacePointer]['code'], TokenHelper::$inlineCommentTokenCodes, true)) {
+			if (!in_array($tokens[$nextNonWhitespacePointer]['code'], TokenHelper::INLINE_COMMENT_TOKEN_CODES, true)) {
 				break;
 			}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ArrayKeyValue.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ArrayKeyValue.php
index 3588426df..98806d801 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ArrayKeyValue.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ArrayKeyValue.php
@@ -3,11 +3,14 @@
 namespace SlevomatCodingStandard\Helpers;
 
 use PHP_CodeSniffer\Files\File;
+use function array_reverse;
+use function current;
 use function in_array;
 use function ltrim;
 use function rtrim;
 use function strpos;
 use function trim;
+use const T_CLOSURE;
 use const T_COMMA;
 use const T_DOUBLE_ARROW;
 use const T_ELLIPSIS;
@@ -19,26 +22,19 @@
 class ArrayKeyValue
 {
 
-	/** @var int */
-	private $pointerStart;
+	private int $pointerStart;
 
-	/** @var int */
-	private $pointerEnd;
+	private int $pointerEnd;
 
-	/** @var ?string */
-	private $indent = null;
+	private ?string $indent = null;
 
-	/** @var ?string */
-	private $key = null;
+	private ?string $key = null;
 
-	/** @var ?int */
-	private $pointerArrow = null;
+	private ?int $pointerArrow = null;
 
-	/** @var ?int */
-	private $pointerComma = null;
+	private ?int $pointerComma = null;
 
-	/** @var bool */
-	private $unpacking = false;
+	private bool $unpacking = false;
 
 	public function __construct(File $phpcsFile, int $pointerStart, int $pointerEnd)
 	{
@@ -120,12 +116,16 @@ private function addValues(File $phpcsFile): void
 		for ($i = $this->pointerStart; $i <= $this->pointerEnd; $i++) {
 			$token = $tokens[$i];
 
-			if (in_array($token['code'], TokenHelper::$arrayTokenCodes, true)) {
+			if (in_array($token['code'], TokenHelper::ARRAY_TOKEN_CODES, true)) {
 				$i = ArrayHelper::openClosePointers($token)[1];
 				continue;
 			}
 
 			if ($token['code'] === T_DOUBLE_ARROW) {
+				if (current(array_reverse($token['conditions'])) === T_CLOSURE) {
+					continue;
+				}
+
 				$this->pointerArrow = $i;
 				continue;
 			}
@@ -149,19 +149,19 @@ private function addValues(File $phpcsFile): void
 				$firstNonWhitespace = $i;
 			}
 
-			if (in_array($token['code'], TokenHelper::$inlineCommentTokenCodes, true) === false) {
+			if (in_array($token['code'], TokenHelper::INLINE_COMMENT_TOKEN_CODES, true) === false) {
 				$key .= $token['content'];
 			}
 		}
 		$haveIndent = $firstNonWhitespace !== null && TokenHelper::findFirstNonWhitespaceOnLine(
 			$phpcsFile,
-			$firstNonWhitespace
+			$firstNonWhitespace,
 		) === $firstNonWhitespace;
 		$this->indent = $haveIndent
 			? TokenHelper::getContent(
 				$phpcsFile,
 				TokenHelper::findFirstTokenOnLine($phpcsFile, $firstNonWhitespace),
-				$firstNonWhitespace - 1
+				$firstNonWhitespace - 1,
 			)
 			: null;
 		$this->key = $this->pointerArrow !== null
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/Attribute.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/Attribute.php
index bc6cb89b1..0bc1886a5 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/Attribute.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/Attribute.php
@@ -8,25 +8,30 @@
 class Attribute
 {
 
-	/** @var int */
-	private $attributePointer;
+	private int $attributePointer;
 
-	/** @var string */
-	private $name;
+	private string $name;
 
-	/** @var int */
-	private $startPointer;
+	private string $fullyQualifiedName;
 
-	/** @var int */
-	private $endPointer;
+	private int $startPointer;
 
-	/** @var string|null */
-	private $content;
+	private int $endPointer;
 
-	public function __construct(int $attributePointer, string $name, int $startPointer, int $endPointer, ?string $content = null)
+	private ?string $content = null;
+
+	public function __construct(
+		int $attributePointer,
+		string $name,
+		string $fullyQualifiedName,
+		int $startPointer,
+		int $endPointer,
+		?string $content = null
+	)
 	{
 		$this->attributePointer = $attributePointer;
 		$this->name = $name;
+		$this->fullyQualifiedName = $fullyQualifiedName;
 		$this->startPointer = $startPointer;
 		$this->endPointer = $endPointer;
 		$this->content = $content;
@@ -42,6 +47,11 @@ public function getName(): string
 		return $this->name;
 	}
 
+	public function getFullyQualifiedName(): string
+	{
+		return $this->fullyQualifiedName;
+	}
+
 	public function getStartPointer(): int
 	{
 		return $this->startPointer;
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/AttributeHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/AttributeHelper.php
index c5ce72ee4..e64dbbdb1 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/AttributeHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/AttributeHelper.php
@@ -4,6 +4,8 @@
 
 use InvalidArgumentException;
 use PHP_CodeSniffer\Files\File;
+use function array_map;
+use function in_array;
 use function sprintf;
 use const T_ANON_CLASS;
 use const T_ATTRIBUTE;
@@ -40,6 +42,28 @@ class AttributeHelper
 		T_VARIABLE,
 	];
 
+	public static function hasAttribute(File $phpcsFile, int $pointer, string $attributeName): bool
+	{
+		$docCommentOpenPointer = DocCommentHelper::findDocCommentOpenPointer($phpcsFile, $pointer);
+		if ($docCommentOpenPointer === null) {
+			return false;
+		}
+
+		$tokens = $phpcsFile->getTokens();
+		$nextPointer = TokenHelper::findNextEffective($phpcsFile, $docCommentOpenPointer + 1);
+
+		if ($nextPointer === null || $tokens[$nextPointer]['code'] !== T_ATTRIBUTE) {
+			return false;
+		}
+
+		$attributeNames = array_map(
+			static fn (Attribute $name): string => $name->getFullyQualifiedName(),
+			self::getAttributes($phpcsFile, $nextPointer),
+		);
+
+		return in_array($attributeName, $attributeNames, true);
+	}
+
 	/**
 	 * @return list
 	 */
@@ -49,7 +73,7 @@ public static function getAttributes(File $phpcsFile, int $attributeOpenerPointe
 
 		if ($tokens[$attributeOpenerPointer]['code'] !== T_ATTRIBUTE) {
 			throw new InvalidArgumentException(
-				sprintf('Token %d must be attribute, %s given.', $attributeOpenerPointer, $tokens[$attributeOpenerPointer]['type'])
+				sprintf('Token %d must be attribute, %s given.', $attributeOpenerPointer, $tokens[$attributeOpenerPointer]['type']),
 			);
 		}
 
@@ -67,8 +91,8 @@ public static function getAttributes(File $phpcsFile, int $attributeOpenerPointe
 
 			$attributeNameEndPointer = TokenHelper::findNextExcluding(
 				$phpcsFile,
-				TokenHelper::getNameTokenCodes(),
-				$attributeNameStartPointer + 1
+				TokenHelper::NAME_TOKEN_CODES,
+				$attributeNameStartPointer + 1,
 			) - 1;
 			$attributeName = TokenHelper::getContent($phpcsFile, $attributeNameStartPointer, $attributeNameEndPointer);
 
@@ -78,8 +102,9 @@ public static function getAttributes(File $phpcsFile, int $attributeOpenerPointe
 				$attributes[] = new Attribute(
 					$attributeOpenerPointer,
 					$attributeName,
+					NamespaceHelper::resolveClassName($phpcsFile, $attributeName, $attributeOpenerPointer),
 					$attributeNameStartPointer,
-					$attributeNameEndPointer
+					$attributeNameEndPointer,
 				);
 				break;
 			}
@@ -88,8 +113,9 @@ public static function getAttributes(File $phpcsFile, int $attributeOpenerPointe
 				$attributes[] = new Attribute(
 					$attributeOpenerPointer,
 					$attributeName,
+					NamespaceHelper::resolveClassName($phpcsFile, $attributeName, $attributeOpenerPointer),
 					$attributeNameStartPointer,
-					$attributeNameEndPointer
+					$attributeNameEndPointer,
 				);
 
 				$actualPointer = $pointerAfterAttributeName;
@@ -99,19 +125,20 @@ public static function getAttributes(File $phpcsFile, int $attributeOpenerPointe
 				$attributes[] = new Attribute(
 					$attributeOpenerPointer,
 					$attributeName,
+					NamespaceHelper::resolveClassName($phpcsFile, $attributeName, $attributeOpenerPointer),
 					$attributeNameStartPointer,
 					$tokens[$pointerAfterAttributeName]['parenthesis_closer'],
 					TokenHelper::getContent(
 						$phpcsFile,
 						$pointerAfterAttributeName,
-						$tokens[$pointerAfterAttributeName]['parenthesis_closer']
-					)
+						$tokens[$pointerAfterAttributeName]['parenthesis_closer'],
+					),
 				);
 
 				$actualPointer = TokenHelper::findNextEffective(
 					$phpcsFile,
 					$tokens[$pointerAfterAttributeName]['parenthesis_closer'] + 1,
-					$attributeCloserPointer
+					$attributeCloserPointer,
 				);
 
 				continue;
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/CatchHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/CatchHelper.php
index b188b40d0..81084fe36 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/CatchHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/CatchHelper.php
@@ -3,7 +3,6 @@
 namespace SlevomatCodingStandard\Helpers;
 
 use PHP_CodeSniffer\Files\File;
-use function array_merge;
 use function in_array;
 use const T_BITWISE_OR;
 use const T_CATCH;
@@ -46,17 +45,15 @@ public static function findCaughtTypesInCatch(File $phpcsFile, array $catchToken
 		/** @var int $catchParenthesisCloserPointer */
 		$catchParenthesisCloserPointer = $catchToken['parenthesis_closer'];
 
-		$nameTokenCodes = TokenHelper::getNameTokenCodes();
-
 		$nameEndPointer = $catchParenthesisOpenerPointer;
 		$tokens = $phpcsFile->getTokens();
 		$caughtTypes = [];
 		do {
 			$nameStartPointer = TokenHelper::findNext(
 				$phpcsFile,
-				array_merge([T_BITWISE_OR], $nameTokenCodes),
+				[T_BITWISE_OR, ...TokenHelper::NAME_TOKEN_CODES],
 				$nameEndPointer + 1,
-				$catchParenthesisCloserPointer
+				$catchParenthesisCloserPointer,
 			);
 			if ($nameStartPointer === null) {
 				break;
@@ -67,13 +64,13 @@ public static function findCaughtTypesInCatch(File $phpcsFile, array $catchToken
 				$nameStartPointer = TokenHelper::findNextEffective($phpcsFile, $nameStartPointer + 1, $catchParenthesisCloserPointer);
 			}
 
-			$pointerAfterNameEndPointer = TokenHelper::findNextExcluding($phpcsFile, $nameTokenCodes, $nameStartPointer + 1);
+			$pointerAfterNameEndPointer = TokenHelper::findNextExcluding($phpcsFile, TokenHelper::NAME_TOKEN_CODES, $nameStartPointer + 1);
 			$nameEndPointer = $pointerAfterNameEndPointer === null ? $nameStartPointer : $pointerAfterNameEndPointer - 1;
 
 			$caughtTypes[] = NamespaceHelper::resolveClassName(
 				$phpcsFile,
 				TokenHelper::getContent($phpcsFile, $nameStartPointer, $nameEndPointer),
-				$catchParenthesisOpenerPointer
+				$catchParenthesisOpenerPointer,
 			);
 		} while (true);
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ClassHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ClassHelper.php
index 14d706623..49b2d811b 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ClassHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ClassHelper.php
@@ -3,7 +3,6 @@
 namespace SlevomatCodingStandard\Helpers;
 
 use PHP_CodeSniffer\Files\File;
-use function array_merge;
 use function array_reverse;
 use function sprintf;
 use const T_ANON_CLASS;
@@ -111,9 +110,11 @@ public static function getTraitUsePointers(File $phpcsFile, int $classPointer):
 	 */
 	private static function getAllClassPointers(File $phpcsFile): array
 	{
-		$lazyValue = static function () use ($phpcsFile): array {
-			return TokenHelper::findNextAll($phpcsFile, array_merge(TokenHelper::$typeKeywordTokenCodes, [T_ANON_CLASS]), 0);
-		};
+		$lazyValue = static fn (): array => TokenHelper::findNextAll(
+			$phpcsFile,
+			TokenHelper::CLASS_TYPE_WITH_ANONYMOUS_CLASS_TOKEN_CODES,
+			0,
+		);
 
 		return SniffLocalCache::getAndSetIfNotCached($phpcsFile, 'classPointers', $lazyValue);
 	}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/Comment.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/Comment.php
index 7a9fd3fdf..6154f4c04 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/Comment.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/Comment.php
@@ -8,11 +8,9 @@
 class Comment
 {
 
-	/** @var int */
-	private $pointer;
+	private int $pointer;
 
-	/** @var string */
-	private $content;
+	private string $content;
 
 	public function __construct(int $pointer, string $content)
 	{
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/CommentHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/CommentHelper.php
index 4dd226fdb..09b6e676c 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/CommentHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/CommentHelper.php
@@ -5,7 +5,7 @@
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Util\Tokens;
 use function array_key_exists;
-use function array_merge;
+use function in_array;
 use function preg_match;
 use function strpos;
 use const T_COMMENT;
@@ -38,13 +38,23 @@ public static function getCommentEndPointer(File $phpcsFile, int $commentStartPo
 			return null;
 		}
 
-		$nextPointerAfterComment = TokenHelper::findNextExcluding(
-			$phpcsFile,
-			array_merge([T_COMMENT], Tokens::$phpcsCommentTokens),
-			$commentStartPointer + 1
-		);
+		$commentEndPointer = $commentStartPointer;
+
+		for ($i = $commentStartPointer + 1; $i < $phpcsFile->numTokens; $i++) {
+			if ($tokens[$i]['code'] === T_COMMENT) {
+				$commentEndPointer = $i;
+				continue;
+			}
+
+			if (in_array($tokens[$i]['code'], Tokens::$phpcsCommentTokens, true)) {
+				$commentEndPointer = $i;
+				continue;
+			}
+
+			break;
+		}
 
-		return $nextPointerAfterComment - 1;
+		return $commentEndPointer;
 	}
 
 	public static function getMultilineCommentStartPointer(File $phpcsFile, int $commentEndPointer): int
@@ -53,7 +63,7 @@ public static function getMultilineCommentStartPointer(File $phpcsFile, int $com
 
 		$commentStartPointer = $commentEndPointer;
 		do {
-			$commentBefore = TokenHelper::findPrevious($phpcsFile, TokenHelper::$inlineCommentTokenCodes, $commentStartPointer - 1);
+			$commentBefore = TokenHelper::findPrevious($phpcsFile, TokenHelper::INLINE_COMMENT_TOKEN_CODES, $commentStartPointer - 1);
 			if ($commentBefore === null) {
 				break;
 			}
@@ -74,7 +84,7 @@ public static function getMultilineCommentEndPointer(File $phpcsFile, int $comme
 
 		$commentEndPointer = $commentStartPointer;
 		do {
-			$commentAfter = TokenHelper::findNext($phpcsFile, TokenHelper::$inlineCommentTokenCodes, $commentEndPointer + 1);
+			$commentAfter = TokenHelper::findNext($phpcsFile, TokenHelper::INLINE_COMMENT_TOKEN_CODES, $commentEndPointer + 1);
 			if ($commentAfter === null) {
 				break;
 			}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ConditionHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ConditionHelper.php
index 865e8250b..cdab8e916 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ConditionHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ConditionHelper.php
@@ -53,7 +53,7 @@ public static function conditionReturnsBoolean(
 		$tokens = $phpcsFile->getTokens();
 
 		$conditionContent = strtolower(
-			trim(TokenHelper::getContent($phpcsFile, $conditionBoundaryStartPointer, $conditionBoundaryEndPointer))
+			trim(TokenHelper::getContent($phpcsFile, $conditionBoundaryStartPointer, $conditionBoundaryEndPointer)),
 		);
 
 		if ($conditionContent === 'false' || $conditionContent === 'true') {
@@ -68,10 +68,10 @@ public static function conditionReturnsBoolean(
 				array_merge(
 					[T_OPEN_PARENTHESIS, T_LESS_THAN, T_GREATER_THAN],
 					Tokens::$booleanOperators,
-					Tokens::$equalityTokens
+					Tokens::$equalityTokens,
 				),
 				$actualPointer,
-				$conditionBoundaryEndPointer + 1
+				$conditionBoundaryEndPointer + 1,
 			);
 
 			if ($actualPointer === null) {
@@ -119,7 +119,7 @@ public static function getNegativeCondition(
 				? TokenHelper::getContent(
 					$phpcsFile,
 					$conditionBoundaryStartPointer,
-					$conditionStartPointer - 1
+					$conditionStartPointer - 1,
 				)
 				: '',
 			self::getNegativeConditionPart($phpcsFile, $conditionStartPointer, $conditionEndPointer, $nested),
@@ -127,9 +127,9 @@ public static function getNegativeCondition(
 				? TokenHelper::getContent(
 					$phpcsFile,
 					$conditionEndPointer + 1,
-					$conditionBoundaryEndPointer
+					$conditionBoundaryEndPointer,
 				)
-				: ''
+				: '',
 		);
 	}
 
@@ -156,7 +156,7 @@ private static function getNegativeConditionPart(
 			$phpcsFile,
 			Tokens::$booleanOperators,
 			$conditionBoundaryStartPointer,
-			$conditionBoundaryEndPointer + 1
+			$conditionBoundaryEndPointer + 1,
 		);
 
 		if ($tokens[$pointerAfterConditionStart]['code'] === T_BOOLEAN_NOT) {
@@ -169,7 +169,7 @@ private static function getNegativeConditionPart(
 				$pointerAfterParenthesisCloser = TokenHelper::findNextEffective(
 					$phpcsFile,
 					$tokens[$pointerAfterBooleanNot]['parenthesis_closer'] + 1,
-					$conditionBoundaryEndPointer + 1
+					$conditionBoundaryEndPointer + 1,
 				);
 				if (
 					$pointerAfterParenthesisCloser === null
@@ -178,7 +178,7 @@ private static function getNegativeConditionPart(
 					return TokenHelper::getContent(
 						$phpcsFile,
 						$pointerAfterBooleanNot + 1,
-						$tokens[$pointerAfterBooleanNot]['parenthesis_closer'] - 1
+						$tokens[$pointerAfterBooleanNot]['parenthesis_closer'] - 1,
 					);
 				}
 			}
@@ -196,7 +196,7 @@ private static function getNegativeConditionPart(
 			$phpcsFile,
 			[T_INSTANCEOF, T_BITWISE_AND, T_COALESCE, T_INLINE_THEN],
 			$conditionBoundaryStartPointer,
-			$conditionBoundaryEndPointer + 1
+			$conditionBoundaryEndPointer + 1,
 		) !== null) {
 			return sprintf('!(%s)', $condition);
 		}
@@ -226,7 +226,7 @@ private static function getNegativeConditionPart(
 			$phpcsFile,
 			[T_IS_EQUAL, T_IS_NOT_EQUAL, T_IS_IDENTICAL, T_IS_NOT_IDENTICAL, T_IS_SMALLER_OR_EQUAL, T_IS_GREATER_OR_EQUAL, T_LESS_THAN, T_GREATER_THAN],
 			$conditionBoundaryStartPointer,
-			$conditionBoundaryEndPointer + 1
+			$conditionBoundaryEndPointer + 1,
 		);
 		if ($comparisonPointer !== null) {
 			$comparisonReplacements = [
@@ -297,7 +297,7 @@ private static function getNegativeLogicalCondition(
 				$phpcsFile,
 				array_merge([T_OPEN_PARENTHESIS, T_CLOSE_PARENTHESIS], Tokens::$booleanOperators),
 				$actualPointer,
-				$conditionBoundaryEndPointer + 1
+				$conditionBoundaryEndPointer + 1,
 			);
 
 			if ($actualPointer === null) {
@@ -348,7 +348,7 @@ private static function getNegativeLogicalCondition(
 			$phpcsFile,
 			$nestedConditionStartPointer,
 			$conditionBoundaryEndPointer,
-			true
+			true,
 		);
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ConstantHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ConstantHelper.php
index 99978a093..a4cfd16de 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ConstantHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ConstantHelper.php
@@ -7,6 +7,7 @@
 use function array_filter;
 use function array_map;
 use function array_reverse;
+use function array_values;
 use function iterator_to_array;
 use function sprintf;
 use const T_CONST;
@@ -43,10 +44,8 @@ public static function getAllNames(File $phpcsFile): array
 		$previousConstantPointer = 0;
 
 		return array_map(
-			static function (int $constantPointer) use ($phpcsFile): string {
-				return self::getName($phpcsFile, $constantPointer);
-			},
-			array_filter(
+			static fn (int $constantPointer): string => self::getName($phpcsFile, $constantPointer),
+			array_values(array_filter(
 				iterator_to_array(self::getAllConstantPointers($phpcsFile, $previousConstantPointer)),
 				static function (int $constantPointer) use ($phpcsFile): bool {
 					foreach (array_reverse($phpcsFile->getTokens()[$constantPointer]['conditions']) as $conditionTokenCode) {
@@ -54,8 +53,8 @@ static function (int $constantPointer) use ($phpcsFile): bool {
 					}
 
 					return true;
-				}
-			)
+				},
+			)),
 		);
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/DocCommentHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/DocCommentHelper.php
index ffed9954d..f24b3b98d 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/DocCommentHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/DocCommentHelper.php
@@ -7,7 +7,6 @@
 use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocTextNode;
 use PHPStan\PhpDocParser\Parser\ParserException;
 use PHPStan\PhpDocParser\Parser\TokenIterator;
-use function array_merge;
 use function count;
 use function in_array;
 use function preg_match;
@@ -64,8 +63,8 @@ public static function getDocComment(File $phpcsFile, int $pointer): ?string
 			TokenHelper::getContent(
 				$phpcsFile,
 				$docCommentOpenToken,
-				$phpcsFile->getTokens()[$docCommentOpenToken]['comment_closer']
-			)
+				$phpcsFile->getTokens()[$docCommentOpenToken]['comment_closer'],
+			),
 		);
 	}
 
@@ -85,7 +84,7 @@ public static function getDocCommentDescription(File $phpcsFile, int $pointer):
 			$phpcsFile,
 			[T_DOC_COMMENT_WHITESPACE, T_DOC_COMMENT_STAR],
 			$docCommentOpenPointer + 1,
-			$tokens[$docCommentOpenPointer]['comment_closer']
+			$tokens[$docCommentOpenPointer]['comment_closer'],
 		);
 
 		if ($descriptionStartPointer === null) {
@@ -100,7 +99,7 @@ public static function getDocCommentDescription(File $phpcsFile, int $pointer):
 			$phpcsFile,
 			[T_DOC_COMMENT_TAG, T_DOC_COMMENT_CLOSE_TAG],
 			$descriptionStartPointer + 1,
-			$tokens[$docCommentOpenPointer]['comment_closer'] + 1
+			$tokens[$docCommentOpenPointer]['comment_closer'] + 1,
 		);
 
 		/** @var list $comments */
@@ -131,11 +130,17 @@ public static function hasInheritdocAnnotation(File $phpcsFile, int $pointer): b
 		}
 
 		foreach ($parsedDocComment->getNode()->children as $child) {
-			if ($child instanceof PhpDocTextNode && stripos($child->text, '{@inheritdoc}') !== false) {
-				return true;
+			if ($child instanceof PhpDocTagNode) {
+				if (strtolower($child->name) === '@inheritdoc') {
+					return true;
+				}
+
+				if (stripos((string) $child->value, '{@inheritdoc}') !== false) {
+					return true;
+				}
 			}
 
-			if ($child instanceof PhpDocTagNode && strtolower($child->name) === '@inheritdoc') {
+			if ($child instanceof PhpDocTextNode && stripos($child->text, '{@inheritdoc}') !== false) {
 				return true;
 			}
 		}
@@ -163,14 +168,14 @@ static function () use ($phpcsFile, $pointer): ?int {
 				$found = TokenHelper::findPrevious(
 					$phpcsFile,
 					[T_DOC_COMMENT_CLOSE_TAG, T_SEMICOLON, T_CLOSE_CURLY_BRACKET, T_OPEN_CURLY_BRACKET],
-					$pointer - 1
+					$pointer - 1,
 				);
 				if ($found !== null && $tokens[$found]['code'] === T_DOC_COMMENT_CLOSE_TAG) {
 					return $tokens[$found]['comment_opener'];
 				}
 
 				return null;
-			}
+			},
 		);
 	}
 
@@ -195,15 +200,15 @@ public static function findDocCommentOwnerPointer(File $phpcsFile, int $docComme
 			if (in_array(
 				$tokens[$i]['code'],
 				[T_PUBLIC, T_PROTECTED, T_PRIVATE, T_VAR, T_READONLY, T_FINAL, T_STATIC, T_ABSTRACT, T_WHITESPACE],
-				true
+				true,
 			)) {
 				continue;
 			}
 
 			if (in_array(
 				$tokens[$i]['code'],
-				array_merge([T_FUNCTION, T_VARIABLE, T_CONST], TokenHelper::$typeKeywordTokenCodes),
-				true
+				[T_FUNCTION, T_VARIABLE, T_CONST, ...TokenHelper::CLASS_TYPE_TOKEN_CODES],
+				true,
 			)) {
 				$docCommentOwnerPointer = $i;
 			}
@@ -225,7 +230,7 @@ public static function isInline(File $phpcsFile, int $docCommentOpenPointer): bo
 			&& in_array(
 				$tokens[$nextPointer]['code'],
 				[T_PUBLIC, T_PROTECTED, T_PRIVATE, T_READONLY, T_FINAL, T_STATIC, T_ABSTRACT, T_CONST, T_CLASS, T_INTERFACE, T_TRAIT, T_ENUM],
-				true
+				true,
 			)
 		) {
 			return false;
@@ -263,12 +268,12 @@ static function () use ($phpcsFile, $docCommentOpenPointer): ?ParsedDocComment {
 						$docCommentOpenPointer,
 						$phpcsFile->getTokens()[$docCommentOpenPointer]['comment_closer'],
 						$parsedDocComment,
-						$docCommentTokens
+						$docCommentTokens,
 					);
 				} catch (ParserException $e) {
 					return null;
 				}
-			}
+			},
 		);
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/EmptyFileException.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/EmptyFileException.php
index cbcdf7400..50c6db2ee 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/EmptyFileException.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/EmptyFileException.php
@@ -12,14 +12,13 @@
 class EmptyFileException extends Exception
 {
 
-	/** @var string */
-	private $filename;
+	private string $filename;
 
 	public function __construct(string $filename, ?Throwable $previous = null)
 	{
 		parent::__construct(sprintf(
 			'File %s is empty',
-			$filename
+			$filename,
 		), 0, $previous);
 
 		$this->filename = $filename;
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/FixerHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/FixerHelper.php
index d994bc6ca..8a65cc2b5 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/FixerHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/FixerHelper.php
@@ -12,10 +12,25 @@
 class FixerHelper
 {
 
+	public static function add(File $phpcsFile, int $pointer, string $content): void
+	{
+		$phpcsFile->fixer->addContent($pointer, IndentationHelper::convertSpacesToTabs($phpcsFile, $content));
+	}
+
+	public static function addBefore(File $phpcsFile, int $pointer, string $content): void
+	{
+		$phpcsFile->fixer->addContentBefore($pointer, IndentationHelper::convertSpacesToTabs($phpcsFile, $content));
+	}
+
+	public static function replace(File $phpcsFile, int $pointer, string $content): void
+	{
+		$phpcsFile->fixer->replaceToken($pointer, IndentationHelper::convertSpacesToTabs($phpcsFile, $content));
+	}
+
 	public static function change(File $phpcsFile, int $startPointer, int $endPointer, string $content): void
 	{
 		self::removeBetweenIncluding($phpcsFile, $startPointer, $endPointer);
-		$phpcsFile->fixer->replaceToken($startPointer, $content);
+		self::replace($phpcsFile, $startPointer, $content);
 	}
 
 	public static function removeBetween(File $phpcsFile, int $startPointer, int $endPointer): void
@@ -48,7 +63,7 @@ public static function removeWhitespaceAfter(File $phpcsFile, int $pointer): voi
 				break;
 			}
 
-			$phpcsFile->fixer->replaceToken($i, '');
+			self::replace($phpcsFile, $i, '');
 		}
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/FunctionHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/FunctionHelper.php
index 633e80b1c..3e5c7fbe8 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/FunctionHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/FunctionHelper.php
@@ -11,9 +11,9 @@
 use PHPStan\PhpDocParser\Ast\PhpDoc\VarTagValueNode;
 use function array_filter;
 use function array_map;
-use function array_merge;
 use function array_pop;
 use function array_reverse;
+use function array_values;
 use function in_array;
 use function iterator_to_array;
 use function preg_match;
@@ -90,6 +90,7 @@ class FunctionHelper
 		'is_string',
 		'ord',
 		'sizeof',
+		'sprintf',
 		'strlen',
 		'strval',
 	];
@@ -106,7 +107,7 @@ public static function getName(File $phpcsFile, int $functionPointer): string
 			$phpcsFile,
 			T_STRING,
 			$functionPointer + 1,
-			$tokens[$functionPointer]['parenthesis_opener']
+			$tokens[$functionPointer]['parenthesis_opener'],
 		)]['content'];
 	}
 
@@ -118,7 +119,7 @@ public static function getFullyQualifiedName(File $phpcsFile, int $functionPoint
 		if (self::isMethod($phpcsFile, $functionPointer)) {
 			foreach (array_reverse(
 				$phpcsFile->getTokens()[$functionPointer]['conditions'],
-				true
+				true,
 			) as $conditionPointer => $conditionTokenCode) {
 				if ($conditionTokenCode === T_ANON_CLASS) {
 					return sprintf('class@anonymous::%s', $name);
@@ -129,7 +130,7 @@ public static function getFullyQualifiedName(File $phpcsFile, int $functionPoint
 						'%s%s::%s',
 						NamespaceHelper::NAMESPACE_SEPARATOR,
 						ClassHelper::getName($phpcsFile, $conditionPointer),
-						$name
+						$name,
 					);
 					break;
 				}
@@ -213,11 +214,11 @@ public static function getParametersTypeHints(File $phpcsFile, int $functionPoin
 
 			$pointerBeforeVariable = TokenHelper::findPreviousExcluding(
 				$phpcsFile,
-				array_merge(TokenHelper::$ineffectiveTokenCodes, [T_BITWISE_AND, T_ELLIPSIS]),
-				$i - 1
+				[...TokenHelper::INEFFECTIVE_TOKEN_CODES, T_BITWISE_AND, T_ELLIPSIS],
+				$i - 1,
 			);
 
-			if (!in_array($tokens[$pointerBeforeVariable]['code'], TokenHelper::getTypeHintTokenCodes(), true)) {
+			if (!in_array($tokens[$pointerBeforeVariable]['code'], TokenHelper::TYPE_HINT_TOKEN_CODES, true)) {
 				$parametersTypeHints[$parameterName] = null;
 				continue;
 			}
@@ -454,15 +455,11 @@ public static function getAllFunctionNames(File $phpcsFile): array
 		$previousFunctionPointer = 0;
 
 		return array_map(
-			static function (int $functionPointer) use ($phpcsFile): string {
-				return self::getName($phpcsFile, $functionPointer);
-			},
-			array_filter(
+			static fn (int $functionPointer): string => self::getName($phpcsFile, $functionPointer),
+			array_values(array_filter(
 				iterator_to_array(self::getAllFunctionOrMethodPointers($phpcsFile, $previousFunctionPointer)),
-				static function (int $functionOrMethodPointer) use ($phpcsFile): bool {
-					return !self::isMethod($phpcsFile, $functionOrMethodPointer);
-				}
-			)
+				static fn (int $functionOrMethodPointer): bool => !self::isMethod($phpcsFile, $functionOrMethodPointer),
+			)),
 		);
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/IdentificatorHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/IdentificatorHelper.php
index b64d3093e..613c8b176 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/IdentificatorHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/IdentificatorHelper.php
@@ -4,7 +4,6 @@
 
 use PHP_CodeSniffer\Files\File;
 use function array_key_exists;
-use function array_merge;
 use function in_array;
 use const T_CLOSE_CURLY_BRACKET;
 use const T_CLOSE_PARENTHESIS;
@@ -32,7 +31,7 @@ public static function getContent(File $phpcsFile, int $startPointer, int $endPo
 
 		$variableContent = '';
 		for ($i = $startPointer; $i <= $endPointer; $i++) {
-			if (in_array($tokens[$i]['code'], TokenHelper::$ineffectiveTokenCodes, true)) {
+			if (in_array($tokens[$i]['code'], TokenHelper::INEFFECTIVE_TOKEN_CODES, true)) {
 				continue;
 			}
 
@@ -46,7 +45,7 @@ public static function findStartPointer(File $phpcsFile, int $endPointer): ?int
 	{
 		$tokens = $phpcsFile->getTokens();
 
-		if (in_array($tokens[$endPointer]['code'], TokenHelper::getNameTokenCodes(), true)) {
+		if (in_array($tokens[$endPointer]['code'], TokenHelper::NAME_TOKEN_CODES, true)) {
 			/** @var int $previousPointer */
 			$previousPointer = TokenHelper::findPreviousEffective($phpcsFile, $endPointer - 1);
 			if (in_array($tokens[$previousPointer]['code'], [T_OBJECT_OPERATOR, T_NULLSAFE_OBJECT_OPERATOR, T_DOUBLE_COLON], true)) {
@@ -74,10 +73,8 @@ public static function findEndPointer(File $phpcsFile, int $startPointer): ?int
 	{
 		$tokens = $phpcsFile->getTokens();
 
-		$nameTokenCodes = TokenHelper::getNameTokenCodes();
-
-		if (in_array($tokens[$startPointer]['code'], $nameTokenCodes, true)) {
-			$startPointer = TokenHelper::findNextExcluding($phpcsFile, $nameTokenCodes, $startPointer + 1) - 1;
+		if (in_array($tokens[$startPointer]['code'], TokenHelper::NAME_TOKEN_CODES, true)) {
+			$startPointer = TokenHelper::findNextExcluding($phpcsFile, TokenHelper::NAME_TOKEN_CODES, $startPointer + 1) - 1;
 		} elseif ($tokens[$startPointer]['code'] === T_DOLLAR) {
 			$startPointer = TokenHelper::findNextEffective($phpcsFile, $startPointer + 1);
 		}
@@ -86,7 +83,7 @@ public static function findEndPointer(File $phpcsFile, int $startPointer): ?int
 		$nextPointer = TokenHelper::findNextEffective($phpcsFile, $startPointer + 1);
 
 		if (
-			in_array($tokens[$startPointer]['code'], array_merge([T_SELF, T_STATIC, T_PARENT], $nameTokenCodes), true)
+			in_array($tokens[$startPointer]['code'], [T_SELF, T_STATIC, T_PARENT, ...TokenHelper::NAME_TOKEN_CODES], true)
 			&& $tokens[$nextPointer]['code'] === T_DOUBLE_COLON
 		) {
 			return self::getEndPointerAfterOperator($phpcsFile, $nextPointer);
@@ -111,23 +108,21 @@ private static function getStartPointerBeforeOperator(File $phpcsFile, int $oper
 	{
 		$tokens = $phpcsFile->getTokens();
 
-		$nameTokenCodes = TokenHelper::getNameTokenCodes();
-
 		/** @var int $previousPointer */
 		$previousPointer = TokenHelper::findPreviousEffective($phpcsFile, $operatorPointer - 1);
 
-		if (in_array($tokens[$previousPointer]['code'], $nameTokenCodes, true)) {
-			$previousPointer = TokenHelper::findPreviousExcluding($phpcsFile, $nameTokenCodes, $previousPointer - 1) + 1;
+		if (in_array($tokens[$previousPointer]['code'], TokenHelper::NAME_TOKEN_CODES, true)) {
+			$previousPointer = TokenHelper::findPreviousExcluding($phpcsFile, TokenHelper::NAME_TOKEN_CODES, $previousPointer - 1) + 1;
 		}
 
 		if (
 			$tokens[$operatorPointer]['code'] === T_DOUBLE_COLON
-			&& in_array($tokens[$previousPointer]['code'], array_merge([T_SELF, T_STATIC, T_PARENT], $nameTokenCodes), true)
+			&& in_array($tokens[$previousPointer]['code'], [T_SELF, T_STATIC, T_PARENT, ...TokenHelper::NAME_TOKEN_CODES], true)
 		) {
 			return $previousPointer;
 		}
 
-		if (in_array($tokens[$previousPointer]['code'], $nameTokenCodes, true)) {
+		if (in_array($tokens[$previousPointer]['code'], TokenHelper::NAME_TOKEN_CODES, true)) {
 			/** @var int $possibleOperatorPointer */
 			$possibleOperatorPointer = TokenHelper::findPreviousEffective($phpcsFile, $previousPointer - 1);
 			if (in_array($tokens[$possibleOperatorPointer]['code'], [T_OBJECT_OPERATOR, T_NULLSAFE_OBJECT_OPERATOR], true)) {
@@ -169,7 +164,7 @@ private static function getStartPointerBeforeVariablePart(File $phpcsFile, int $
 			return self::getStartPointerBeforeVariablePart($phpcsFile, $tokens[$previousPointer]['bracket_opener']);
 		}
 
-		if (in_array($tokens[$previousPointer]['code'], array_merge([T_VARIABLE], TokenHelper::getNameTokenCodes()), true)) {
+		if (in_array($tokens[$previousPointer]['code'], [T_VARIABLE, ...TokenHelper::NAME_TOKEN_CODES], true)) {
 			return self::getStartPointerBeforeVariablePart($phpcsFile, $previousPointer);
 		}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/IndentationHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/IndentationHelper.php
index e6daae0d1..995bd3bc0 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/IndentationHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/IndentationHelper.php
@@ -3,6 +3,7 @@
 namespace SlevomatCodingStandard\Helpers;
 
 use PHP_CodeSniffer\Files\File;
+use function floor;
 use function in_array;
 use function ltrim;
 use function preg_replace_callback;
@@ -23,9 +24,6 @@ class IndentationHelper
 
 	public const DEFAULT_INDENTATION_WIDTH = 4;
 
-	public const TAB_INDENT = "\t";
-	public const SPACES_INDENT = '    ';
-
 	public static function getIndentation(File $phpcsFile, int $pointer): string
 	{
 		$firstPointerOnLine = TokenHelper::findFirstTokenOnLine($phpcsFile, $pointer);
@@ -33,24 +31,20 @@ public static function getIndentation(File $phpcsFile, int $pointer): string
 		return TokenHelper::getContent($phpcsFile, $firstPointerOnLine, $pointer - 1);
 	}
 
-	public static function addIndentation(string $indentation, int $level = 1): string
+	public static function addIndentation(File $phpcsFile, string $indentation, int $level = 1): string
 	{
-		$whitespace = self::getOneIndentationLevel($indentation);
-
-		return $indentation . str_repeat($whitespace, $level);
+		return $indentation . str_repeat(self::getOneIndentationLevel($phpcsFile), $level);
 	}
 
-	public static function getOneIndentationLevel(string $indentation): string
+	public static function getOneIndentationLevel(File $phpcsFile): string
 	{
-		return $indentation === ''
-			? self::TAB_INDENT
-			: ($indentation[0] === self::TAB_INDENT ? self::TAB_INDENT : self::SPACES_INDENT);
+		return str_repeat(' ', $phpcsFile->config->tabWidth !== 0 ? $phpcsFile->config->tabWidth : self::DEFAULT_INDENTATION_WIDTH);
 	}
 
 	/**
 	 * @param list $codePointers
 	 */
-	public static function fixIndentation(File $phpcsFile, array $codePointers, string $defaultIndentation): string
+	public static function removeIndentation(File $phpcsFile, array $codePointers, string $defaultIndentation): string
 	{
 		$tokens = $phpcsFile->getTokens();
 
@@ -59,6 +53,9 @@ public static function fixIndentation(File $phpcsFile, array $codePointers, stri
 		$code = '';
 		$inHeredoc = false;
 
+		$indentation = self::getOneIndentationLevel($phpcsFile);
+		$indentationLength = strlen($indentation);
+
 		foreach ($codePointers as $no => $codePointer) {
 			$content = $tokens[$codePointer]['content'];
 
@@ -71,10 +68,8 @@ public static function fixIndentation(File $phpcsFile, array $codePointers, stri
 			) {
 				if ($content === $phpcsFile->eolChar) {
 					// Nothing
-				} elseif ($content[0] === self::TAB_INDENT) {
-					$content = substr($content, 1);
-				} elseif (substr($content, 0, self::DEFAULT_INDENTATION_WIDTH) === self::SPACES_INDENT) {
-					$content = substr($content, self::DEFAULT_INDENTATION_WIDTH);
+				} elseif (substr($content, 0, $indentationLength) === $indentation) {
+					$content = substr($content, $indentationLength);
 				} else {
 					$content = $defaultIndentation . ltrim($content);
 				}
@@ -92,14 +87,19 @@ public static function fixIndentation(File $phpcsFile, array $codePointers, stri
 		return rtrim($code);
 	}
 
-	public static function convertTabsToSpaces(File $phpcsFile, string $code): string
+	public static function convertSpacesToTabs(File $phpcsFile, string $code): string
 	{
-		return preg_replace_callback('~^(\t+)~', static function (array $matches) use ($phpcsFile): string {
-			$indentation = str_repeat(
-				' ',
-				$phpcsFile->config->tabWidth !== 0 ? $phpcsFile->config->tabWidth : self::DEFAULT_INDENTATION_WIDTH
-			);
-			return str_repeat($indentation, strlen($matches[1]));
+		// @codeCoverageIgnoreStart
+		if ($phpcsFile->config->tabWidth === 0) {
+			return $code;
+		}
+		// @codeCoverageIgnoreEnd
+
+		return preg_replace_callback('~^([ ]+)~m', static function (array $matches) use ($phpcsFile): string {
+			$tabsCount = (int) floor(strlen($matches[1]) / $phpcsFile->config->tabWidth);
+			$spacesCountToRemove = $tabsCount * $phpcsFile->config->tabWidth;
+
+			return str_repeat("\t", $tabsCount) . substr($matches[1], $spacesCountToRemove);
 		}, $code);
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/NamespaceHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/NamespaceHelper.php
index 708f7d935..5bb24ca5f 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/NamespaceHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/NamespaceHelper.php
@@ -45,7 +45,7 @@ public static function getAllNamespacesPointers(File $phpcsFile): array
 				static function ($pointer) use ($phpcsFile, $tokens) {
 					$next = TokenHelper::findNextEffective($phpcsFile, $pointer + 1);
 					return $next === null || $tokens[$next]['code'] !== T_NS_SEPARATOR;
-				}
+				},
 			);
 
 			return array_values($all);
@@ -101,8 +101,8 @@ public static function getName(File $phpcsFile, int $namespacePointer): string
 		$namespaceNameStartPointer = TokenHelper::findNextEffective($phpcsFile, $namespacePointer + 1);
 		$namespaceNameEndPointer = TokenHelper::findNextExcluding(
 			$phpcsFile,
-			TokenHelper::getNameTokenCodes(),
-			$namespaceNameStartPointer + 1
+			TokenHelper::NAME_TOKEN_CODES,
+			$namespaceNameStartPointer + 1,
 		) - 1;
 
 		return TokenHelper::getContent($phpcsFile, $namespaceNameStartPointer, $namespaceNameEndPointer);
@@ -150,7 +150,7 @@ public static function isTypeInNamespace(string $typeName, string $namespace): b
 	{
 		return StringHelper::startsWith(
 			self::normalizeToCanonicalName($typeName) . '\\',
-			$namespace . '\\'
+			$namespace . '\\',
 		);
 	}
 
@@ -181,7 +181,7 @@ public static function resolveName(File $phpcsFile, string $nameAsReferencedInFi
 				self::NAMESPACE_SEPARATOR,
 				$useStatements[$firstPartUniqueId]->getFullyQualifiedTypeName(),
 				self::NAMESPACE_SEPARATOR,
-				implode(self::NAMESPACE_SEPARATOR, array_slice($nameParts, 1))
+				implode(self::NAMESPACE_SEPARATOR, array_slice($nameParts, 1)),
 			);
 		}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ParameterHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ParameterHelper.php
index 6c4c55565..563d16862 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ParameterHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ParameterHelper.php
@@ -28,7 +28,7 @@ public static function isParameter(File $phpcsFile, int $variablePointer): bool
 		}
 
 		$parenthesisOwnerPointer = $tokens[$parenthesisOpenerPointer]['parenthesis_owner'];
-		return in_array($tokens[$parenthesisOwnerPointer]['code'], TokenHelper::$functionTokenCodes, true);
+		return in_array($tokens[$parenthesisOwnerPointer]['code'], TokenHelper::FUNCTION_TOKEN_CODES, true);
 	}
 
 }
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ParsedDocComment.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ParsedDocComment.php
index 2c4fa0113..b5d5f1bf3 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ParsedDocComment.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ParsedDocComment.php
@@ -7,7 +7,6 @@
 use PHPStan\PhpDocParser\Ast\Node;
 use PHPStan\PhpDocParser\Ast\PhpDoc\PhpDocNode;
 use PHPStan\PhpDocParser\Parser\TokenIterator;
-use function array_merge;
 use function count;
 use function strlen;
 use function trim;
@@ -19,17 +18,13 @@
 class ParsedDocComment
 {
 
-	/** @var int */
-	private $openPointer;
+	private int $openPointer;
 
-	/** @var int */
-	private $closePointer;
+	private int $closePointer;
 
-	/** @var PhpDocNode */
-	private $node;
+	private PhpDocNode $node;
 
-	/** @var TokenIterator */
-	private $tokens;
+	private TokenIterator $tokens;
 
 	public function __construct(int $openPointer, int $closePointer, PhpDocNode $node, TokenIterator $tokens)
 	{
@@ -73,7 +68,7 @@ public function getNodeStartPointer(File $phpcsFile, Node $node): int
 			}
 		}
 
-		return TokenHelper::findNext($phpcsFile, array_merge(TokenHelper::$annotationTokenCodes, [T_DOC_COMMENT_STRING]), $searchPointer);
+		return TokenHelper::findNext($phpcsFile, [...TokenHelper::ANNOTATION_TOKEN_CODES, T_DOC_COMMENT_STRING], $searchPointer);
 	}
 
 	public function getNodeEndPointer(File $phpcsFile, Node $node, int $nodeStartPointer): int
@@ -82,7 +77,7 @@ public function getNodeEndPointer(File $phpcsFile, Node $node, int $nodeStartPoi
 
 		$content = trim($this->tokens->getContentBetween(
 			$node->getAttribute(Attribute::START_INDEX),
-			$node->getAttribute(Attribute::END_INDEX) + 1
+			$node->getAttribute(Attribute::END_INDEX) + 1,
 		));
 		$length = strlen($content);
 
@@ -100,8 +95,8 @@ public function getNodeEndPointer(File $phpcsFile, Node $node, int $nodeStartPoi
 
 		return TokenHelper::findPrevious(
 			$phpcsFile,
-			array_merge(TokenHelper::$annotationTokenCodes, [T_DOC_COMMENT_STRING]),
-			$searchPointer
+			[...TokenHelper::ANNOTATION_TOKEN_CODES, T_DOC_COMMENT_STRING],
+			$searchPointer,
 		);
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/PhpDocParserHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/PhpDocParserHelper.php
index 6cc06d61a..4ac6cf090 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/PhpDocParserHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/PhpDocParserHelper.php
@@ -9,6 +9,7 @@
 use PHPStan\PhpDocParser\Parser\ConstExprParser;
 use PHPStan\PhpDocParser\Parser\PhpDocParser;
 use PHPStan\PhpDocParser\Parser\TypeParser;
+use PHPStan\PhpDocParser\ParserConfig;
 use PHPStan\PhpDocParser\Printer\Printer;
 
 /**
@@ -22,7 +23,7 @@ public static function getLexer(): Lexer
 		static $lexer;
 
 		if ($lexer === null) {
-			$lexer = new Lexer(true);
+			$lexer = new Lexer(self::getConfig());
 		}
 
 		return $lexer;
@@ -33,17 +34,12 @@ public static function getParser(): PhpDocParser
 		static $parser;
 
 		if ($parser === null) {
-			$usedAttributes = ['lines' => true, 'indexes' => true];
-
-			$constantExpressionParser = new ConstExprParser(true, true, $usedAttributes);
+			$config = self::getConfig();
+			$constantExpressionParser = new ConstExprParser($config);
 			$parser = new PhpDocParser(
-				new TypeParser($constantExpressionParser, true, $usedAttributes),
+				$config,
+				new TypeParser($config, $constantExpressionParser),
 				$constantExpressionParser,
-				true,
-				true,
-				$usedAttributes,
-				true,
-				true
 			);
 		}
 
@@ -79,4 +75,15 @@ public static function cloneNode(Node $node): Node
 		return $cloneNode;
 	}
 
+	private static function getConfig(): ParserConfig
+	{
+		static $config;
+
+		if ($config === null) {
+			$config = new ParserConfig(['lines' => true, 'indexes' => true]);
+		}
+
+		return $config;
+	}
+
 }
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/PropertyHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/PropertyHelper.php
index 74a0726fc..bc53d9db6 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/PropertyHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/PropertyHelper.php
@@ -6,7 +6,6 @@
 use PHP_CodeSniffer\Util\Tokens;
 use function array_key_exists;
 use function array_keys;
-use function array_merge;
 use function array_reverse;
 use function array_values;
 use function count;
@@ -14,18 +13,18 @@
 use function preg_match;
 use function preg_replace;
 use function sprintf;
+use const T_ABSTRACT;
 use const T_ANON_CLASS;
 use const T_CLOSE_CURLY_BRACKET;
+use const T_COMMA;
+use const T_FINAL;
 use const T_FUNCTION;
 use const T_NULLABLE;
 use const T_OPEN_CURLY_BRACKET;
-use const T_PRIVATE;
-use const T_PROTECTED;
-use const T_PUBLIC;
+use const T_OPEN_PARENTHESIS;
 use const T_READONLY;
 use const T_SEMICOLON;
 use const T_STATIC;
-use const T_VAR;
 
 /**
  * @internal
@@ -39,15 +38,23 @@ public static function isProperty(File $phpcsFile, int $variablePointer, bool $p
 
 		$previousPointer = TokenHelper::findPreviousExcluding(
 			$phpcsFile,
-			array_merge(TokenHelper::$ineffectiveTokenCodes, TokenHelper::getTypeHintTokenCodes(), [T_NULLABLE]),
-			$variablePointer - 1
+			[...TokenHelper::INEFFECTIVE_TOKEN_CODES, ...TokenHelper::TYPE_HINT_TOKEN_CODES, T_NULLABLE],
+			$variablePointer - 1,
 		);
 
+		if (in_array($tokens[$previousPointer]['code'], [T_FINAL, T_ABSTRACT], true)) {
+			return true;
+		}
+
 		if ($tokens[$previousPointer]['code'] === T_STATIC) {
 			$previousPointer = TokenHelper::findPreviousEffective($phpcsFile, $previousPointer - 1);
 		}
 
-		if (in_array($tokens[$previousPointer]['code'], [T_PUBLIC, T_PROTECTED, T_PRIVATE, T_VAR, T_READONLY], true)) {
+		if (in_array(
+			$tokens[$previousPointer]['code'],
+			[...array_values(Tokens::$scopeModifiers), T_READONLY],
+			true,
+		)) {
 			$constructorPointer = TokenHelper::findPrevious($phpcsFile, T_FUNCTION, $previousPointer - 1);
 
 			if ($constructorPointer === null) {
@@ -66,36 +73,100 @@ public static function isProperty(File $phpcsFile, int $variablePointer, bool $p
 
 		$functionPointer = TokenHelper::findPrevious(
 			$phpcsFile,
-			array_merge(TokenHelper::$functionTokenCodes, [T_SEMICOLON, T_CLOSE_CURLY_BRACKET, T_OPEN_CURLY_BRACKET]),
-			$variablePointer - 1
+			[...TokenHelper::FUNCTION_TOKEN_CODES, T_SEMICOLON, T_CLOSE_CURLY_BRACKET, T_OPEN_CURLY_BRACKET],
+			$variablePointer - 1,
 		);
 		if (
 			$functionPointer !== null
-			&& in_array($tokens[$functionPointer]['code'], TokenHelper::$functionTokenCodes, true)
+			&& in_array($tokens[$functionPointer]['code'], TokenHelper::FUNCTION_TOKEN_CODES, true)
 		) {
 			return false;
 		}
 
+		$previousParenthesisPointer = TokenHelper::findPrevious($phpcsFile, T_OPEN_PARENTHESIS, $variablePointer - 1);
+		if ($previousParenthesisPointer !== null && $tokens[$previousParenthesisPointer]['parenthesis_closer'] > $variablePointer) {
+			$previousPointer = TokenHelper::findPreviousEffective($phpcsFile, $previousParenthesisPointer - 1);
+			if ($previousPointer !== null && in_array($tokens[$previousPointer]['content'], ['get', 'set'], true)) {
+				// Parameter of property hook
+				return false;
+			}
+		}
+
+		$previousCurlyBracketPointer = TokenHelper::findPrevious($phpcsFile, T_OPEN_CURLY_BRACKET, $variablePointer - 1);
+		if (
+			$previousCurlyBracketPointer !== null
+			&& $tokens[$previousCurlyBracketPointer]['bracket_closer'] > $variablePointer
+		) {
+			// Variable in content of property hook
+			if (!array_key_exists('scope_condition', $tokens[$previousCurlyBracketPointer])) {
+				return false;
+			}
+		}
+
 		$conditionCode = array_values($tokens[$variablePointer]['conditions'])[count($tokens[$variablePointer]['conditions']) - 1];
 
 		return in_array($conditionCode, Tokens::$ooScopeTokens, true);
 	}
 
+	public static function getStartPointer(File $phpcsFile, int $propertyPointer): int
+	{
+		$previousCodeEndPointer = TokenHelper::findPrevious(
+			$phpcsFile,
+			[
+				// Previous property or constant
+				T_SEMICOLON,
+				// Previous method or property with hooks
+				T_CLOSE_CURLY_BRACKET,
+				// Start of the class
+				T_OPEN_CURLY_BRACKET,
+				// Start of the constructor
+				T_OPEN_PARENTHESIS,
+				// Previous parameter in the constructor
+				T_COMMA,
+			],
+			$propertyPointer - 1,
+		);
+
+		$startPointer = TokenHelper::findPreviousEffective($phpcsFile, $propertyPointer - 1, $previousCodeEndPointer);
+
+		do {
+			$possibleStartPointer = TokenHelper::findPrevious(
+				$phpcsFile,
+				TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES,
+				$startPointer - 1,
+				$previousCodeEndPointer,
+			);
+
+			if ($possibleStartPointer === null) {
+				return $startPointer;
+			}
+
+			$startPointer = $possibleStartPointer;
+		} while (true);
+	}
+
+	public static function getEndPointer(File $phpcsFile, int $propertyPointer): int
+	{
+		$tokens = $phpcsFile->getTokens();
+
+		$endPointer = TokenHelper::findNext($phpcsFile, [T_SEMICOLON, T_OPEN_CURLY_BRACKET], $propertyPointer + 1);
+
+		return $tokens[$endPointer]['code'] === T_OPEN_CURLY_BRACKET
+			? $tokens[$endPointer]['bracket_closer']
+			: $endPointer;
+	}
+
 	public static function findTypeHint(File $phpcsFile, int $propertyPointer): ?TypeHint
 	{
 		$tokens = $phpcsFile->getTokens();
 
-		$propertyStartPointer = TokenHelper::findPrevious(
-			$phpcsFile,
-			[T_PRIVATE, T_PROTECTED, T_PUBLIC, T_VAR, T_STATIC, T_READONLY],
-			$propertyPointer - 1
-		);
+		$propertyStartPointer = self::getStartPointer($phpcsFile, $propertyPointer);
 
 		$typeHintEndPointer = TokenHelper::findPrevious(
 			$phpcsFile,
-			TokenHelper::getTypeHintTokenCodes(),
+			TokenHelper::TYPE_HINT_TOKEN_CODES,
 			$propertyPointer - 1,
-			$propertyStartPointer
+			$propertyStartPointer,
 		);
 		if ($typeHintEndPointer === null) {
 			return null;
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ReferencedName.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ReferencedName.php
index 8890db40d..366304034 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ReferencedName.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ReferencedName.php
@@ -12,17 +12,13 @@ class ReferencedName
 	public const TYPE_FUNCTION = 'function';
 	public const TYPE_CONSTANT = 'constant';
 
-	/** @var string */
-	private $nameAsReferencedInFile;
+	private string $nameAsReferencedInFile;
 
-	/** @var int */
-	private $startPointer;
+	private int $startPointer;
 
-	/** @var int */
-	private $endPointer;
+	private int $endPointer;
 
-	/** @var string */
-	private $type;
+	private string $type;
 
 	public function __construct(string $nameAsReferencedInFile, int $startPointer, int $endPointer, string $type)
 	{
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ReferencedNameHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ReferencedNameHelper.php
index 1a91a6e06..c90d2b202 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ReferencedNameHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ReferencedNameHelper.php
@@ -4,7 +4,7 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Util\Tokens;
-use function array_merge;
+use function array_key_exists;
 use function array_reverse;
 use function array_values;
 use function count;
@@ -35,6 +35,9 @@
 use const T_HEREDOC;
 use const T_IMPLEMENTS;
 use const T_INSTANCEOF;
+use const T_NAME_FULLY_QUALIFIED;
+use const T_NAME_QUALIFIED;
+use const T_NAME_RELATIVE;
 use const T_NAMESPACE;
 use const T_NEW;
 use const T_NS_SEPARATOR;
@@ -51,6 +54,7 @@
 use const T_TYPE_UNION;
 use const T_USE;
 use const T_VARIABLE;
+use const T_WHITESPACE;
 
 /**
  * @internal
@@ -63,9 +67,7 @@ class ReferencedNameHelper
 	 */
 	public static function getAllReferencedNames(File $phpcsFile, int $openTagPointer): array
 	{
-		$lazyValue = static function () use ($phpcsFile, $openTagPointer): array {
-			return self::createAllReferencedNames($phpcsFile, $openTagPointer);
-		};
+		$lazyValue = static fn (): array => self::createAllReferencedNames($phpcsFile, $openTagPointer);
 
 		return SniffLocalCache::getAndSetIfNotCached($phpcsFile, 'references', $lazyValue);
 	}
@@ -75,9 +77,7 @@ public static function getAllReferencedNames(File $phpcsFile, int $openTagPointe
 	 */
 	public static function getAllReferencedNamesInAttributes(File $phpcsFile, int $openTagPointer): array
 	{
-		$lazyValue = static function () use ($phpcsFile, $openTagPointer): array {
-			return self::createAllReferencedNamesInAttributes($phpcsFile, $openTagPointer);
-		};
+		$lazyValue = static fn (): array => self::createAllReferencedNamesInAttributes($phpcsFile, $openTagPointer);
 
 		return SniffLocalCache::getAndSetIfNotCached($phpcsFile, 'referencesFromAttributes', $lazyValue);
 	}
@@ -102,9 +102,7 @@ public static function getReferencedNameEndPointer(File $phpcsFile, int $startPo
 	{
 		$tokens = $phpcsFile->getTokens();
 
-		$nameTokenCodes = TokenHelper::getNameTokenCodes();
-
-		$nameTokenCodesWithWhitespace = array_merge($nameTokenCodes, Tokens::$emptyTokens);
+		$nameTokenCodesWithWhitespace = [...TokenHelper::NAME_TOKEN_CODES, ...TokenHelper::INEFFECTIVE_TOKEN_CODES];
 
 		$lastNamePointer = $startPointer;
 		for ($i = $startPointer + 1; $i < count($tokens); $i++) {
@@ -112,7 +110,7 @@ public static function getReferencedNameEndPointer(File $phpcsFile, int $startPo
 				break;
 			}
 
-			if (!in_array($tokens[$i]['code'], $nameTokenCodes, true)) {
+			if (!in_array($tokens[$i]['code'], TokenHelper::NAME_TOKEN_CODES, true)) {
 				continue;
 			}
 
@@ -130,7 +128,7 @@ private static function createAllReferencedNames(File $phpcsFile, int $openTagPo
 		$referencedNames = [];
 
 		$beginSearchAtPointer = $openTagPointer + 1;
-		$nameTokenCodes = TokenHelper::getNameTokenCodes();
+		$nameTokenCodes = TokenHelper::NAME_TOKEN_CODES;
 		$nameTokenCodes[] = T_DOUBLE_QUOTED_STRING;
 		$nameTokenCodes[] = T_HEREDOC;
 
@@ -172,8 +170,8 @@ private static function createAllReferencedNames(File $phpcsFile, int $openTagPo
 				/** @var int $beginSearchAtPointer */
 				$beginSearchAtPointer = TokenHelper::findNextExcluding(
 					$phpcsFile,
-					array_merge(TokenHelper::$ineffectiveTokenCodes, $nameTokenCodes),
-					$nameStartPointer + 1
+					[...TokenHelper::INEFFECTIVE_TOKEN_CODES, ...$nameTokenCodes],
+					$nameStartPointer + 1,
 				);
 				continue;
 			}
@@ -184,7 +182,7 @@ private static function createAllReferencedNames(File $phpcsFile, int $openTagPo
 				self::getReferenceName($phpcsFile, $nameStartPointer, $nameEndPointer),
 				$nameStartPointer,
 				$nameEndPointer,
-				self::getReferenceType($phpcsFile, $nameStartPointer, $nameEndPointer)
+				self::getReferenceType($phpcsFile, $nameStartPointer, $nameEndPointer),
 			);
 			$beginSearchAtPointer = $nameEndPointer + 1;
 		}
@@ -198,8 +196,6 @@ private static function getReferenceType(File $phpcsFile, int $nameStartPointer,
 		$nextTokenAfterEndPointer = TokenHelper::findNextEffective($phpcsFile, $nameEndPointer + 1);
 		$previousTokenBeforeStartPointer = TokenHelper::findPreviousEffective($phpcsFile, $nameStartPointer - 1);
 
-		$nameTokenCodes = TokenHelper::getNameTokenCodes();
-
 		if ($tokens[$nextTokenAfterEndPointer]['code'] === T_OPEN_PARENTHESIS) {
 			return $tokens[$previousTokenBeforeStartPointer]['code'] === T_NEW
 				? ReferencedName::TYPE_CLASS
@@ -271,8 +267,8 @@ private static function getReferenceType(File $phpcsFile, int $nameStartPointer,
 		if ($tokens[$previousTokenBeforeStartPointer]['code'] === T_COMMA) {
 			$previousTokenPointer = TokenHelper::findPreviousExcluding(
 				$phpcsFile,
-				array_merge([T_COMMA], $nameTokenCodes, TokenHelper::$ineffectiveTokenCodes),
-				$previousTokenBeforeStartPointer - 1
+				[T_COMMA, ...TokenHelper::NAME_TOKEN_CODES, ...TokenHelper::INEFFECTIVE_TOKEN_CODES],
+				$previousTokenBeforeStartPointer - 1,
 			);
 
 			return in_array($tokens[$previousTokenPointer]['code'], [
@@ -287,8 +283,8 @@ private static function getReferenceType(File $phpcsFile, int $nameStartPointer,
 		if (in_array($tokens[$previousTokenBeforeStartPointer]['code'], [T_BITWISE_OR, T_OPEN_PARENTHESIS], true)) {
 			$catchPointer = TokenHelper::findPreviousExcluding(
 				$phpcsFile,
-				array_merge([T_BITWISE_OR, T_OPEN_PARENTHESIS], $nameTokenCodes, TokenHelper::$ineffectiveTokenCodes),
-				$previousTokenBeforeStartPointer - 1
+				[T_BITWISE_OR, T_OPEN_PARENTHESIS, ...TokenHelper::NAME_TOKEN_CODES, ...TokenHelper::INEFFECTIVE_TOKEN_CODES],
+				$previousTokenBeforeStartPointer - 1,
 			);
 
 			if ($tokens[$catchPointer]['code'] === T_CATCH) {
@@ -322,7 +318,6 @@ private static function isReferencedName(File $phpcsFile, int $startPointer): bo
 
 		$skipTokenCodes = [
 			T_FUNCTION,
-			T_AS,
 			T_DOUBLE_COLON,
 			T_OBJECT_OPERATOR,
 			T_NULLSAFE_OBJECT_OPERATOR,
@@ -377,14 +372,19 @@ private static function isReferencedName(File $phpcsFile, int $startPointer): bo
 
 		$isProbablyReferencedName = !in_array(
 			$previousToken['code'],
-			array_merge($skipTokenCodes, TokenHelper::$typeKeywordTokenCodes),
-			true
+			[...$skipTokenCodes, ...TokenHelper::CLASS_TYPE_TOKEN_CODES],
+			true,
 		);
 
 		if (!$isProbablyReferencedName) {
 			return false;
 		}
 
+		if ($previousToken['code'] === T_AS && !array_key_exists('nested_parenthesis', $previousToken)) {
+			// "as" in "use" statement
+			return false;
+		}
+
 		$endPointer = self::getReferencedNameEndPointer($phpcsFile, $startPointer);
 		$referencedName = self::getReferenceName($phpcsFile, $startPointer, $endPointer);
 
@@ -411,7 +411,7 @@ private static function createAllReferencedNamesInAttributes(File $phpcsFile, in
 			$searchEndPointer = $tokens[$attributeStartPointer]['attribute_closer'];
 
 			$searchPointer = $searchStartPointer;
-			$searchTokens = array_merge(TokenHelper::getNameTokenCodes(), [T_OPEN_PARENTHESIS, T_CLOSE_PARENTHESIS]);
+			$searchTokens = [...TokenHelper::NAME_TOKEN_CODES, T_OPEN_PARENTHESIS, T_CLOSE_PARENTHESIS];
 			$level = 0;
 			do {
 				$pointer = TokenHelper::findNext($phpcsFile, $searchTokens, $searchPointer, $searchEndPointer);
@@ -453,7 +453,7 @@ private static function createAllReferencedNamesInAttributes(File $phpcsFile, in
 					$referencedName,
 					$attributeStartPointer,
 					$tokens[$attributeStartPointer]['attribute_closer'],
-					$referenceType
+					$referenceType,
 				);
 
 				$searchPointer = $referencedNameEndPointer + 1;
@@ -494,6 +494,31 @@ private static function getReferencedNamesFromString(string $content): array
 				}
 
 				$referencedNames[] = $referencedName;
+			} elseif (is_array($token) && $token[0] === T_NEW) {
+				$referencedName = '';
+				$tmpPosition = $position + 1;
+				while (true) {
+					if (!is_array($subTokens[$tmpPosition])) {
+						break;
+					}
+					if ($subTokens[$tmpPosition][0] === T_WHITESPACE) {
+						$tmpPosition++;
+						continue;
+					}
+					if (!in_array(
+						$subTokens[$tmpPosition][0],
+						[T_STRING, T_NS_SEPARATOR, T_NAME_QUALIFIED, T_NAME_FULLY_QUALIFIED, T_NAME_RELATIVE],
+						true,
+					)) {
+						break;
+					}
+
+					$referencedName .= $subTokens[$tmpPosition][1];
+					$tmpPosition++;
+				}
+				if ($referencedName !== '') {
+					$referencedNames[] = $referencedName;
+				}
 			}
 		}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ScopeHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ScopeHelper.php
index 68c65b73d..7435fec15 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ScopeHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/ScopeHelper.php
@@ -21,7 +21,7 @@ public static function isInSameScope(File $phpcsFile, int $firstPointer, int $se
 			$scope = 0;
 
 			foreach (array_reverse($tokens[$pointer]['conditions'], true) as $conditionPointer => $conditionTokenCode) {
-				if (!in_array($conditionTokenCode, TokenHelper::$functionTokenCodes, true)) {
+				if (!in_array($conditionTokenCode, TokenHelper::FUNCTION_TOKEN_CODES, true)) {
 					continue;
 				}
 
@@ -55,9 +55,7 @@ public static function getRootPointer(File $phpcsFile, int $pointer): int
 	 */
 	public static function getAllRootPointers(File $phpcsFile): array
 	{
-		$lazyValue = static function () use ($phpcsFile): array {
-			return TokenHelper::findNextAll($phpcsFile, T_OPEN_TAG, 0);
-		};
+		$lazyValue = static fn (): array => TokenHelper::findNextAll($phpcsFile, T_OPEN_TAG, 0);
 
 		return SniffLocalCache::getAndSetIfNotCached($phpcsFile, 'openTagPointers', $lazyValue);
 	}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/SniffLocalCache.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/SniffLocalCache.php
index fac1f790e..b6f0baefb 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/SniffLocalCache.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/SniffLocalCache.php
@@ -17,7 +17,7 @@ final class SniffLocalCache
 	 * @phpcsSuppress SlevomatCodingStandard.TypeHints.DisallowMixedTypeHint
 	 * @var array>
 	 */
-	private static $cache = [];
+	private static array $cache = [];
 
 	/**
 	 * @phpcsSuppress SlevomatCodingStandard.TypeHints.DisallowMixedTypeHint
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/SniffSettingsHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/SniffSettingsHelper.php
index ade9c26ce..eb15511fb 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/SniffSettingsHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/SniffSettingsHelper.php
@@ -39,12 +39,8 @@ public static function normalizeNullableInteger($settings): ?int
 	 */
 	public static function normalizeArray(array $settings): array
 	{
-		$settings = array_map(static function (string $value): string {
-			return trim($value);
-		}, $settings);
-		$settings = array_filter($settings, static function (string $value): bool {
-			return $value !== '';
-		});
+		$settings = array_map(static fn (string $value): string => trim($value), $settings);
+		$settings = array_filter($settings, static fn (string $value): bool => $value !== '');
 		return array_values($settings);
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/SuppressHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/SuppressHelper.php
index 96b1d2c04..6ececcf4c 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/SuppressHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/SuppressHelper.php
@@ -40,7 +40,7 @@ static function (bool $carry, Annotation $annotation) use ($suppressName): bool
 
 				return $carry;
 			},
-			false
+			false,
 		);
 	}
 
@@ -63,7 +63,7 @@ public static function removeSuppressAnnotation(File $phpcsFile, int $pointer, s
 		$pointerBefore = TokenHelper::findPrevious(
 			$phpcsFile,
 			[T_DOC_COMMENT_OPEN_TAG, T_DOC_COMMENT_STAR],
-			$suppressAnnotation->getStartPointer() - 1
+			$suppressAnnotation->getStartPointer() - 1,
 		);
 
 		$changeStart = $tokens[$pointerBefore]['code'] === T_DOC_COMMENT_STAR ? $pointerBefore : $suppressAnnotation->getStartPointer();
@@ -72,7 +72,7 @@ public static function removeSuppressAnnotation(File $phpcsFile, int $pointer, s
 		$changeEnd = TokenHelper::findNext(
 			$phpcsFile,
 			[T_DOC_COMMENT_CLOSE_TAG, T_DOC_COMMENT_STAR],
-			$suppressAnnotation->getEndPointer() + 1
+			$suppressAnnotation->getEndPointer() + 1,
 		) - 1;
 
 		$phpcsFile->fixer->beginChangeset();
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/TernaryOperatorHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/TernaryOperatorHelper.php
index ce1f675f3..a404995cc 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/TernaryOperatorHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/TernaryOperatorHelper.php
@@ -53,7 +53,7 @@ public static function getElsePointer(File $phpcsFile, int $inlineThenPointer):
 			$pointer = TokenHelper::findNext(
 				$phpcsFile,
 				[T_INLINE_ELSE, T_OPEN_PARENTHESIS, T_OPEN_SHORT_ARRAY, T_OPEN_SQUARE_BRACKET],
-				$pointer + 1
+				$pointer + 1,
 			);
 
 			if ($tokens[$pointer]['code'] === T_OPEN_PARENTHESIS) {
@@ -83,7 +83,7 @@ public static function getStartPointer(File $phpcsFile, int $inlineThenPointer):
 			$pointerBeforeCondition = TokenHelper::findPrevious(
 				$phpcsFile,
 				[T_EQUAL, T_DOUBLE_ARROW, T_COMMA, T_RETURN, T_THROW, T_CASE, T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO, T_OPEN_SQUARE_BRACKET, T_OPEN_SHORT_ARRAY, T_OPEN_PARENTHESIS],
-				$pointerBeforeCondition - 1
+				$pointerBeforeCondition - 1,
 			);
 
 			if (
@@ -116,7 +116,7 @@ public static function getEndPointer(File $phpcsFile, int $inlineThenPointer, in
 			$pointerAfterInlineElseEnd = TokenHelper::findNext(
 				$phpcsFile,
 				[T_SEMICOLON, T_COLON, T_COMMA, T_DOUBLE_ARROW, T_CLOSE_PARENTHESIS, T_CLOSE_SHORT_ARRAY, T_CLOSE_SQUARE_BRACKET, T_COALESCE],
-				$pointerAfterInlineElseEnd + 1
+				$pointerAfterInlineElseEnd + 1,
 			);
 
 			if ($pointerAfterInlineElseEnd === null) {
@@ -136,7 +136,7 @@ public static function getEndPointer(File $phpcsFile, int $inlineThenPointer, in
 					$phpcsFile,
 					[T_OPEN_PARENTHESIS, T_OPEN_SHORT_ARRAY],
 					$pointerAfterInlineElseEnd - 1,
-					$inlineThenPointer
+					$inlineThenPointer,
 				);
 
 				if ($previousPointer === null) {
@@ -162,7 +162,7 @@ public static function getEndPointer(File $phpcsFile, int $inlineThenPointer, in
 					$phpcsFile,
 					T_OPEN_SHORT_ARRAY,
 					$pointerAfterInlineElseEnd - 1,
-					$inlineThenPointer
+					$inlineThenPointer,
 				);
 				if ($previousPointer === null) {
 					break;
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/TokenHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/TokenHelper.php
index fc4119d94..c09892f1e 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/TokenHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/TokenHelper.php
@@ -4,10 +4,10 @@
 
 use PHP_CodeSniffer\Files\File;
 use function array_key_exists;
-use function array_merge;
 use function count;
+use const T_ABSTRACT;
+use const T_ANON_CLASS;
 use const T_ARRAY;
-use const T_ARRAY_HINT;
 use const T_BREAK;
 use const T_CALLABLE;
 use const T_CLASS;
@@ -24,6 +24,7 @@
 use const T_ENUM;
 use const T_EXIT;
 use const T_FALSE;
+use const T_FINAL;
 use const T_FN;
 use const T_FUNCTION;
 use const T_INTERFACE;
@@ -40,8 +41,11 @@
 use const T_PHPCS_IGNORE_FILE;
 use const T_PHPCS_SET;
 use const T_PRIVATE;
+use const T_PRIVATE_SET;
 use const T_PROTECTED;
+use const T_PROTECTED_SET;
 use const T_PUBLIC;
+use const T_PUBLIC_SET;
 use const T_READONLY;
 use const T_RETURN;
 use const T_SELF;
@@ -50,7 +54,9 @@
 use const T_THROW;
 use const T_TRAIT;
 use const T_TRUE;
+use const T_TYPE_CLOSE_PARENTHESIS;
 use const T_TYPE_INTERSECTION;
+use const T_TYPE_OPEN_PARENTHESIS;
 use const T_TYPE_UNION;
 use const T_VAR;
 use const T_WHITESPACE;
@@ -61,40 +67,70 @@
 class TokenHelper
 {
 
-	/** @var array */
-	public static $arrayTokenCodes = [
+	public const ONLY_NAME_TOKEN_CODES = [
+		T_STRING,
+		T_NAME_FULLY_QUALIFIED,
+		T_NAME_QUALIFIED,
+		T_NAME_RELATIVE,
+	];
+
+	public const NAME_TOKEN_CODES = [
+		...self::ONLY_NAME_TOKEN_CODES,
+		T_NS_SEPARATOR,
+	];
+
+	public const ONLY_TYPE_HINT_TOKEN_CODES = [
+		...self::NAME_TOKEN_CODES,
+		T_SELF,
+		T_PARENT,
+		T_CALLABLE,
+		T_FALSE,
+		T_TRUE,
+		T_NULL,
+	];
+
+	public const TYPE_HINT_TOKEN_CODES = [
+		...self::ONLY_TYPE_HINT_TOKEN_CODES,
+		T_TYPE_UNION,
+		T_TYPE_INTERSECTION,
+		T_TYPE_OPEN_PARENTHESIS,
+		T_TYPE_CLOSE_PARENTHESIS,
+	];
+
+	public const MODIFIERS_TOKEN_CODES = [
+		T_FINAL,
+		T_ABSTRACT,
+		T_VAR,
+		T_PUBLIC,
+		T_PUBLIC_SET,
+		T_PROTECTED,
+		T_PROTECTED_SET,
+		T_PRIVATE,
+		T_PRIVATE_SET,
+		T_READONLY,
+		T_STATIC,
+	];
+
+	public const PROPERTY_MODIFIERS_TOKEN_CODES = self::MODIFIERS_TOKEN_CODES;
+
+	public const ARRAY_TOKEN_CODES = [
 		T_ARRAY,
 		T_OPEN_SHORT_ARRAY,
 	];
 
-	/** @var array */
-	public static $typeKeywordTokenCodes = [
+	public const CLASS_TYPE_TOKEN_CODES = [
 		T_CLASS,
 		T_TRAIT,
 		T_INTERFACE,
 		T_ENUM,
 	];
 
-	/** @var array */
-	public static $ineffectiveTokenCodes = [
-		T_WHITESPACE,
-		T_COMMENT,
-		T_DOC_COMMENT,
-		T_DOC_COMMENT_OPEN_TAG,
-		T_DOC_COMMENT_CLOSE_TAG,
-		T_DOC_COMMENT_STAR,
-		T_DOC_COMMENT_STRING,
-		T_DOC_COMMENT_TAG,
-		T_DOC_COMMENT_WHITESPACE,
-		T_PHPCS_DISABLE,
-		T_PHPCS_ENABLE,
-		T_PHPCS_IGNORE,
-		T_PHPCS_IGNORE_FILE,
-		T_PHPCS_SET,
+	public const CLASS_TYPE_WITH_ANONYMOUS_CLASS_TOKEN_CODES = [
+		...self::CLASS_TYPE_TOKEN_CODES,
+		T_ANON_CLASS,
 	];
 
-	/** @var array */
-	public static $annotationTokenCodes = [
+	public const ANNOTATION_TOKEN_CODES = [
 		T_DOC_COMMENT_TAG,
 		T_PHPCS_DISABLE,
 		T_PHPCS_ENABLE,
@@ -103,8 +139,7 @@ class TokenHelper
 		T_PHPCS_SET,
 	];
 
-	/** @var array */
-	public static $inlineCommentTokenCodes = [
+	public const INLINE_COMMENT_TOKEN_CODES = [
 		T_COMMENT,
 		T_PHPCS_DISABLE,
 		T_PHPCS_ENABLE,
@@ -113,8 +148,19 @@ class TokenHelper
 		T_PHPCS_SET,
 	];
 
-	/** @var array */
-	public static $earlyExitTokenCodes = [
+	public const INEFFECTIVE_TOKEN_CODES = [
+		T_WHITESPACE,
+		T_DOC_COMMENT,
+		T_DOC_COMMENT_OPEN_TAG,
+		T_DOC_COMMENT_CLOSE_TAG,
+		T_DOC_COMMENT_STAR,
+		T_DOC_COMMENT_STRING,
+		T_DOC_COMMENT_TAG,
+		T_DOC_COMMENT_WHITESPACE,
+		...self::INLINE_COMMENT_TOKEN_CODES,
+	];
+
+	public const EARLY_EXIT_TOKEN_CODES = [
 		T_RETURN,
 		T_CONTINUE,
 		T_BREAK,
@@ -122,23 +168,12 @@ class TokenHelper
 		T_EXIT,
 	];
 
-	/** @var array */
-	public static $functionTokenCodes = [
+	public const FUNCTION_TOKEN_CODES = [
 		T_FUNCTION,
 		T_CLOSURE,
 		T_FN,
 	];
 
-	/** @var array */
-	public static $propertyModifiersTokenCodes = [
-		T_VAR,
-		T_PUBLIC,
-		T_PROTECTED,
-		T_PRIVATE,
-		T_READONLY,
-		T_STATIC,
-	];
-
 	/**
 	 * @param int|string|array $types
 	 */
@@ -187,7 +222,7 @@ public static function findNextContent(File $phpcsFile, $types, string $content,
 	 */
 	public static function findNextEffective(File $phpcsFile, int $startPointer, ?int $endPointer = null): ?int
 	{
-		return self::findNextExcluding($phpcsFile, self::$ineffectiveTokenCodes, $startPointer, $endPointer);
+		return self::findNextExcluding($phpcsFile, self::INEFFECTIVE_TOKEN_CODES, $startPointer, $endPointer);
 	}
 
 	/**
@@ -258,7 +293,7 @@ public static function findPreviousContent(File $phpcsFile, $types, string $cont
 	 */
 	public static function findPreviousEffective(File $phpcsFile, int $startPointer, ?int $endPointer = null): ?int
 	{
-		return self::findPreviousExcluding($phpcsFile, self::$ineffectiveTokenCodes, $startPointer, $endPointer);
+		return self::findPreviousExcluding($phpcsFile, self::INEFFECTIVE_TOKEN_CODES, $startPointer, $endPointer);
 	}
 
 	/**
@@ -415,7 +450,7 @@ public static function findFirstNonWhitespaceOnPreviousLine(File $phpcsFile, int
 			$phpcsFile,
 			[T_WHITESPACE, T_DOC_COMMENT_WHITESPACE],
 			$phpcsFile->eolChar,
-			$pointer
+			$pointer,
 		);
 		if ($newLinePointerOnPreviousLine === null) {
 			return null;
@@ -425,7 +460,7 @@ public static function findFirstNonWhitespaceOnPreviousLine(File $phpcsFile, int
 			$phpcsFile,
 			[T_WHITESPACE, T_DOC_COMMENT_WHITESPACE],
 			$phpcsFile->eolChar,
-			$newLinePointerOnPreviousLine - 1
+			$newLinePointerOnPreviousLine - 1,
 		);
 		if ($newLinePointerBeforePreviousLine === null) {
 			return null;
@@ -463,62 +498,4 @@ public static function getLastTokenPointer(File $phpcsFile): int
 		return $tokenCount - 1;
 	}
 
-	/**
-	 * @return array
-	 */
-	public static function getNameTokenCodes(): array
-	{
-		return [T_STRING, T_NS_SEPARATOR, T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, T_NAME_RELATIVE];
-	}
-
-	/**
-	 * @return array
-	 */
-	public static function getOnlyNameTokenCodes(): array
-	{
-		return [T_STRING, T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED, T_NAME_RELATIVE];
-	}
-
-	/**
-	 * @return array
-	 */
-	public static function getOnlyTypeHintTokenCodes(): array
-	{
-		static $typeHintTokenCodes = null;
-
-		if ($typeHintTokenCodes === null) {
-			$typeHintTokenCodes = array_merge(
-				self::getNameTokenCodes(),
-				[
-					T_SELF,
-					T_PARENT,
-					T_ARRAY_HINT,
-					T_CALLABLE,
-					T_FALSE,
-					T_TRUE,
-					T_NULL,
-				]
-			);
-		}
-
-		return $typeHintTokenCodes;
-	}
-
-	/**
-	 * @return array
-	 */
-	public static function getTypeHintTokenCodes(): array
-	{
-		static $typeHintTokenCodes = null;
-
-		if ($typeHintTokenCodes === null) {
-			$typeHintTokenCodes = array_merge(
-				self::getOnlyTypeHintTokenCodes(),
-				[T_TYPE_UNION, T_TYPE_INTERSECTION]
-			);
-		}
-
-		return $typeHintTokenCodes;
-	}
-
 }
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/TokenPointerOutOfBoundsException.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/TokenPointerOutOfBoundsException.php
index 32ff5368f..4ee16dc86 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/TokenPointerOutOfBoundsException.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/TokenPointerOutOfBoundsException.php
@@ -12,11 +12,9 @@
 class TokenPointerOutOfBoundsException extends Exception
 {
 
-	/** @var int */
-	private $pointer;
+	private int $pointer;
 
-	/** @var int */
-	private $lastTokenPointer;
+	private int $lastTokenPointer;
 
 	public function __construct(int $pointer, int $lastTokenPointer, ?Throwable $previous = null)
 	{
@@ -24,10 +22,10 @@ public function __construct(int $pointer, int $lastTokenPointer, ?Throwable $pre
 			sprintf(
 				'Attempted access to token pointer %d, last token pointer is %d',
 				$pointer,
-				$lastTokenPointer
+				$lastTokenPointer,
 			),
 			0,
-			$previous
+			$previous,
 		);
 
 		$this->pointer = $pointer;
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/TypeHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/TypeHelper.php
index 8539c98d8..f6b620c14 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/TypeHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/TypeHelper.php
@@ -21,7 +21,7 @@ public static function isTypeName(string $typeName): bool
 	{
 		$result = preg_match(
 			'~^\\\\?([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)(\\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*$~',
-			$typeName
+			$typeName,
 		);
 		if ($result === false) {
 			// @codeCoverageIgnoreStart
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/TypeHint.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/TypeHint.php
index 7bd8fcc21..c97555b0f 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/TypeHint.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/TypeHint.php
@@ -11,17 +11,13 @@
 class TypeHint
 {
 
-	/** @var string */
-	private $typeHint;
+	private string $typeHint;
 
-	/** @var bool */
-	private $nullable;
+	private bool $nullable;
 
-	/** @var int */
-	private $startPointer;
+	private int $startPointer;
 
-	/** @var int */
-	private $endPointer;
+	private int $endPointer;
 
 	public function __construct(string $typeHint, bool $nullable, int $startPointer, int $endPointer)
 	{
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/TypeHintHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/TypeHintHelper.php
index abde19b64..1f276b0a6 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/TypeHintHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/TypeHintHelper.php
@@ -238,7 +238,7 @@ public static function typeHintEqualsAnnotation(
 			if (self::getFullyQualifiedTypeHint($phpcsFile, $functionPointer, $typeHintParts[$i]) !== self::getFullyQualifiedTypeHint(
 				$phpcsFile,
 				$functionPointer,
-				$typeHintInAnnotationParts[$i]
+				$typeHintInAnnotationParts[$i],
 			)) {
 				return false;
 			}
@@ -251,8 +251,8 @@ public static function getStartPointer(File $phpcsFile, int $endPointer): int
 	{
 		$previousPointer = TokenHelper::findPreviousExcluding(
 			$phpcsFile,
-			array_merge([T_WHITESPACE], TokenHelper::getTypeHintTokenCodes()),
-			$endPointer - 1
+			[T_WHITESPACE, ...TokenHelper::TYPE_HINT_TOKEN_CODES],
+			$endPointer - 1,
 		);
 		return TokenHelper::findNextNonWhitespace($phpcsFile, $previousPointer + 1);
 	}
@@ -292,7 +292,7 @@ private static function isTemplate(File $phpcsFile, int $docCommentOpenPointer,
 
 		$docCommentOwnerPointer = DocCommentHelper::findDocCommentOwnerPointer($phpcsFile, $docCommentOpenPointer);
 		if ($docCommentOwnerPointer !== null) {
-			if (in_array($tokens[$docCommentOwnerPointer]['code'], TokenHelper::$typeKeywordTokenCodes, true)) {
+			if (in_array($tokens[$docCommentOwnerPointer]['code'], TokenHelper::CLASS_TYPE_TOKEN_CODES, true)) {
 				return $containsTypeHintInTemplateAnnotation($docCommentOpenPointer);
 			}
 
@@ -404,9 +404,7 @@ private static function normalize(string $typeHint): string
 		$convertedHints = array_unique($convertedHints);
 
 		if (count($convertedHints) > 1) {
-			$convertedHints = array_map(static function (string $part): string {
-				return self::isVoidTypeHint($part) ? 'null' : $part;
-			}, $convertedHints);
+			$convertedHints = array_map(static fn (string $part): string => self::isVoidTypeHint($part) ? 'null' : $part, $convertedHints);
 		}
 
 		sort($convertedHints);
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/UseStatement.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/UseStatement.php
index fb5eb5150..6e2563332 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/UseStatement.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/UseStatement.php
@@ -15,23 +15,17 @@ class UseStatement
 	public const TYPE_FUNCTION = ReferencedName::TYPE_FUNCTION;
 	public const TYPE_CONSTANT = ReferencedName::TYPE_CONSTANT;
 
-	/** @var string */
-	private $nameAsReferencedInFile;
+	private string $nameAsReferencedInFile;
 
-	/** @var string */
-	private $normalizedNameAsReferencedInFile;
+	private string $normalizedNameAsReferencedInFile;
 
-	/** @var string */
-	private $fullyQualifiedTypeName;
+	private string $fullyQualifiedTypeName;
 
-	/** @var int */
-	private $usePointer;
+	private int $usePointer;
 
-	/** @var string */
-	private $type;
+	private string $type;
 
-	/** @var string|null */
-	private $alias;
+	private ?string $alias = null;
 
 	public function __construct(
 		string $nameAsReferencedInFile,
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/UseStatementHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/UseStatementHelper.php
index bc6fdd1fd..d99ed5ea7 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/UseStatementHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/UseStatementHelper.php
@@ -3,15 +3,19 @@
 namespace SlevomatCodingStandard\Helpers;
 
 use PHP_CodeSniffer\Files\File;
-use function array_merge;
+use function array_key_exists;
 use function array_reverse;
 use function count;
 use function current;
 use function in_array;
-use const T_ANON_CLASS;
+use function strtolower;
 use const T_AS;
+use const T_CLOSE_CURLY_BRACKET;
 use const T_COMMA;
+use const T_DECLARE;
+use const T_FUNCTION;
 use const T_NAMESPACE;
+use const T_OPEN_CURLY_BRACKET;
 use const T_OPEN_PARENTHESIS;
 use const T_OPEN_TAG;
 use const T_OPEN_USE_GROUP;
@@ -25,29 +29,68 @@
 class UseStatementHelper
 {
 
-	public static function isAnonymousFunctionUse(File $phpcsFile, int $usePointer): bool
+	public static function isImportUse(File $phpcsFile, int $usePointer): bool
 	{
 		$tokens = $phpcsFile->getTokens();
 		$nextPointer = TokenHelper::findNextEffective($phpcsFile, $usePointer + 1);
-		$nextToken = $tokens[$nextPointer];
 
-		return $nextToken['code'] === T_OPEN_PARENTHESIS;
+		// Anonymous function use
+		if ($tokens[$nextPointer]['code'] === T_OPEN_PARENTHESIS) {
+			return false;
+		}
+
+		if (
+			$tokens[$nextPointer]['code'] === T_STRING
+			&& in_array(strtolower($tokens[$nextPointer]['content']), ['function', 'const'], true)
+		) {
+			return true;
+		}
+
+		$previousPointer = TokenHelper::findPrevious(
+			$phpcsFile,
+			[T_OPEN_TAG, T_DECLARE, T_NAMESPACE, T_OPEN_CURLY_BRACKET, T_CLOSE_CURLY_BRACKET],
+			$usePointer,
+		);
+
+		if (in_array($tokens[$previousPointer]['code'], [T_OPEN_TAG, T_DECLARE, T_NAMESPACE], true)) {
+			return true;
+		}
+
+		if (array_key_exists('scope_condition', $tokens[$previousPointer])) {
+			$scopeConditionPointer = $tokens[$previousPointer]['scope_condition'];
+
+			if (
+				$tokens[$previousPointer]['code'] === T_OPEN_CURLY_BRACKET
+				&& in_array($tokens[$scopeConditionPointer]['code'], TokenHelper::CLASS_TYPE_WITH_ANONYMOUS_CLASS_TOKEN_CODES, true)
+			) {
+				return false;
+			}
+
+			// Trait use after another trait use
+			if ($tokens[$scopeConditionPointer]['code'] === T_USE) {
+				return false;
+			}
+
+			// Trait use after method or import use after function
+			if ($tokens[$scopeConditionPointer]['code'] === T_FUNCTION) {
+				return ClassHelper::getClassPointer($phpcsFile, $usePointer) === null;
+			}
+		}
+
+		return true;
 	}
 
 	public static function isTraitUse(File $phpcsFile, int $usePointer): bool
 	{
-		$typePointer = TokenHelper::findPrevious($phpcsFile, array_merge(TokenHelper::$typeKeywordTokenCodes, [T_ANON_CLASS]), $usePointer);
-		if ($typePointer !== null) {
-			$tokens = $phpcsFile->getTokens();
-			$typeToken = $tokens[$typePointer];
-			$openerPointer = $typeToken['scope_opener'];
-			$closerPointer = $typeToken['scope_closer'];
+		$tokens = $phpcsFile->getTokens();
+		$nextPointer = TokenHelper::findNextEffective($phpcsFile, $usePointer + 1);
 
-			return $usePointer > $openerPointer && $usePointer < $closerPointer
-				&& !self::isAnonymousFunctionUse($phpcsFile, $usePointer);
+		// Anonymous function use
+		if ($tokens[$nextPointer]['code'] === T_OPEN_PARENTHESIS) {
+			return false;
 		}
 
-		return false;
+		return !self::isImportUse($phpcsFile, $usePointer);
 	}
 
 	public static function getAlias(File $phpcsFile, int $usePointer): ?string
@@ -79,10 +122,10 @@ public static function getFullyQualifiedTypeNameFromUse(File $phpcsFile, int $us
 		$tokens = $phpcsFile->getTokens();
 
 		$nameEndPointer = TokenHelper::findNext($phpcsFile, [T_SEMICOLON, T_AS, T_COMMA], $usePointer + 1) - 1;
-		if (in_array($tokens[$nameEndPointer]['code'], TokenHelper::$ineffectiveTokenCodes, true)) {
+		if (in_array($tokens[$nameEndPointer]['code'], TokenHelper::INEFFECTIVE_TOKEN_CODES, true)) {
 			$nameEndPointer = TokenHelper::findPreviousEffective($phpcsFile, $nameEndPointer);
 		}
-		$nameStartPointer = TokenHelper::findPreviousExcluding($phpcsFile, TokenHelper::getNameTokenCodes(), $nameEndPointer - 1) + 1;
+		$nameStartPointer = TokenHelper::findPreviousExcluding($phpcsFile, TokenHelper::NAME_TOKEN_CODES, $nameEndPointer - 1) + 1;
 
 		$name = TokenHelper::getContent($phpcsFile, $nameStartPointer, $nameEndPointer);
 
@@ -147,7 +190,7 @@ public static function getFileUseStatements(File $phpcsFile): array
 					self::getFullyQualifiedTypeNameFromUse($phpcsFile, $usePointer),
 					$usePointer,
 					$type,
-					self::getAlias($phpcsFile, $usePointer)
+					self::getAlias($phpcsFile, $usePointer),
 				);
 				$useStatements[$pointerBeforeUseStatements][UseStatement::getUniqueId($type, $name)] = $useStatement;
 			}
@@ -183,14 +226,13 @@ private static function getUseStatementPointers(File $phpcsFile, int $openTagPoi
 			$pointer = $openTagPointer + 1;
 			$pointers = [];
 			while (true) {
-				$typesToFind = array_merge([T_USE], TokenHelper::$typeKeywordTokenCodes);
-				$pointer = TokenHelper::findNext($phpcsFile, $typesToFind, $pointer);
+				$pointer = TokenHelper::findNext($phpcsFile, [T_USE, ...TokenHelper::CLASS_TYPE_TOKEN_CODES], $pointer);
 				if ($pointer === null) {
 					break;
 				}
 
 				$token = $tokens[$pointer];
-				if (in_array($token['code'], TokenHelper::$typeKeywordTokenCodes, true)) {
+				if (in_array($token['code'], TokenHelper::CLASS_TYPE_TOKEN_CODES, true)) {
 					$pointer = $token['scope_closer'] + 1;
 					continue;
 				}
@@ -200,7 +242,7 @@ private static function getUseStatementPointers(File $phpcsFile, int $openTagPoi
 					continue;
 				}
 
-				if (self::isAnonymousFunctionUse($phpcsFile, $pointer)) {
+				if (!self::isImportUse($phpcsFile, $pointer)) {
 					$pointer++;
 					continue;
 				}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/VariableHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/VariableHelper.php
index 676b0ab7a..4f9770ea7 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/VariableHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/VariableHelper.php
@@ -86,11 +86,12 @@ public static function isUsedInScopeInString(File $phpcsFile, string $variableNa
 
 		$stringContent = $tokens[$stringPointer]['content'];
 
-		if (preg_match('~(\\\\)?(' . preg_quote($variableName, '~') . ')\b~', $stringContent, $matches) !== 0) {
+		if (preg_match('~(\\\\)?(' . preg_quote($variableName, '~') . ')\b~', $stringContent, $matches) === 1) {
 			if ($matches[1] === '') {
 				return true;
 			}
 
+			/** @phpstan-ignore-next-line */
 			if (strlen($matches[1]) % 2 === 1) {
 				return true;
 			}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/YodaHelper.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/YodaHelper.php
index 9b0c3ad97..b576b60bc 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/YodaHelper.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Helpers/YodaHelper.php
@@ -23,7 +23,6 @@
 use const T_BOOLEAN_AND;
 use const T_BOOLEAN_OR;
 use const T_CASE;
-use const T_CLOSE_CURLY_BRACKET;
 use const T_CLOSE_PARENTHESIS;
 use const T_CLOSE_SHORT_ARRAY;
 use const T_COALESCE;
@@ -184,13 +183,11 @@ public static function getRightSideTokens(array $tokens, int $comparisonTokenPoi
 	 */
 	public static function getDynamismForTokens(array $tokens, array $sideTokens): ?int
 	{
-		$sideTokens = array_values(array_filter($sideTokens, static function (array $token): bool {
-			return !in_array(
-				$token['code'],
-				[T_WHITESPACE, T_COMMENT, T_DOC_COMMENT, T_NS_SEPARATOR, T_PLUS, T_MINUS, T_INT_CAST, T_DOUBLE_CAST, T_STRING_CAST, T_ARRAY_CAST, T_OBJECT_CAST, T_BOOL_CAST, T_UNSET_CAST],
-				true
-			);
-		}));
+		$sideTokens = array_values(array_filter($sideTokens, static fn (array $token): bool => !in_array(
+			$token['code'],
+			[T_WHITESPACE, T_COMMENT, T_DOC_COMMENT, T_NS_SEPARATOR, T_PLUS, T_MINUS, T_INT_CAST, T_DOUBLE_CAST, T_STRING_CAST, T_ARRAY_CAST, T_OBJECT_CAST, T_BOOL_CAST, T_UNSET_CAST],
+			true,
+		)));
 
 		$sideTokensCount = count($sideTokens);
 
@@ -235,8 +232,8 @@ public static function getDynamismForTokens(array $tokens, array $sideTokens): ?
 		}
 
 		if (array_key_exists(0, $sideTokens)) {
-			/** @var int $sideTokenCode */
 			$sideTokenCode = $sideTokens[0]['code'];
+			/** @phpstan-ignore argument.type */
 			if (array_key_exists($sideTokenCode, $dynamism)) {
 				return $dynamism[$sideTokenCode];
 			}
@@ -343,7 +340,6 @@ private static function getStopTokenCodes(): array
 				T_COLON => true,
 				T_RETURN => true,
 				T_COMMA => true,
-				T_CLOSE_CURLY_BRACKET => true,
 				T_MATCH_ARROW => true,
 				T_FN_ARROW => true,
 			];
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/AlphabeticallySortedByKeysSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/AlphabeticallySortedByKeysSniff.php
index 27f47b01a..dd60e04d9 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/AlphabeticallySortedByKeysSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/AlphabeticallySortedByKeysSniff.php
@@ -24,7 +24,7 @@ class AlphabeticallySortedByKeysSniff implements Sniff
 	 */
 	public function register(): array
 	{
-		return TokenHelper::$arrayTokenCodes;
+		return TokenHelper::ARRAY_TOKEN_CODES;
 	}
 
 	/**
@@ -51,7 +51,7 @@ public function process(File $phpcsFile, $stackPointer): void
 		$fix = $phpcsFile->addFixableError(
 			'Keyed multi-line arrays must be sorted alphabetically.',
 			$stackPointer,
-			self::CODE_INCORRECT_KEY_ORDER
+			self::CODE_INCORRECT_KEY_ORDER,
 		);
 		if ($fix) {
 			$this->fix($phpcsFile, $keyValues);
@@ -66,16 +66,18 @@ private function fix(File $phpcsFile, array $keyValues): void
 		$pointerStart = $keyValues[0]->getPointerStart();
 		$pointerEnd = $keyValues[count($keyValues) - 1]->getPointerEnd();
 
-		// determine indent to use
+		// Determine indent to use
 		$indent = ArrayHelper::getIndentation($keyValues);
 
-		usort($keyValues, static function ($a1, $a2) {
-			return strnatcasecmp((string) $a1->getKey(), (string) $a2->getKey());
-		});
+		usort($keyValues, static fn ($a1, $a2) => strnatcasecmp((string) $a1->getKey(), (string) $a2->getKey()));
 
-		$content = implode('', array_map(static function (ArrayKeyValue $keyValue) use ($phpcsFile, $indent) {
-			return $keyValue->getContent($phpcsFile, true, $indent) . $phpcsFile->eolChar;
-		}, $keyValues));
+		$content = implode(
+			'',
+			array_map(
+				static fn (ArrayKeyValue $keyValue) => $keyValue->getContent($phpcsFile, true, $indent) . $phpcsFile->eolChar,
+				$keyValues,
+			),
+		);
 
 		$phpcsFile->fixer->beginChangeset();
 		FixerHelper::change($phpcsFile, $pointerStart, $pointerEnd, $content);
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/ArrayAccessSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/ArrayAccessSniff.php
index e5d9ffaaa..2a250146c 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/ArrayAccessSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/ArrayAccessSniff.php
@@ -4,6 +4,7 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use const T_CLOSE_SQUARE_BRACKET;
 use const T_OPEN_SQUARE_BRACKET;
@@ -44,7 +45,7 @@ public function process(File $phpcsFile, $stackPointer): void
 				$phpcsFile,
 				$stackPointer,
 				'There should be no space between array variable and array access operator.',
-				self::CODE_NO_SPACE_BEFORE_BRACKETS
+				self::CODE_NO_SPACE_BEFORE_BRACKETS,
 			);
 		}
 
@@ -56,7 +57,7 @@ public function process(File $phpcsFile, $stackPointer): void
 			$phpcsFile,
 			$stackPointer,
 			'There should be no space between array access operators.',
-			self::CODE_NO_SPACE_BETWEEN_BRACKETS
+			self::CODE_NO_SPACE_BETWEEN_BRACKETS,
 		);
 	}
 
@@ -69,7 +70,7 @@ private function addError(File $phpcsFile, int $stackPointer, string $error, str
 		}
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->replaceToken($stackPointer - 1, '');
+		FixerHelper::replace($phpcsFile, $stackPointer - 1, '');
 		$phpcsFile->fixer->endChangeset();
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/DisallowImplicitArrayCreationSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/DisallowImplicitArrayCreationSniff.php
index 59997e616..e66eb223c 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/DisallowImplicitArrayCreationSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/DisallowImplicitArrayCreationSniff.php
@@ -84,7 +84,7 @@ public function process(File $phpcsFile, $bracketOpenerPointer): void
 
 		$scopeOwnerPointer = null;
 		foreach (array_reverse($tokens[$variablePointer]['conditions'], true) as $conditionPointer => $conditionTokenCode) {
-			if (!in_array($conditionTokenCode, TokenHelper::$functionTokenCodes, true)) {
+			if (!in_array($conditionTokenCode, TokenHelper::FUNCTION_TOKEN_CODES, true)) {
 				continue;
 			}
 
@@ -103,7 +103,7 @@ public function process(File $phpcsFile, $bracketOpenerPointer): void
 			? count($tokens) - 1
 			: $tokens[$scopeOwnerPointer]['scope_closer'];
 
-		if (in_array($tokens[$scopeOwnerPointer]['code'], TokenHelper::$functionTokenCodes, true)) {
+		if (in_array($tokens[$scopeOwnerPointer]['code'], TokenHelper::FUNCTION_TOKEN_CODES, true)) {
 			if ($this->isParameter($phpcsFile, $scopeOwnerPointer, $variablePointer)) {
 				return;
 			}
@@ -133,7 +133,7 @@ private function isParameter(File $phpcsFile, int $functionPointer, int $variabl
 			T_VARIABLE,
 			$variableName,
 			$tokens[$functionPointer]['parenthesis_opener'] + 1,
-			$tokens[$functionPointer]['parenthesis_closer']
+			$tokens[$functionPointer]['parenthesis_closer'],
 		);
 		return $parameterPointer !== null;
 	}
@@ -147,7 +147,7 @@ private function isInheritedVariable(File $phpcsFile, int $closurePointer, int $
 			$phpcsFile,
 			T_USE,
 			$tokens[$closurePointer]['parenthesis_closer'] + 1,
-			$tokens[$closurePointer]['scope_opener']
+			$tokens[$closurePointer]['scope_opener'],
 		);
 		if ($usePointer === null) {
 			return false;
@@ -160,7 +160,7 @@ private function isInheritedVariable(File $phpcsFile, int $closurePointer, int $
 			T_VARIABLE,
 			$variableName,
 			$parenthesisOpenerPointer + 1,
-			$tokens[$parenthesisOpenerPointer]['parenthesis_closer']
+			$tokens[$parenthesisOpenerPointer]['parenthesis_closer'],
 		);
 		return $inheritedVariablePointer !== null;
 	}
@@ -222,7 +222,7 @@ private function isCreatedInList(File $phpcsFile, int $variablePointer, int $sco
 			$phpcsFile,
 			[T_OPEN_PARENTHESIS, T_OPEN_SHORT_ARRAY, T_OPEN_SQUARE_BRACKET],
 			$variablePointer - 1,
-			$scopeOpenerPointer
+			$scopeOpenerPointer,
 		);
 		if ($parenthesisOpenerPointer === null) {
 			return false;
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/DisallowPartiallyKeyedSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/DisallowPartiallyKeyedSniff.php
index 28af0d876..e6bfc28a5 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/DisallowPartiallyKeyedSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/DisallowPartiallyKeyedSniff.php
@@ -17,7 +17,7 @@ class DisallowPartiallyKeyedSniff implements Sniff
 	 */
 	public function register(): array
 	{
-		return TokenHelper::$arrayTokenCodes;
+		return TokenHelper::ARRAY_TOKEN_CODES;
 	}
 
 	/**
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/MultiLineArrayEndBracketPlacementSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/MultiLineArrayEndBracketPlacementSniff.php
index 46980e91a..870df29ee 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/MultiLineArrayEndBracketPlacementSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/MultiLineArrayEndBracketPlacementSniff.php
@@ -5,6 +5,7 @@
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
 use SlevomatCodingStandard\Helpers\ArrayHelper;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use function in_array;
 
@@ -18,7 +19,7 @@ class MultiLineArrayEndBracketPlacementSniff implements Sniff
 	 */
 	public function register(): array
 	{
-		return TokenHelper::$arrayTokenCodes;
+		return TokenHelper::ARRAY_TOKEN_CODES;
 	}
 
 	/**
@@ -36,7 +37,7 @@ public function process(File $phpcsFile, $stackPointer): void
 		[$arrayOpenerPointer, $arrayCloserPointer] = ArrayHelper::openClosePointers($tokens[$stackPointer]);
 
 		$nextEffective = TokenHelper::findNextEffective($phpcsFile, $arrayOpenerPointer + 1, $arrayCloserPointer);
-		if ($nextEffective === null || in_array($tokens[$nextEffective]['code'], TokenHelper::$arrayTokenCodes, true) === false) {
+		if ($nextEffective === null || in_array($tokens[$nextEffective]['code'], TokenHelper::ARRAY_TOKEN_CODES, true) === false) {
 			return;
 		}
 
@@ -54,7 +55,7 @@ public function process(File $phpcsFile, $stackPointer): void
 			return;
 		}
 
-		$phpcsFile->fixer->addContent($arrayOpenerPointer, $phpcsFile->eolChar);
+		FixerHelper::add($phpcsFile, $arrayOpenerPointer, $phpcsFile->eolChar);
 	}
 
 }
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/SingleLineArrayWhitespaceSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/SingleLineArrayWhitespaceSniff.php
index 98ce9ea62..a4e460368 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/SingleLineArrayWhitespaceSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/SingleLineArrayWhitespaceSniff.php
@@ -5,6 +5,7 @@
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
 use SlevomatCodingStandard\Helpers\ArrayHelper;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\SniffSettingsHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use function in_array;
@@ -23,18 +24,16 @@ class SingleLineArrayWhitespaceSniff implements Sniff
 	public const CODE_SPACE_BEFORE_ARRAY_CLOSE = 'SpaceBeforeArrayClose';
 	public const CODE_SPACE_IN_EMPTY_ARRAY = 'SpaceInEmptyArray';
 
-	/** @var int */
-	public $spacesAroundBrackets = 0;
+	public int $spacesAroundBrackets = 0;
 
-	/** @var bool */
-	public $enableEmptyArrayCheck = false;
+	public bool $enableEmptyArrayCheck = false;
 
 	/**
 	 * @return array
 	 */
 	public function register(): array
 	{
-		return TokenHelper::$arrayTokenCodes;
+		return TokenHelper::ARRAY_TOKEN_CODES;
 	}
 
 	/**
@@ -78,7 +77,7 @@ public function process(File $phpcsFile, $stackPointer): int
 			}
 
 			// Skip nested arrays as they will be processed separately
-			if (in_array($tokens[$i]['code'], TokenHelper::$arrayTokenCodes, true)) {
+			if (in_array($tokens[$i]['code'], TokenHelper::ARRAY_TOKEN_CODES, true)) {
 				$i = ArrayHelper::openClosePointers($tokens[$i])[1];
 
 				continue;
@@ -113,7 +112,7 @@ private function checkWhitespaceInEmptyArray(File $phpcsFile, int $arrayStart, i
 			return;
 		}
 
-		$phpcsFile->fixer->replaceToken($arrayStart + 1, '');
+		FixerHelper::replace($phpcsFile, $arrayStart + 1, '');
 	}
 
 	private function checkWhitespaceAfterOpeningBracket(File $phpcsFile, int $arrayStart): void
@@ -138,9 +137,13 @@ private function checkWhitespaceAfterOpeningBracket(File $phpcsFile, int $arrayS
 		}
 
 		if ($spaceLength === 0) {
-			$phpcsFile->fixer->addContent($arrayStart, str_repeat(' ', $this->spacesAroundBrackets));
+			FixerHelper::add($phpcsFile, $arrayStart, str_repeat(' ', $this->spacesAroundBrackets));
 		} else {
-			$phpcsFile->fixer->replaceToken($whitespacePointer, str_repeat(' ', $this->spacesAroundBrackets));
+			FixerHelper::replace(
+				$phpcsFile,
+				$whitespacePointer,
+				str_repeat(' ', $this->spacesAroundBrackets),
+			);
 		}
 	}
 
@@ -166,9 +169,13 @@ private function checkWhitespaceBeforeClosingBracket(File $phpcsFile, int $array
 		}
 
 		if ($spaceLength === 0) {
-			$phpcsFile->fixer->addContentBefore($arrayEnd, str_repeat(' ', $this->spacesAroundBrackets));
+			FixerHelper::addBefore($phpcsFile, $arrayEnd, str_repeat(' ', $this->spacesAroundBrackets));
 		} else {
-			$phpcsFile->fixer->replaceToken($whitespacePointer, str_repeat(' ', $this->spacesAroundBrackets));
+			FixerHelper::replace(
+				$phpcsFile,
+				$whitespacePointer,
+				str_repeat(' ', $this->spacesAroundBrackets),
+			);
 		}
 	}
 
@@ -187,14 +194,14 @@ private function checkWhitespaceBeforeComma(File $phpcsFile, int $comma): void
 		$error = sprintf(
 			'Expected 0 spaces between "%s" and comma, %d found.',
 			$tokens[$comma - 2]['content'],
-			$tokens[$comma - 1]['length']
+			$tokens[$comma - 1]['length'],
 		);
 		$fix = $phpcsFile->addFixableError($error, $comma, self::CODE_SPACE_BEFORE_COMMA);
 		if (!$fix) {
 			return;
 		}
 
-		$phpcsFile->fixer->replaceToken($comma - 1, '');
+		FixerHelper::replace($phpcsFile, $comma - 1, '');
 	}
 
 	private function checkWhitespaceAfterComma(File $phpcsFile, int $comma): void
@@ -205,7 +212,7 @@ private function checkWhitespaceAfterComma(File $phpcsFile, int $comma): void
 			$error = sprintf('Expected 1 space between comma and "%s", 0 found.', $tokens[$comma + 1]['content']);
 			$fix = $phpcsFile->addFixableError($error, $comma, self::CODE_SPACE_AFTER_COMMA);
 			if ($fix) {
-				$phpcsFile->fixer->addContent($comma, ' ');
+				FixerHelper::add($phpcsFile, $comma, ' ');
 			}
 
 			return;
@@ -222,7 +229,7 @@ private function checkWhitespaceAfterComma(File $phpcsFile, int $comma): void
 			return;
 		}
 
-		$phpcsFile->fixer->replaceToken($comma + 1, ' ');
+		FixerHelper::replace($phpcsFile, $comma + 1, ' ');
 	}
 
 }
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/TrailingArrayCommaSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/TrailingArrayCommaSniff.php
index 3ced79010..f2de5517e 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/TrailingArrayCommaSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Arrays/TrailingArrayCommaSniff.php
@@ -5,6 +5,7 @@
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
 use SlevomatCodingStandard\Helpers\ArrayHelper;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\SniffSettingsHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use function in_array;
@@ -17,15 +18,14 @@ class TrailingArrayCommaSniff implements Sniff
 
 	public const CODE_MISSING_TRAILING_COMMA = 'MissingTrailingComma';
 
-	/** @var bool|null */
-	public $enableAfterHeredoc = null;
+	public ?bool $enableAfterHeredoc = null;
 
 	/**
 	 * @return array
 	 */
 	public function register(): array
 	{
-		return TokenHelper::$arrayTokenCodes;
+		return TokenHelper::ARRAY_TOKEN_CODES;
 	}
 
 	/**
@@ -66,14 +66,14 @@ public function process(File $phpcsFile, $stackPointer): void
 		$fix = $phpcsFile->addFixableError(
 			'Multi-line arrays must have a trailing comma after the last element.',
 			$pointerPreviousToClose,
-			self::CODE_MISSING_TRAILING_COMMA
+			self::CODE_MISSING_TRAILING_COMMA,
 		);
 		if (!$fix) {
 			return;
 		}
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->addContent($pointerPreviousToClose, ',');
+		FixerHelper::add($phpcsFile, $pointerPreviousToClose, ',');
 		$phpcsFile->fixer->endChangeset();
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Attributes/AttributeAndTargetSpacingSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Attributes/AttributeAndTargetSpacingSniff.php
index 143391bd6..57796b577 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Attributes/AttributeAndTargetSpacingSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Attributes/AttributeAndTargetSpacingSniff.php
@@ -19,11 +19,9 @@ class AttributeAndTargetSpacingSniff implements Sniff
 
 	public const CODE_INCORRECT_LINES_COUNT_BETWEEN_ATTRIBUTE_AND_TARGET = 'IncorrectLinesCountBetweenAttributeAndTarget';
 
-	/** @var int */
-	public $linesCount = 0;
+	public int $linesCount = 0;
 
-	/** @var bool */
-	public $allowOnSameLine = false;
+	public bool $allowOnSameLine = false;
 
 	/**
 	 * @return array
@@ -83,7 +81,7 @@ public function process(File $phpcsFile, $attributeOpenerPointer): void
 		$fix = $phpcsFile->addFixableError(
 			$errorMessage,
 			$attributeOpenerPointer,
-			self::CODE_INCORRECT_LINES_COUNT_BETWEEN_ATTRIBUTE_AND_TARGET
+			self::CODE_INCORRECT_LINES_COUNT_BETWEEN_ATTRIBUTE_AND_TARGET,
 		);
 
 		if (!$fix) {
@@ -93,13 +91,13 @@ public function process(File $phpcsFile, $attributeOpenerPointer): void
 		if ($areOnSameLine) {
 			$indentation = IndentationHelper::getIndentation(
 				$phpcsFile,
-				TokenHelper::findFirstNonWhitespaceOnLine($phpcsFile, $pointerAfter)
+				TokenHelper::findFirstNonWhitespaceOnLine($phpcsFile, $pointerAfter),
 			);
 
 			$phpcsFile->fixer->beginChangeset();
 
 			FixerHelper::removeWhitespaceAfter($phpcsFile, $attributeCloserPointer);
-			$phpcsFile->fixer->addContentBefore($pointerAfter, str_repeat($phpcsFile->eolChar, $this->linesCount + 1) . $indentation);
+			FixerHelper::addBefore($phpcsFile, $pointerAfter, str_repeat($phpcsFile->eolChar, $this->linesCount + 1) . $indentation);
 
 			$phpcsFile->fixer->endChangeset();
 
@@ -111,8 +109,7 @@ public function process(File $phpcsFile, $attributeOpenerPointer): void
 		$phpcsFile->fixer->beginChangeset();
 
 		FixerHelper::removeBetween($phpcsFile, $attributeCloserPointer, $firstTokenOnLine);
-
-		$phpcsFile->fixer->addContentBefore($firstTokenOnLine, str_repeat($phpcsFile->eolChar, $this->linesCount + 1));
+		FixerHelper::addBefore($phpcsFile, $firstTokenOnLine, str_repeat($phpcsFile->eolChar, $this->linesCount + 1));
 
 		$phpcsFile->fixer->endChangeset();
 	}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Attributes/AttributesOrderSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Attributes/AttributesOrderSniff.php
index 337c98e60..0ddc23c87 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Attributes/AttributesOrderSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Attributes/AttributesOrderSniff.php
@@ -10,6 +10,7 @@
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use UnexpectedValueException;
 use function array_keys;
+use function array_map;
 use function asort;
 use function count;
 use function ltrim;
@@ -27,10 +28,9 @@ class AttributesOrderSniff implements Sniff
 	public const CODE_INCORRECT_ORDER = 'IncorrectOrder';
 
 	/** @var list */
-	public $order = [];
+	public array $order = [];
 
-	/** @var bool */
-	public $orderAlphabetically = false;
+	public bool $orderAlphabetically = false;
 
 	/**
 	 * @return array
@@ -89,15 +89,19 @@ public function process(File $phpcsFile, $attributeOpenerPointer): void
 			$actualOrder = $attributesGroups;
 			$expectedOrder = $actualOrder;
 
-			uasort($expectedOrder, static function (array $attributesGroup1, array $attributesGroup2): int {
-				return strnatcmp($attributesGroup1[0]->getName(), $attributesGroup2[0]->getName());
-			});
+			uasort(
+				$expectedOrder,
+				static fn (array $attributesGroup1, array $attributesGroup2): int => strnatcmp(
+					$attributesGroup1[0]->getFullyQualifiedName(),
+					$attributesGroup2[0]->getFullyQualifiedName(),
+				),
+			);
 
 		} else {
 			$actualOrder = [];
 
 			foreach ($attributesGroups as $attributesGroupNo => $attributesGroup) {
-				$attributeName = $this->normalizeAttributeName($attributesGroup[0]->getName());
+				$attributeName = $this->normalizeAttributeName($attributesGroup[0]->getFullyQualifiedName());
 
 				foreach ($this->order as $orderPosition => $attributeNameOnPosition) {
 					if (
@@ -139,7 +143,7 @@ public function process(File $phpcsFile, $attributeOpenerPointer): void
 			$attributesGroupsContent[$attributesGroupNo] = TokenHelper::getContent(
 				$phpcsFile,
 				$attributesGroup[0]->getAttributePointer(),
-				$tokens[$attributesGroup[0]->getAttributePointer()]['attribute_closer']
+				$tokens[$attributesGroup[0]->getAttributePointer()]['attribute_closer'],
 			);
 		}
 
@@ -156,16 +160,16 @@ public function process(File $phpcsFile, $attributeOpenerPointer): void
 		foreach (array_keys($expectedOrder) as $position => $attributesGroupNo) {
 			if ($areOnSameLine) {
 				if ($position !== 0) {
-					$phpcsFile->fixer->addContent($attributesStartPointer, ' ');
+					FixerHelper::add($phpcsFile, $attributesStartPointer, ' ');
 				}
 
-				$phpcsFile->fixer->addContent($attributesStartPointer, $attributesGroupsContent[$attributesGroupNo]);
+				FixerHelper::add($phpcsFile, $attributesStartPointer, $attributesGroupsContent[$attributesGroupNo]);
 			} else {
 				if ($position !== 0) {
-					$phpcsFile->fixer->addContent($attributesStartPointer, $indentation);
+					FixerHelper::add($phpcsFile, $attributesStartPointer, $indentation);
 				}
 
-				$phpcsFile->fixer->addContent($attributesStartPointer, $attributesGroupsContent[$attributesGroupNo]);
+				FixerHelper::add($phpcsFile, $attributesStartPointer, $attributesGroupsContent[$attributesGroupNo]);
 
 				if ($position !== count($attributesGroups) - 1) {
 					$phpcsFile->fixer->addNewline($attributesStartPointer);
@@ -182,11 +186,7 @@ public function process(File $phpcsFile, $attributeOpenerPointer): void
 	 */
 	private function normalizeOrder(array $order): array
 	{
-		foreach ($order as $itemNo => $item) {
-			$order[$itemNo] = $this->normalizeAttributeName(trim($item));
-		}
-
-		return $order;
+		return array_map(fn (string $item): string => $this->normalizeAttributeName(trim($item)), $order);
 	}
 
 	private function normalizeAttributeName(string $name): string
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Attributes/DisallowAttributesJoiningSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Attributes/DisallowAttributesJoiningSniff.php
index a86f110f2..68a688368 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Attributes/DisallowAttributesJoiningSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Attributes/DisallowAttributesJoiningSniff.php
@@ -5,6 +5,7 @@
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
 use SlevomatCodingStandard\Helpers\AttributeHelper;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use function count;
 use function sprintf;
 use const T_ATTRIBUTE;
@@ -42,7 +43,7 @@ public function process(File $phpcsFile, $attributeOpenerPointer): void
 		$fix = $phpcsFile->addFixableError(
 			sprintf('%d attributes are joined.', $attributeCount),
 			$attributeOpenerPointer,
-			self::CODE_DISALLOWED_ATTRIBUTES_JOINING
+			self::CODE_DISALLOWED_ATTRIBUTES_JOINING,
 		);
 
 		if (!$fix) {
@@ -55,15 +56,15 @@ public function process(File $phpcsFile, $attributeOpenerPointer): void
 			$previousAttribute = $attributes[$i - 1];
 			$attribute = $attributes[$i];
 
-			$phpcsFile->fixer->addContent($previousAttribute->getEndPointer(), ']');
+			FixerHelper::add($phpcsFile, $previousAttribute->getEndPointer(), ']');
 
 			for ($j = $previousAttribute->getEndPointer() + 1; $j < $attribute->getStartPointer(); $j++) {
 				if ($phpcsFile->fixer->getTokenContent($j) === ',') {
-					$phpcsFile->fixer->replaceToken($j, '');
+					FixerHelper::replace($phpcsFile, $j, '');
 				}
 			}
 
-			$phpcsFile->fixer->addContentBefore($attribute->getStartPointer(), '#[');
+			FixerHelper::addBefore($phpcsFile, $attribute->getStartPointer(), '#[');
 		}
 
 		$phpcsFile->fixer->endChangeset();
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Attributes/DisallowMultipleAttributesPerLineSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Attributes/DisallowMultipleAttributesPerLineSniff.php
index ca6f9200e..df7b5abf4 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Attributes/DisallowMultipleAttributesPerLineSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Attributes/DisallowMultipleAttributesPerLineSniff.php
@@ -57,7 +57,7 @@ public function process(File $phpcsFile, $attributeOpenerPointer): void
 		$fix = $phpcsFile->addFixableError(
 			'Multiple attributes per line are disallowed.',
 			$nextAttributeOpenerPointer,
-			self::CODE_DISALLOWED_MULTIPLE_ATTRIBUTES_PER_LINE
+			self::CODE_DISALLOWED_MULTIPLE_ATTRIBUTES_PER_LINE,
 		);
 
 		if (!$fix) {
@@ -67,14 +67,13 @@ public function process(File $phpcsFile, $attributeOpenerPointer): void
 		$nonWhitespacePointerBefore = TokenHelper::findPreviousNonWhitespace($phpcsFile, $nextAttributeOpenerPointer - 1);
 		$indentation = IndentationHelper::getIndentation(
 			$phpcsFile,
-			TokenHelper::findFirstNonWhitespaceOnLine($phpcsFile, $attributeOpenerPointer)
+			TokenHelper::findFirstNonWhitespaceOnLine($phpcsFile, $attributeOpenerPointer),
 		);
 
 		$phpcsFile->fixer->beginChangeset();
 
 		FixerHelper::removeBetween($phpcsFile, $nonWhitespacePointerBefore, $nextAttributeOpenerPointer);
-
-		$phpcsFile->fixer->addContentBefore($nextAttributeOpenerPointer, $phpcsFile->eolChar . $indentation);
+		FixerHelper::addBefore($phpcsFile, $nextAttributeOpenerPointer, $phpcsFile->eolChar . $indentation);
 
 		$phpcsFile->fixer->endChangeset();
 	}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Attributes/RequireAttributeAfterDocCommentSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Attributes/RequireAttributeAfterDocCommentSniff.php
index 9729e99a9..9eeada477 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Attributes/RequireAttributeAfterDocCommentSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Attributes/RequireAttributeAfterDocCommentSniff.php
@@ -40,7 +40,7 @@ public function process(File $phpcsFile, $attributeOpenerPointer): void
 		$docCommentOpenerPointer = TokenHelper::findNextExcluding(
 			$phpcsFile,
 			T_WHITESPACE,
-			$tokens[$attributeOpenerPointer]['attribute_closer'] + 1
+			$tokens[$attributeOpenerPointer]['attribute_closer'] + 1,
 		);
 
 		if ($tokens[$docCommentOpenerPointer]['code'] !== T_DOC_COMMENT_OPEN_TAG) {
@@ -67,7 +67,7 @@ public function process(File $phpcsFile, $attributeOpenerPointer): void
 		$fix = $phpcsFile->addFixableError(
 			'Attribute should be placed after documentation comment.',
 			$attributeOpenerPointer,
-			self::CODE_ATTRIBUTE_BEFORE_DOC_COMMENT
+			self::CODE_ATTRIBUTE_BEFORE_DOC_COMMENT,
 		);
 
 		if (!$fix) {
@@ -76,7 +76,7 @@ public function process(File $phpcsFile, $attributeOpenerPointer): void
 
 		$phpcsFile->fixer->beginChangeset();
 
-		$phpcsFile->fixer->addContentBefore($attributeStartPointer, $docComment);
+		FixerHelper::addBefore($phpcsFile, $attributeStartPointer, $docComment);
 
 		FixerHelper::removeBetweenIncluding($phpcsFile, $docCommentStartPointer, $docCommentEndPointer);
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/AbstractMethodSignature.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/AbstractMethodSignature.php
index 5e00be600..c4a468c12 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/AbstractMethodSignature.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/AbstractMethodSignature.php
@@ -4,7 +4,6 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
-use SlevomatCodingStandard\Helpers\IndentationHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use function assert;
 use function is_string;
@@ -61,9 +60,4 @@ protected function getSignature(File $phpcsFile, int $signatureStartPointer, int
 		return $signature;
 	}
 
-	protected function getSignatureWithoutTabs(File $phpcsFile, string $signature): string
-	{
-		return IndentationHelper::convertTabsToSpaces($phpcsFile, $signature);
-	}
-
 }
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/AbstractPropertyConstantAndEnumCaseSpacing.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/AbstractPropertyConstantAndEnumCaseSpacing.php
index eeb2f68c3..07ee541bf 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/AbstractPropertyConstantAndEnumCaseSpacing.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/AbstractPropertyConstantAndEnumCaseSpacing.php
@@ -10,6 +10,8 @@
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use function assert;
 use function in_array;
+use function max;
+use function min;
 use function str_repeat;
 use const T_ATTRIBUTE;
 use const T_COMMENT;
@@ -17,14 +19,9 @@
 use const T_DOC_COMMENT_OPEN_TAG;
 use const T_ENUM_CASE;
 use const T_FUNCTION;
-use const T_PRIVATE;
-use const T_PROTECTED;
-use const T_PUBLIC;
-use const T_READONLY;
+use const T_OPEN_CURLY_BRACKET;
 use const T_SEMICOLON;
-use const T_STATIC;
 use const T_USE;
-use const T_VAR;
 use const T_VARIABLE;
 
 /**
@@ -33,17 +30,17 @@
 abstract class AbstractPropertyConstantAndEnumCaseSpacing implements Sniff
 {
 
-	/** @var int */
-	public $minLinesCountBeforeWithComment = 1;
+	public int $minLinesCountBeforeWithComment = 1;
 
-	/** @var int */
-	public $maxLinesCountBeforeWithComment = 1;
+	public int $maxLinesCountBeforeWithComment = 1;
 
-	/** @var int */
-	public $minLinesCountBeforeWithoutComment = 0;
+	public int $minLinesCountBeforeWithoutComment = 0;
 
-	/** @var int */
-	public $maxLinesCountBeforeWithoutComment = 1;
+	public int $maxLinesCountBeforeWithoutComment = 1;
+
+	public ?int $minLinesCountBeforeMultiline = null;
+
+	public ?int $maxLinesCountBeforeMultiline = null;
 
 	abstract protected function isNextMemberValid(File $phpcsFile, int $pointer): bool;
 
@@ -59,21 +56,22 @@ public function process(File $phpcsFile, $pointer): int
 		$this->maxLinesCountBeforeWithComment = SniffSettingsHelper::normalizeInteger($this->maxLinesCountBeforeWithComment);
 		$this->minLinesCountBeforeWithoutComment = SniffSettingsHelper::normalizeInteger($this->minLinesCountBeforeWithoutComment);
 		$this->maxLinesCountBeforeWithoutComment = SniffSettingsHelper::normalizeInteger($this->maxLinesCountBeforeWithoutComment);
+		$this->minLinesCountBeforeMultiline = SniffSettingsHelper::normalizeNullableInteger($this->minLinesCountBeforeMultiline);
+		$this->maxLinesCountBeforeMultiline = SniffSettingsHelper::normalizeNullableInteger($this->maxLinesCountBeforeMultiline);
 
 		$tokens = $phpcsFile->getTokens();
 
 		$classPointer = ClassHelper::getClassPointer($phpcsFile, $pointer);
 
-		$semicolonPointer = TokenHelper::findNext($phpcsFile, [T_SEMICOLON], $pointer + 1);
-		assert($semicolonPointer !== null);
+		$endPointer = $this->getEndPointer($phpcsFile, $pointer);
 
-		$firstOnLinePointer = TokenHelper::findFirstTokenOnNextLine($phpcsFile, $semicolonPointer);
+		$firstOnLinePointer = TokenHelper::findFirstTokenOnNextLine($phpcsFile, $endPointer);
 		assert($firstOnLinePointer !== null);
 
 		$nextFunctionPointer = TokenHelper::findNext(
 			$phpcsFile,
 			[T_FUNCTION, T_ENUM_CASE, T_CONST, T_VARIABLE, T_USE],
-			$firstOnLinePointer + 1
+			$firstOnLinePointer + 1,
 		);
 		if (
 			$nextFunctionPointer === null
@@ -83,14 +81,14 @@ public function process(File $phpcsFile, $pointer): int
 			return $nextFunctionPointer ?? $firstOnLinePointer;
 		}
 
-		$types = [T_COMMENT, T_DOC_COMMENT_OPEN_TAG, T_ATTRIBUTE, T_ENUM_CASE, T_CONST, T_VAR, T_PUBLIC, T_PROTECTED, T_PRIVATE, T_READONLY, T_STATIC, T_USE];
+		$types = [T_COMMENT, T_DOC_COMMENT_OPEN_TAG, T_ATTRIBUTE, T_ENUM_CASE, T_CONST, T_USE, ...TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES];
 		$nextPointer = TokenHelper::findNext($phpcsFile, $types, $firstOnLinePointer + 1, $tokens[$classPointer]['scope_closer']);
 
 		if (!$this->isNextMemberValid($phpcsFile, $nextPointer)) {
 			return $nextPointer;
 		}
 
-		$linesBetween = $tokens[$nextPointer]['line'] - $tokens[$semicolonPointer]['line'] - 1;
+		$linesBetween = $tokens[$nextPointer]['line'] - $tokens[$endPointer]['line'] - 1;
 		if (in_array($tokens[$nextPointer]['code'], [T_DOC_COMMENT_OPEN_TAG, T_COMMENT, T_ATTRIBUTE], true)) {
 			$minExpectedLines = $this->minLinesCountBeforeWithComment;
 			$maxExpectedLines = $this->maxLinesCountBeforeWithComment;
@@ -99,6 +97,23 @@ public function process(File $phpcsFile, $pointer): int
 			$maxExpectedLines = $this->maxLinesCountBeforeWithoutComment;
 		}
 
+		if (
+			$this->minLinesCountBeforeMultiline !== null
+			&& !$this instanceof EnumCaseSpacingSniff
+			&& $tokens[$pointer]['line'] !== $tokens[$endPointer]['line']
+		) {
+			$minExpectedLines = max($minExpectedLines, $this->minLinesCountBeforeMultiline);
+			$maxExpectedLines = max($minExpectedLines, $maxExpectedLines);
+		}
+
+		if (
+			$this->maxLinesCountBeforeMultiline !== null
+			&& !$this instanceof EnumCaseSpacingSniff
+			&& $tokens[$pointer]['line'] !== $tokens[$endPointer]['line']
+		) {
+			$maxExpectedLines = max($minExpectedLines, min($maxExpectedLines, $this->maxLinesCountBeforeMultiline));
+		}
+
 		if ($linesBetween >= $minExpectedLines && $linesBetween <= $maxExpectedLines) {
 			return $firstOnLinePointer;
 		}
@@ -109,13 +124,17 @@ public function process(File $phpcsFile, $pointer): int
 		}
 
 		if ($linesBetween > $maxExpectedLines) {
-			$lastPointerOnLine = TokenHelper::findLastTokenOnLine($phpcsFile, $semicolonPointer);
+			$lastPointerOnLine = TokenHelper::findLastTokenOnLine($phpcsFile, $endPointer);
 			$firstPointerOnNextLine = TokenHelper::findFirstTokenOnLine($phpcsFile, $nextPointer);
 
 			$phpcsFile->fixer->beginChangeset();
 
 			if ($maxExpectedLines > 0) {
-				$phpcsFile->fixer->addContent($lastPointerOnLine, str_repeat($phpcsFile->eolChar, $maxExpectedLines));
+				FixerHelper::add(
+					$phpcsFile,
+					$lastPointerOnLine,
+					str_repeat($phpcsFile->eolChar, $maxExpectedLines),
+				);
 			}
 
 			FixerHelper::removeBetween($phpcsFile, $lastPointerOnLine, $firstPointerOnNextLine);
@@ -134,4 +153,15 @@ public function process(File $phpcsFile, $pointer): int
 		return $firstOnLinePointer;
 	}
 
+	private function getEndPointer(File $phpcsFile, int $pointer): int
+	{
+		$tokens = $phpcsFile->getTokens();
+
+		$endPointer = TokenHelper::findNext($phpcsFile, [T_SEMICOLON, T_OPEN_CURLY_BRACKET], $pointer + 1);
+
+		return $tokens[$endPointer]['code'] === T_OPEN_CURLY_BRACKET
+			? $tokens[$endPointer]['bracket_closer']
+			: $endPointer;
+	}
+
 }
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/BackedEnumTypeSpacingSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/BackedEnumTypeSpacingSniff.php
index 0af9932de..abad0b944 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/BackedEnumTypeSpacingSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/BackedEnumTypeSpacingSniff.php
@@ -20,11 +20,9 @@ class BackedEnumTypeSpacingSniff implements Sniff
 
 	public const CODE_INCORRECT_SPACES_BEFORE_TYPE = 'IncorrectSpacesBeforeType';
 
-	/** @var int */
-	public $spacesCountBeforeColon = 0;
+	public int $spacesCountBeforeColon = 0;
 
-	/** @var int */
-		public $spacesCountBeforeType = 1;
+	public int $spacesCountBeforeType = 1;
 
 	/**
 	 * @return array
@@ -68,7 +66,7 @@ public function checkSpacesBeforeColon(File $phpcsFile, int $colonPointer): void
 		$fix = $phpcsFile->addFixableError(
 			$this->formatErrorMessage('before colon', $this->spacesCountBeforeColon),
 			$colonPointer,
-			self::CODE_INCORRECT_SPACES_BEFORE_COLON
+			self::CODE_INCORRECT_SPACES_BEFORE_COLON,
 		);
 		if (!$fix) {
 			return;
@@ -78,7 +76,7 @@ public function checkSpacesBeforeColon(File $phpcsFile, int $colonPointer): void
 
 		FixerHelper::removeBetween($phpcsFile, $namePointer, $colonPointer);
 
-		$phpcsFile->fixer->addContentBefore($colonPointer, str_repeat(' ', $this->spacesCountBeforeColon));
+		FixerHelper::addBefore($phpcsFile, $colonPointer, str_repeat(' ', $this->spacesCountBeforeColon));
 
 		$phpcsFile->fixer->endChangeset();
 	}
@@ -96,7 +94,7 @@ public function checkSpacesBeforeType(File $phpcsFile, int $colonPointer): void
 		$fix = $phpcsFile->addFixableError(
 			$this->formatErrorMessage('before type', $this->spacesCountBeforeType),
 			$typePointer,
-			self::CODE_INCORRECT_SPACES_BEFORE_TYPE
+			self::CODE_INCORRECT_SPACES_BEFORE_TYPE,
 		);
 		if (!$fix) {
 			return;
@@ -106,7 +104,7 @@ public function checkSpacesBeforeType(File $phpcsFile, int $colonPointer): void
 
 		FixerHelper::removeBetween($phpcsFile, $colonPointer, $typePointer);
 
-		$phpcsFile->fixer->addContentBefore($typePointer, str_repeat(' ', $this->spacesCountBeforeType));
+		FixerHelper::addBefore($phpcsFile, $typePointer, str_repeat(' ', $this->spacesCountBeforeType));
 
 		$phpcsFile->fixer->endChangeset();
 	}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ClassConstantVisibilitySniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ClassConstantVisibilitySniff.php
index 0f375d9f7..f717c5a8e 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ClassConstantVisibilitySniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ClassConstantVisibilitySniff.php
@@ -6,12 +6,14 @@
 use PHP_CodeSniffer\Sniffs\Sniff;
 use PHP_CodeSniffer\Util\Tokens;
 use SlevomatCodingStandard\Helpers\ClassHelper;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use function array_keys;
 use function count;
 use function in_array;
 use function sprintf;
 use const T_CONST;
+use const T_EQUAL;
 use const T_FINAL;
 use const T_PRIVATE;
 use const T_PROTECTED;
@@ -22,8 +24,7 @@ class ClassConstantVisibilitySniff implements Sniff
 
 	public const CODE_MISSING_CONSTANT_VISIBILITY = 'MissingConstantVisibility';
 
-	/** @var bool */
-	public $fixable = false;
+	public bool $fixable = false;
 
 	/**
 	 * @return array
@@ -62,17 +63,20 @@ public function process(File $phpcsFile, $constantPointer): void
 			return;
 		}
 
+		$equalSignPointer = TokenHelper::findNext($phpcsFile, T_EQUAL, $constantPointer + 1);
+		$namePointer = TokenHelper::findPreviousEffective($phpcsFile, $equalSignPointer - 1);
+
 		$message = sprintf(
 			'Constant %s::%s visibility missing.',
 			ClassHelper::getFullyQualifiedName($phpcsFile, $classPointer),
-			$tokens[TokenHelper::findNextEffective($phpcsFile, $constantPointer + 1)]['content']
+			$tokens[$namePointer]['content'],
 		);
 
 		if ($this->fixable) {
 			$fix = $phpcsFile->addFixableError($message, $constantPointer, self::CODE_MISSING_CONSTANT_VISIBILITY);
 			if ($fix) {
 				$phpcsFile->fixer->beginChangeset();
-				$phpcsFile->fixer->addContentBefore($constantPointer, 'public ');
+				FixerHelper::addBefore($phpcsFile, $constantPointer, 'public ');
 				$phpcsFile->fixer->endChangeset();
 			}
 		} else {
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ClassLengthSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ClassLengthSniff.php
index bdc035d7a..c5aa1287c 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ClassLengthSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ClassLengthSniff.php
@@ -18,14 +18,11 @@ class ClassLengthSniff implements Sniff
 
 	public const CODE_CLASS_TOO_LONG = 'ClassTooLong';
 
-	/** @var int */
-	public $maxLinesLength = 250;
+	public int $maxLinesLength = 250;
 
-	/** @var bool */
-	public $includeComments = false;
+	public bool $includeComments = false;
 
-	/** @var bool */
-	public $includeWhitespace = false;
+	public bool $includeWhitespace = false;
 
 	/**
 	 * @return array
@@ -46,9 +43,7 @@ public function process(File $phpcsFile, $pointer): void
 			FunctionHelper::LINE_INCLUDE_COMMENT => $this->includeComments,
 			FunctionHelper::LINE_INCLUDE_WHITESPACE => $this->includeWhitespace,
 		]));
-		$flags = array_reduce($flags, static function ($carry, $flag): int {
-			return $carry | $flag;
-		}, 0);
+		$flags = array_reduce($flags, static fn ($carry, $flag): int => $carry | $flag, 0);
 
 		$length = FunctionHelper::getLineCount($phpcsFile, $pointer, $flags);
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ClassMemberSpacingSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ClassMemberSpacingSniff.php
index 0b763764d..c295be62d 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ClassMemberSpacingSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ClassMemberSpacingSniff.php
@@ -15,28 +15,18 @@
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use SlevomatCodingStandard\Helpers\UseStatementHelper;
 use function array_key_exists;
-use function array_merge;
 use function in_array;
 use function sprintf;
 use function str_repeat;
-use const T_ABSTRACT;
-use const T_ANON_CLASS;
 use const T_AS;
 use const T_ATTRIBUTE_END;
 use const T_CLOSE_CURLY_BRACKET;
 use const T_CONST;
 use const T_ENUM_CASE;
-use const T_FINAL;
 use const T_FUNCTION;
 use const T_OPEN_CURLY_BRACKET;
-use const T_PRIVATE;
-use const T_PROTECTED;
-use const T_PUBLIC;
-use const T_READONLY;
 use const T_SEMICOLON;
-use const T_STATIC;
 use const T_USE;
-use const T_VAR;
 use const T_VARIABLE;
 
 class ClassMemberSpacingSniff implements Sniff
@@ -44,16 +34,14 @@ class ClassMemberSpacingSniff implements Sniff
 
 	public const CODE_INCORRECT_COUNT_OF_BLANK_LINES_BETWEEN_MEMBERS = 'IncorrectCountOfBlankLinesBetweenMembers';
 
-	/** @var int */
-	public $linesCountBetweenMembers = 1;
+	public int $linesCountBetweenMembers = 1;
 
 	/**
 	 * @return array
 	 */
 	public function register(): array
 	{
-		/** @phpstan-var array */
-		return array_merge(TokenHelper::$typeKeywordTokenCodes, [T_ANON_CLASS]);
+		return TokenHelper::CLASS_TYPE_WITH_ANONYMOUS_CLASS_TOKEN_CODES;
 	}
 
 	/**
@@ -67,7 +55,6 @@ public function process(File $phpcsFile, $classPointer): void
 		$tokens = $phpcsFile->getTokens();
 
 		$memberPointer = null;
-		$previousMemberPointer = null;
 
 		do {
 			$previousMemberPointer = $memberPointer;
@@ -75,7 +62,7 @@ public function process(File $phpcsFile, $classPointer): void
 			$memberPointer = $this->findNextMember(
 				$phpcsFile,
 				$classPointer,
-				$previousMemberPointer ?? $tokens[$classPointer]['scope_opener']
+				$previousMemberPointer ?? $tokens[$classPointer]['scope_opener'],
 			);
 
 			if ($memberPointer === null) {
@@ -96,7 +83,7 @@ public function process(File $phpcsFile, $classPointer): void
 
 			$commentPointerAfterPreviousMember = TokenHelper::findNextNonWhitespace($phpcsFile, $previousMemberEndPointer + 1);
 			if (
-				in_array($tokens[$commentPointerAfterPreviousMember]['code'], TokenHelper::$inlineCommentTokenCodes, true)
+				in_array($tokens[$commentPointerAfterPreviousMember]['code'], TokenHelper::INLINE_COMMENT_TOKEN_CODES, true)
 				&& (
 					$tokens[$previousMemberEndPointer]['line'] === $tokens[$commentPointerAfterPreviousMember]['line']
 					|| $tokens[$previousMemberEndPointer]['line'] + 1 === $tokens[$commentPointerAfterPreviousMember]['line']
@@ -109,7 +96,7 @@ public function process(File $phpcsFile, $classPointer): void
 				}
 			}
 
-			$memberStartPointer = $this->getMemberStartPointer($phpcsFile, $memberPointer);
+			$memberStartPointer = $this->getMemberStartPointer($phpcsFile, $memberPointer, $previousMemberEndPointer);
 
 			$actualLinesCount = $tokens[$memberStartPointer]['line'] - $tokens[$previousMemberEndPointer]['line'] - 1;
 
@@ -121,25 +108,36 @@ public function process(File $phpcsFile, $classPointer): void
 				? 'Expected 1 blank line between class members, found %2$d.'
 				: 'Expected %1$d blank lines between class members, found %2$d.';
 
-			$fix = $phpcsFile->addFixableError(
+			$firstPointerOnMemberLine = TokenHelper::findFirstTokenOnLine($phpcsFile, $memberStartPointer);
+			$nonWhitespaceBetweenMembersPointer = TokenHelper::findNextNonWhitespace(
+				$phpcsFile,
+				$previousMemberEndPointer + 1,
+				$firstPointerOnMemberLine,
+			);
+			$errorParameters = [
 				sprintf($errorMessage, $this->linesCountBetweenMembers, $actualLinesCount),
 				$memberPointer,
-				self::CODE_INCORRECT_COUNT_OF_BLANK_LINES_BETWEEN_MEMBERS
-			);
+				self::CODE_INCORRECT_COUNT_OF_BLANK_LINES_BETWEEN_MEMBERS,
+			];
+
+			if ($nonWhitespaceBetweenMembersPointer !== null) {
+				$phpcsFile->addError(...$errorParameters);
+				continue;
+			}
+
+			$fix = $phpcsFile->addFixableError(...$errorParameters);
 			if (!$fix) {
 				continue;
 			}
 
 			$newLines = str_repeat(
 				$phpcsFile->eolChar,
-				$this->linesCountBetweenMembers + ($hasCommentWithNewLineAfterPreviousMember ? 0 : 1)
+				$this->linesCountBetweenMembers + ($hasCommentWithNewLineAfterPreviousMember ? 0 : 1),
 			);
 
-			$firstPointerOnMemberLine = TokenHelper::findFirstTokenOnLine($phpcsFile, $memberStartPointer);
-
 			$phpcsFile->fixer->beginChangeset();
 
-			$phpcsFile->fixer->addContent($previousMemberEndPointer, $newLines);
+			FixerHelper::add($phpcsFile, $previousMemberEndPointer, $newLines);
 
 			FixerHelper::removeBetween($phpcsFile, $previousMemberEndPointer, $firstPointerOnMemberLine);
 
@@ -152,13 +150,15 @@ private function findNextMember(File $phpcsFile, int $classPointer, int $previou
 	{
 		$tokens = $phpcsFile->getTokens();
 
+		$memberTokenCodes = [T_USE, T_CONST, T_FUNCTION, T_ENUM_CASE, ...TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES];
+
 		$memberPointer = $previousMemberPointer;
 		do {
 			$memberPointer = TokenHelper::findNext(
 				$phpcsFile,
-				[T_USE, T_CONST, T_VAR, T_PUBLIC, T_PROTECTED, T_PRIVATE, T_READONLY, T_STATIC, T_FUNCTION, T_ENUM_CASE],
+				$memberTokenCodes,
 				$memberPointer + 1,
-				$tokens[$classPointer]['scope_closer']
+				$tokens[$classPointer]['scope_closer'],
 			);
 
 			if ($memberPointer === null) {
@@ -169,13 +169,13 @@ private function findNextMember(File $phpcsFile, int $classPointer, int $previou
 				if (!UseStatementHelper::isTraitUse($phpcsFile, $memberPointer)) {
 					continue;
 				}
-			} elseif (in_array($tokens[$memberPointer]['code'], [T_VAR, T_PUBLIC, T_PROTECTED, T_PRIVATE, T_READONLY, T_STATIC], true)) {
+			} elseif (in_array($tokens[$memberPointer]['code'], TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES, true)) {
 				$asPointer = TokenHelper::findPreviousEffective($phpcsFile, $memberPointer - 1);
 				if ($tokens[$asPointer]['code'] === T_AS) {
 					continue;
 				}
 
-				$propertyPointer = TokenHelper::findNext($phpcsFile, [T_VARIABLE, T_FUNCTION, T_CONST, T_ENUM_CASE], $memberPointer + 1);
+				$propertyPointer = TokenHelper::findNext($phpcsFile, [T_VARIABLE, T_FUNCTION, T_CONST], $memberPointer + 1);
 				if (
 					$propertyPointer === null
 					|| $tokens[$propertyPointer]['code'] !== T_VARIABLE
@@ -196,13 +196,17 @@ private function findNextMember(File $phpcsFile, int $classPointer, int $previou
 		return $memberPointer;
 	}
 
-	private function getMemberStartPointer(File $phpcsFile, int $memberPointer): int
+	private function getMemberStartPointer(File $phpcsFile, int $memberPointer, int $previousMemberEndPointer): int
 	{
 		$tokens = $phpcsFile->getTokens();
 
 		$memberFirstCodePointer = $this->getMemberFirstCodePointer($phpcsFile, $memberPointer);
 
 		do {
+			if ($memberFirstCodePointer <= $previousMemberEndPointer) {
+				return TokenHelper::findNextNonWhitespace($phpcsFile, $memberFirstCodePointer + 1);
+			}
+
 			$pointerBefore = TokenHelper::findPreviousNonWhitespace($phpcsFile, $memberFirstCodePointer - 1);
 
 			if ($tokens[$pointerBefore]['code'] === T_ATTRIBUTE_END) {
@@ -210,10 +214,7 @@ private function getMemberStartPointer(File $phpcsFile, int $memberPointer): int
 				continue;
 			}
 
-			if (
-				in_array($tokens[$pointerBefore]['code'], Tokens::$commentTokens, true)
-				&& $tokens[$pointerBefore]['line'] + 1 === $tokens[$memberFirstCodePointer]['line']
-			) {
+			if (in_array($tokens[$pointerBefore]['code'], Tokens::$commentTokens, true)) {
 				$pointerBeforeComment = TokenHelper::findPreviousEffective($phpcsFile, $pointerBefore - 1);
 				if ($tokens[$pointerBeforeComment]['line'] !== $tokens[$pointerBefore]['line']) {
 					$memberFirstCodePointer = array_key_exists('comment_opener', $tokens[$pointerBefore])
@@ -238,17 +239,16 @@ private function getMemberFirstCodePointer(File $phpcsFile, int $memberPointer):
 			return $memberPointer;
 		}
 
+		$endTokenCodes = [T_SEMICOLON, T_CLOSE_CURLY_BRACKET];
+		$startOrEndTokenCodes = [...TokenHelper::MODIFIERS_TOKEN_CODES, ...$endTokenCodes];
+
 		$firstCodePointer = $memberPointer;
 		$previousFirstCodePointer = $memberPointer;
 		do {
 			/** @var int $firstCodePointer */
-			$firstCodePointer = TokenHelper::findPrevious(
-				$phpcsFile,
-				[T_VAR, T_PUBLIC, T_PROTECTED, T_PRIVATE, T_ABSTRACT, T_FINAL, T_SEMICOLON, T_CLOSE_CURLY_BRACKET],
-				$firstCodePointer - 1
-			);
+			$firstCodePointer = TokenHelper::findPrevious($phpcsFile, $startOrEndTokenCodes, $firstCodePointer - 1);
 
-			if (in_array($tokens[$firstCodePointer]['code'], [T_SEMICOLON, T_CLOSE_CURLY_BRACKET], true)) {
+			if (in_array($tokens[$firstCodePointer]['code'], $endTokenCodes, true)) {
 				break;
 			}
 
@@ -263,7 +263,11 @@ private function getMemberEndPointer(File $phpcsFile, int $memberPointer): int
 	{
 		$tokens = $phpcsFile->getTokens();
 
-		if ($tokens[$memberPointer]['code'] === T_USE) {
+		if (
+			$tokens[$memberPointer]['code'] === T_USE
+			// Property with hooks
+			|| $tokens[$memberPointer]['code'] === T_VARIABLE
+		) {
 			$pointer = TokenHelper::findNextLocal($phpcsFile, [T_SEMICOLON, T_OPEN_CURLY_BRACKET], $memberPointer + 1);
 
 			return $tokens[$pointer]['code'] === T_OPEN_CURLY_BRACKET
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ClassStructureSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ClassStructureSniff.php
index e01288ba7..5140cf641 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ClassStructureSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ClassStructureSniff.php
@@ -5,12 +5,16 @@
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
 use PHP_CodeSniffer\Util\Tokens;
+use SlevomatCodingStandard\Helpers\AnnotationHelper;
+use SlevomatCodingStandard\Helpers\AttributeHelper;
 use SlevomatCodingStandard\Helpers\ClassHelper;
 use SlevomatCodingStandard\Helpers\DocCommentHelper;
 use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\FunctionHelper;
+use SlevomatCodingStandard\Helpers\NamespaceHelper;
 use SlevomatCodingStandard\Helpers\PropertyHelper;
 use SlevomatCodingStandard\Helpers\SniffSettingsHelper;
+use SlevomatCodingStandard\Helpers\StringHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use function array_diff;
 use function array_filter;
@@ -18,24 +22,32 @@
 use function array_key_exists;
 use function array_keys;
 use function array_merge;
+use function array_shift;
 use function array_values;
 use function assert;
 use function implode;
 use function in_array;
+use function ltrim;
 use function preg_replace;
 use function preg_split;
 use function sprintf;
 use function str_repeat;
 use function strtolower;
+use function substr;
+use const PREG_SPLIT_NO_EMPTY;
 use const T_ABSTRACT;
+use const T_ATTRIBUTE_END;
 use const T_CLOSE_CURLY_BRACKET;
 use const T_CONST;
 use const T_ENUM_CASE;
 use const T_FINAL;
 use const T_FUNCTION;
 use const T_OPEN_CURLY_BRACKET;
+use const T_PRIVATE_SET;
 use const T_PROTECTED;
+use const T_PROTECTED_SET;
 use const T_PUBLIC;
+use const T_PUBLIC_SET;
 use const T_SEMICOLON;
 use const T_STATIC;
 use const T_USE;
@@ -60,6 +72,7 @@ class ClassStructureSniff implements Sniff
 	private const GROUP_CONSTRUCTOR = 'constructor';
 	private const GROUP_STATIC_CONSTRUCTORS = 'static constructors';
 	private const GROUP_DESTRUCTOR = 'destructor';
+	private const GROUP_INVOKE_METHOD = 'invoke method';
 	private const GROUP_MAGIC_METHODS = 'magic methods';
 	private const GROUP_PUBLIC_METHODS = 'public methods';
 	private const GROUP_PUBLIC_ABSTRACT_METHODS = 'public abstract methods';
@@ -174,17 +187,23 @@ class ClassStructureSniff implements Sniff
 		'__serialize' => self::GROUP_MAGIC_METHODS,
 		'__unserialize' => self::GROUP_MAGIC_METHODS,
 		'__tostring' => self::GROUP_MAGIC_METHODS,
-		'__invoke' => self::GROUP_MAGIC_METHODS,
+		'__invoke' => self::GROUP_INVOKE_METHOD,
 		'__set_state' => self::GROUP_MAGIC_METHODS,
 		'__clone' => self::GROUP_MAGIC_METHODS,
 		'__debuginfo' => self::GROUP_MAGIC_METHODS,
 	];
 
+	/** @var array */
+	public array $methodGroups = [];
+
 	/** @var list */
-	public $groups = [];
+	public array $groups = [];
+
+	/** @var array, annotations: array}>>|null */
+	private ?array $normalizedMethodGroups = null;
 
 	/** @var array|null */
-	private $normalizedGroups;
+	private ?array $normalizedGroups = null;
 
 	/**
 	 * @return array
@@ -201,8 +220,8 @@ public function register(): array
 	public function process(File $phpcsFile, $pointer): int
 	{
 		$tokens = $phpcsFile->getTokens();
-		/** @var array{scope_closer: int, level: int} $rootScopeToken */
 		$rootScopeToken = $tokens[$pointer];
+		assert(array_key_exists('scope_opener', $rootScopeToken));
 
 		$groupsOrder = $this->getNormalizedGroups();
 
@@ -217,6 +236,11 @@ public function process(File $phpcsFile, $pointer): int
 
 			[$groupFirstMemberPointer, $groupLastMemberPointer, $group] = $nextGroup;
 
+			// Use "magic methods" group for __invoke() when "invoke" group is not explicitly defined
+			if ($group === self::GROUP_INVOKE_METHOD && !array_key_exists($group, $groupsOrder)) {
+				$group = self::GROUP_MAGIC_METHODS;
+			}
+
 			if ($groupsOrder[$group] >= ($groupsOrder[$expectedGroup] ?? 0)) {
 				$groupsFirstMembers[$group] = $groupFirstMemberPointer;
 				$expectedGroup = $group;
@@ -226,19 +250,17 @@ public function process(File $phpcsFile, $pointer): int
 
 			$expectedGroups = array_filter(
 				$groupsOrder,
-				static function (int $order) use ($groupsOrder, $expectedGroup): bool {
-					return $order >= $groupsOrder[$expectedGroup];
-				}
+				static fn (int $order): bool => $order >= $groupsOrder[$expectedGroup],
 			);
 			$fix = $phpcsFile->addFixableError(
 				sprintf(
 					'The placement of "%s" group is invalid. Last group was "%s" and one of these is expected after it: %s',
 					$group,
 					$expectedGroup,
-					implode(', ', array_keys($expectedGroups))
+					implode(', ', array_keys($expectedGroups)),
 				),
 				$groupFirstMemberPointer,
-				self::CODE_INCORRECT_GROUP_ORDER
+				self::CODE_INCORRECT_GROUP_ORDER,
 			);
 			if (!$fix) {
 				continue;
@@ -266,15 +288,14 @@ static function (int $order) use ($groupsOrder, $expectedGroup): bool {
 	private function findNextGroup(File $phpcsFile, int $pointer, array $rootScopeToken): ?array
 	{
 		$tokens = $phpcsFile->getTokens();
-		$groupTokenTypes = [T_USE, T_ENUM_CASE, T_CONST, T_VARIABLE, T_FUNCTION];
 
 		$currentTokenPointer = $pointer;
 		while (true) {
 			$currentTokenPointer = TokenHelper::findNext(
 				$phpcsFile,
-				$groupTokenTypes,
-				($currentToken['scope_closer'] ?? $currentTokenPointer) + 1,
-				$rootScopeToken['scope_closer']
+				[T_USE, T_ENUM_CASE, T_CONST, T_VARIABLE, T_FUNCTION],
+				$currentTokenPointer + 1,
+				$rootScopeToken['scope_closer'],
 			);
 			if ($currentTokenPointer === null) {
 				break;
@@ -302,6 +323,11 @@ private function findNextGroup(File $phpcsFile, int $pointer, array $rootScopeTo
 			}
 
 			$groupLastMemberPointer = $currentTokenPointer;
+
+			$currentTokenPointer = $currentToken['code'] === T_VARIABLE
+				// Skip to the end of the property definition
+				? PropertyHelper::getEndPointer($phpcsFile, $currentTokenPointer)
+				: ($currentToken['scope_closer'] ?? $currentTokenPointer);
 		}
 
 		if (!isset($currentGroup)) {
@@ -338,6 +364,12 @@ private function getGroupForToken(File $phpcsFile, int $pointer): string
 					return self::SPECIAL_METHODS[$name];
 				}
 
+				$methodGroup = $this->resolveMethodGroup($phpcsFile, $pointer, $name);
+
+				if ($methodGroup !== null) {
+					return $methodGroup;
+				}
+
 				$visibility = $this->getVisibilityForToken($phpcsFile, $pointer);
 				$isStatic = $this->isMemberStatic($phpcsFile, $pointer);
 				$isFinal = $this->isMethodFinal($phpcsFile, $pointer);
@@ -376,6 +408,7 @@ private function getGroupForToken(File $phpcsFile, int $pointer): string
 
 				switch ($visibility) {
 					case T_PUBLIC:
+					case T_PUBLIC_SET:
 						return $isStatic ? self::GROUP_PUBLIC_STATIC_PROPERTIES : self::GROUP_PUBLIC_PROPERTIES;
 					case T_PROTECTED:
 						return $isStatic
@@ -387,21 +420,146 @@ private function getGroupForToken(File $phpcsFile, int $pointer): string
 		}
 	}
 
-	private function getVisibilityForToken(File $phpcsFile, int $pointer): int
+	private function resolveMethodGroup(File $phpcsFile, int $pointer, string $method): ?string
+	{
+		foreach ($this->getNormalizedMethodGroups() as $group => $methodRequirements) {
+			foreach ($methodRequirements as $methodRequirement) {
+				if ($methodRequirement['name'] !== null) {
+					$requiredName = strtolower($methodRequirement['name']);
+
+					if (StringHelper::endsWith($requiredName, '*')) {
+						$methodNamePrefix = substr($requiredName, 0, -1);
+
+						if ($method === $methodNamePrefix || !StringHelper::startsWith($method, $methodNamePrefix)) {
+							continue;
+						}
+					} elseif ($method !== $requiredName) {
+						continue;
+					}
+				}
+
+				if (
+					$this->hasRequiredAnnotations($phpcsFile, $pointer, $methodRequirement['annotations'])
+					&& $this->hasRequiredAttributes($phpcsFile, $pointer, $methodRequirement['attributes'])
+				) {
+					return $group;
+				}
+			}
+		}
+
+		return null;
+	}
+
+	/**
+	 * @param array $requiredAnnotations
+	 */
+	private function hasRequiredAnnotations(File $phpcsFile, int $pointer, array $requiredAnnotations): bool
+	{
+		if ($requiredAnnotations === []) {
+			return true;
+		}
+
+		$annotations = [];
+
+		foreach (AnnotationHelper::getAnnotations($phpcsFile, $pointer) as $annotation) {
+			$annotations[$annotation->getName()] = true;
+		}
+
+		foreach ($requiredAnnotations as $requiredAnnotation) {
+			if (!array_key_exists('@' . $requiredAnnotation, $annotations)) {
+				return false;
+			}
+		}
+
+		return true;
+	}
+
+	/**
+	 * @param array $requiredAttributes
+	 */
+	private function hasRequiredAttributes(File $phpcsFile, int $pointer, array $requiredAttributes): bool
+	{
+		if ($requiredAttributes === []) {
+			return true;
+		}
+
+		$attributesClassNames = $this->getAttributeClassNamesForToken($phpcsFile, $pointer);
+
+		foreach ($requiredAttributes as $requiredAttribute) {
+			if (!array_key_exists(strtolower($requiredAttribute), $attributesClassNames)) {
+				return false;
+			}
+		}
+
+		return true;
+	}
+
+	/**
+	 * @return array
+	 */
+	private function getAttributeClassNamesForToken(File $phpcsFile, int $pointer): array
 	{
 		$tokens = $phpcsFile->getTokens();
+		$attributePointer = null;
+		$attributes = [];
 
-		$previousPointer = TokenHelper::findPrevious(
-			$phpcsFile,
-			array_merge(Tokens::$scopeModifiers, [T_OPEN_CURLY_BRACKET, T_CLOSE_CURLY_BRACKET, T_SEMICOLON]),
-			$pointer - 1
-		);
+		while (true) {
+			$attributeEndPointerCandidate = TokenHelper::findPrevious(
+				$phpcsFile,
+				[T_ATTRIBUTE_END, T_SEMICOLON, T_CLOSE_CURLY_BRACKET, T_OPEN_CURLY_BRACKET],
+				$attributePointer ?? $pointer - 1,
+			);
+
+			if (
+				$attributeEndPointerCandidate === null
+				|| $tokens[$attributeEndPointerCandidate]['code'] !== T_ATTRIBUTE_END
+			) {
+				break;
+			}
+
+			$attributePointer = $tokens[$attributeEndPointerCandidate]['attribute_opener'];
 
-		/** @var int $visibilityPointer */
-		$visibilityPointer = in_array($tokens[$previousPointer]['code'], Tokens::$scopeModifiers, true)
-			? $tokens[$previousPointer]['code']
-			: T_PUBLIC;
-		return $visibilityPointer;
+			foreach (AttributeHelper::getAttributes($phpcsFile, $attributePointer) as $attribute) {
+				$attributeClass = NamespaceHelper::resolveClassName(
+					$phpcsFile,
+					$attribute->getName(),
+					$attribute->getStartPointer(),
+				);
+				$attributeClass = ltrim($attributeClass, '\\');
+				$attributes[strtolower($attributeClass)] = $attributeClass;
+			}
+		}
+
+		return $attributes;
+	}
+
+	/**
+	 * @return int|string
+	 */
+	private function getVisibilityForToken(File $phpcsFile, int $pointer)
+	{
+		$tokens = $phpcsFile->getTokens();
+
+		$previousPointer = $pointer - 1;
+
+		$endTokenCodes = [T_OPEN_CURLY_BRACKET, T_CLOSE_CURLY_BRACKET, T_SEMICOLON];
+		$tokenCodesToSearch = [...array_values(Tokens::$scopeModifiers), ...$endTokenCodes];
+
+		do {
+			$previousPointer = TokenHelper::findPrevious($phpcsFile, $tokenCodesToSearch, $previousPointer - 1);
+
+			if (in_array($tokens[$previousPointer]['code'], $endTokenCodes, true)) {
+				// No visibility modifier found -> public
+				return T_PUBLIC;
+			}
+
+			if (in_array($tokens[$previousPointer]['code'], [T_PROTECTED_SET, T_PRIVATE_SET], true)) {
+				continue;
+			}
+
+			return $tokens[$previousPointer]['code'];
+
+		} while (true);
 	}
 
 	private function isMemberStatic(File $phpcsFile, int $pointer): bool
@@ -409,7 +567,7 @@ private function isMemberStatic(File $phpcsFile, int $pointer): bool
 		$previousPointer = TokenHelper::findPrevious(
 			$phpcsFile,
 			[T_OPEN_CURLY_BRACKET, T_CLOSE_CURLY_BRACKET, T_SEMICOLON, T_STATIC],
-			$pointer - 1
+			$pointer - 1,
 		);
 		return $phpcsFile->getTokens()[$previousPointer]['code'] === T_STATIC;
 	}
@@ -419,7 +577,7 @@ private function isMethodFinal(File $phpcsFile, int $pointer): bool
 		$previousPointer = TokenHelper::findPrevious(
 			$phpcsFile,
 			[T_OPEN_CURLY_BRACKET, T_CLOSE_CURLY_BRACKET, T_SEMICOLON, T_FINAL],
-			$pointer - 1
+			$pointer - 1,
 		);
 		return $phpcsFile->getTokens()[$previousPointer]['code'] === T_FINAL;
 	}
@@ -429,7 +587,7 @@ private function isMethodAbstract(File $phpcsFile, int $pointer): bool
 		$previousPointer = TokenHelper::findPrevious(
 			$phpcsFile,
 			[T_OPEN_CURLY_BRACKET, T_CLOSE_CURLY_BRACKET, T_SEMICOLON, T_ABSTRACT],
-			$pointer - 1
+			$pointer - 1,
 		);
 		return $phpcsFile->getTokens()[$previousPointer]['code'] === T_ABSTRACT;
 	}
@@ -481,7 +639,8 @@ private function fixIncorrectGroupOrder(
 		$linesBetween = $this->removeBlankLinesAfterMember($file, $previousMemberEndPointer, $groupStartPointer);
 
 		$newLines = str_repeat($file->eolChar, $linesBetween);
-		$file->fixer->addContentBefore($nextGroupMemberStartPointer, $groupContent . $newLines);
+
+		FixerHelper::addBefore($file, $nextGroupMemberStartPointer, $groupContent . $newLines);
 
 		$file->fixer->endChangeset();
 	}
@@ -517,15 +676,18 @@ private function findGroupEndPointer(File $phpcsFile, int $memberPointer): int
 		$tokens = $phpcsFile->getTokens();
 
 		if ($tokens[$memberPointer]['code'] === T_FUNCTION && !FunctionHelper::isAbstract($phpcsFile, $memberPointer)) {
-			$endPointer = $tokens[$memberPointer]['scope_closer'];
-		} elseif ($tokens[$memberPointer]['code'] === T_USE && array_key_exists('scope_closer', $tokens[$memberPointer])) {
-			$endPointer = $tokens[$memberPointer]['scope_closer'];
-		} else {
-			$endPointer = TokenHelper::findNext($phpcsFile, T_SEMICOLON, $memberPointer + 1);
-			assert($endPointer !== null);
+			return $tokens[$memberPointer]['scope_closer'];
+		}
+
+		if ($tokens[$memberPointer]['code'] === T_USE && array_key_exists('scope_closer', $tokens[$memberPointer])) {
+			return $tokens[$memberPointer]['scope_closer'];
 		}
 
-		return $endPointer;
+		$endPointer = TokenHelper::findNext($phpcsFile, [T_SEMICOLON, T_OPEN_CURLY_BRACKET], $memberPointer + 1);
+
+		return $tokens[$endPointer]['code'] === T_OPEN_CURLY_BRACKET
+			? $tokens[$endPointer]['bracket_closer']
+			: $endPointer;
 	}
 
 	private function removeBlankLinesAfterMember(File $phpcsFile, int $memberEndPointer, int $endPointer): int
@@ -540,13 +702,50 @@ private function removeBlankLinesAfterMember(File $phpcsFile, int $memberEndPoin
 			}
 
 			$linesToRemove++;
-			$phpcsFile->fixer->replaceToken($whitespacePointer, '');
+			FixerHelper::replace($phpcsFile, $whitespacePointer, '');
 			$whitespacePointer++;
 		}
 
 		return $linesToRemove;
 	}
 
+	/**
+	 * @return array, annotations: array}>>
+	 */
+	private function getNormalizedMethodGroups(): array
+	{
+		if ($this->normalizedMethodGroups === null) {
+			$this->normalizedMethodGroups = [];
+			$methodGroups = SniffSettingsHelper::normalizeAssociativeArray($this->methodGroups);
+
+			foreach ($methodGroups as $group => $groupDefinition) {
+				$group = strtolower((string) $group);
+				$this->normalizedMethodGroups[$group] = [];
+				$methodDefinitions = preg_split('~\\s*,\\s*~', (string) $groupDefinition, -1, PREG_SPLIT_NO_EMPTY);
+				/** @var list $methodDefinitions */
+				foreach ($methodDefinitions as $methodDefinition) {
+					$tokens = preg_split('~(?=[#@])~', $methodDefinition);
+					/** @var non-empty-list $tokens */
+					$method = array_shift($tokens);
+					$methodRequirement = [
+						'name' => $method !== '' ? $method : null,
+						'attributes' => [],
+						'annotations' => [],
+					];
+
+					foreach ($tokens as $token) {
+						$key = $token[0] === '#' ? 'attributes' : 'annotations';
+						$methodRequirement[$key][] = substr($token, 1);
+					}
+
+					$this->normalizedMethodGroups[$group][] = $methodRequirement;
+				}
+			}
+		}
+
+		return $this->normalizedMethodGroups;
+	}
+
 	/**
 	 * @return array
 	 */
@@ -585,17 +784,20 @@ private function getNormalizedGroups(): array
 				self::GROUP_MAGIC_METHODS,
 			];
 
+			$normalizedMethodGroups = $this->getNormalizedMethodGroups();
 			$normalizedGroupsWithShortcuts = [];
 			$order = 1;
 			foreach (SniffSettingsHelper::normalizeArray($this->groups) as $groupsString) {
-				/** @var list $groups */
-				$groups = preg_split('~\\s*,\\s*~', strtolower($groupsString));
+				/** @var list $groups */
+				$groups = preg_split('~\\s*,\\s*~', strtolower($groupsString), -1, PREG_SPLIT_NO_EMPTY);
 				foreach ($groups as $groupOrShortcut) {
 					$groupOrShortcut = preg_replace('~\\s+~', ' ', $groupOrShortcut);
 
 					if (
 						!in_array($groupOrShortcut, $supportedGroups, true)
 						&& !array_key_exists($groupOrShortcut, self::SHORTCUTS)
+						&& $groupOrShortcut !== self::GROUP_INVOKE_METHOD
+						&& !array_key_exists($groupOrShortcut, $normalizedMethodGroups)
 					) {
 						throw new UnsupportedClassGroupException($groupOrShortcut);
 					}
@@ -608,7 +810,11 @@ private function getNormalizedGroups(): array
 
 			$normalizedGroups = [];
 			foreach ($normalizedGroupsWithShortcuts as $groupOrShortcut => $groupOrder) {
-				if (in_array($groupOrShortcut, $supportedGroups, true)) {
+				if (
+					in_array($groupOrShortcut, $supportedGroups, true)
+					|| $groupOrShortcut === self::GROUP_INVOKE_METHOD
+					|| array_key_exists($groupOrShortcut, $normalizedMethodGroups)
+				) {
 					$normalizedGroups[$groupOrShortcut] = $groupOrder;
 				} else {
 					foreach ($this->unpackShortcut($groupOrShortcut, $supportedGroups) as $group) {
@@ -624,12 +830,16 @@ private function getNormalizedGroups(): array
 				}
 			}
 
-			if ($normalizedGroups === []) {
+			if ($normalizedGroups === [] && $normalizedMethodGroups === []) {
 				$normalizedGroups = array_flip($supportedGroups);
 			} else {
-				$missingGroups = array_diff($supportedGroups, array_keys($normalizedGroups));
+				$missingGroups = array_diff(
+					array_merge($supportedGroups, array_keys($normalizedMethodGroups)),
+					array_keys($normalizedGroups),
+				);
+
 				if ($missingGroups !== []) {
-					throw new MissingClassGroupsException($missingGroups);
+					throw new MissingClassGroupsException(array_values($missingGroups));
 				}
 			}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ConstantSpacingSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ConstantSpacingSniff.php
index 70defe2b0..0df8094c8 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ConstantSpacingSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ConstantSpacingSniff.php
@@ -59,7 +59,7 @@ protected function isNextMemberValid(File $phpcsFile, int $pointer): bool
 
 		$nextPointer = TokenHelper::findNext($phpcsFile, [T_FUNCTION, T_ENUM_CASE, T_CONST, T_VARIABLE, T_USE], $pointer + 1);
 
-		return $tokens[$nextPointer]['code'] === T_CONST;
+		return $nextPointer !== null && $tokens[$nextPointer]['code'] === T_CONST;
 	}
 
 	protected function addError(File $phpcsFile, int $pointer, int $minExpectedLines, int $maxExpectedLines, int $found): bool
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/DisallowConstructorPropertyPromotionSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/DisallowConstructorPropertyPromotionSniff.php
index fd4106386..5009f2ce3 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/DisallowConstructorPropertyPromotionSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/DisallowConstructorPropertyPromotionSniff.php
@@ -4,13 +4,12 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
+use PHP_CodeSniffer\Util\Tokens;
 use SlevomatCodingStandard\Helpers\TokenHelper;
+use function array_values;
 use function sprintf;
 use function strtolower;
 use const T_FUNCTION;
-use const T_PRIVATE;
-use const T_PROTECTED;
-use const T_PUBLIC;
 use const T_READONLY;
 use const T_VARIABLE;
 
@@ -43,9 +42,9 @@ public function process(File $phpcsFile, $functionPointer): void
 
 		$modifierPointers = TokenHelper::findNextAll(
 			$phpcsFile,
-			[T_PUBLIC, T_PROTECTED, T_PRIVATE, T_READONLY],
+			[...array_values(Tokens::$scopeModifiers), T_READONLY],
 			$tokens[$functionPointer]['parenthesis_opener'] + 1,
-			$tokens[$functionPointer]['parenthesis_closer']
+			$tokens[$functionPointer]['parenthesis_closer'],
 		);
 
 		if ($modifierPointers === []) {
@@ -58,10 +57,10 @@ public function process(File $phpcsFile, $functionPointer): void
 			$phpcsFile->addError(
 				sprintf(
 					'Constructor property promotion is disallowed, promotion of property %s found.',
-					$tokens[$variablePointer]['content']
+					$tokens[$variablePointer]['content'],
 				),
 				$variablePointer,
-				self::CODE_DISALLOWED_CONSTRUCTOR_PROPERTY_PROMOTION
+				self::CODE_DISALLOWED_CONSTRUCTOR_PROPERTY_PROMOTION,
 			);
 		}
 	}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/DisallowLateStaticBindingForConstantsSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/DisallowLateStaticBindingForConstantsSniff.php
index 2863e0877..6d24e3681 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/DisallowLateStaticBindingForConstantsSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/DisallowLateStaticBindingForConstantsSniff.php
@@ -4,6 +4,7 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use function strtolower;
 use const T_DOUBLE_COLON;
@@ -56,7 +57,7 @@ public function process(File $phpcsFile, $staticPointer): void
 		$fix = $phpcsFile->addFixableError(
 			'Late static binding for constants is disallowed.',
 			$staticPointer,
-			self::CODE_DISALLOWED_LATE_STATIC_BINDING_FOR_CONSTANT
+			self::CODE_DISALLOWED_LATE_STATIC_BINDING_FOR_CONSTANT,
 		);
 
 		if (!$fix) {
@@ -64,7 +65,7 @@ public function process(File $phpcsFile, $staticPointer): void
 		}
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->replaceToken($staticPointer, 'self');
+		FixerHelper::replace($phpcsFile, $staticPointer, 'self');
 		$phpcsFile->fixer->endChangeset();
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/DisallowMultiConstantDefinitionSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/DisallowMultiConstantDefinitionSniff.php
index 73238b08c..549f26448 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/DisallowMultiConstantDefinitionSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/DisallowMultiConstantDefinitionSniff.php
@@ -65,7 +65,7 @@ public function process(File $phpcsFile, $constantPointer): void
 		$fix = $phpcsFile->addFixableError(
 			'Use of multi constant definition is disallowed.',
 			$constantPointer,
-			self::CODE_DISALLOWED_MULTI_CONSTANT_DEFINITION
+			self::CODE_DISALLOWED_MULTI_CONSTANT_DEFINITION,
 		);
 		if (!$fix) {
 			return;
@@ -97,14 +97,14 @@ public function process(File $phpcsFile, $constantPointer): void
 
 		$phpcsFile->fixer->beginChangeset();
 
-		$phpcsFile->fixer->addContent($constantPointer, ' ');
+		FixerHelper::add($phpcsFile, $constantPointer, ' ');
 
 		FixerHelper::removeBetween($phpcsFile, $constantPointer, $pointerAfterConst);
 
 		foreach ($commaPointers as $commaPointer) {
 			FixerHelper::removeBetween($phpcsFile, $data[$commaPointer]['pointerBeforeComma'], $commaPointer);
-
-			$phpcsFile->fixer->replaceToken(
+			FixerHelper::replace(
+				$phpcsFile,
 				$commaPointer,
 				sprintf(
 					';%s%s%s%sconst ',
@@ -113,8 +113,8 @@ public function process(File $phpcsFile, $constantPointer): void
 						? sprintf('%s%s%s', $indentation, $docComment, $phpcsFile->eolChar)
 						: '',
 					$indentation,
-					$visibility !== null ? sprintf('%s ', $visibility) : ''
-				)
+					$visibility !== null ? sprintf('%s ', $visibility) : '',
+				),
 			);
 
 			FixerHelper::removeBetween($phpcsFile, $commaPointer, $data[$commaPointer]['pointerAfterComma']);
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/DisallowMultiPropertyDefinitionSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/DisallowMultiPropertyDefinitionSniff.php
index ed126df5f..1d22e672d 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/DisallowMultiPropertyDefinitionSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/DisallowMultiPropertyDefinitionSniff.php
@@ -10,18 +10,17 @@
 use SlevomatCodingStandard\Helpers\PropertyHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use function count;
+use function in_array;
 use function sprintf;
 use function trim;
 use const T_ARRAY;
 use const T_AS;
+use const T_CLASS;
 use const T_COMMA;
+use const T_CONST;
 use const T_FUNCTION;
 use const T_OPEN_SHORT_ARRAY;
-use const T_PRIVATE;
-use const T_PROTECTED;
-use const T_PUBLIC;
 use const T_SEMICOLON;
-use const T_VAR;
 use const T_VARIABLE;
 
 class DisallowMultiPropertyDefinitionSniff implements Sniff
@@ -34,23 +33,30 @@ class DisallowMultiPropertyDefinitionSniff implements Sniff
 	 */
 	public function register(): array
 	{
-		return [T_VAR, T_PUBLIC, T_PROTECTED, T_PRIVATE];
+		return TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES;
 	}
 
 	/**
 	 * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
-	 * @param int $visibilityPointer
+	 * @param int $modifierPointer
 	 */
-	public function process(File $phpcsFile, $visibilityPointer): void
+	public function process(File $phpcsFile, $modifierPointer): void
 	{
 		$tokens = $phpcsFile->getTokens();
 
-		$asPointer = TokenHelper::findPreviousEffective($phpcsFile, $visibilityPointer - 1);
+		$asPointer = TokenHelper::findPreviousEffective($phpcsFile, $modifierPointer - 1);
 		if ($tokens[$asPointer]['code'] === T_AS) {
 			return;
 		}
 
-		$propertyPointer = TokenHelper::findNext($phpcsFile, [T_VARIABLE, T_FUNCTION], $visibilityPointer + 1);
+		$nextPointer = TokenHelper::findNextEffective($phpcsFile, $modifierPointer + 1);
+		if (in_array($tokens[$nextPointer]['code'], TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES, true)) {
+			// We don't want to report the same property multiple times
+			return;
+		}
+
+		// Ignore other class members with same mofidiers
+		$propertyPointer = TokenHelper::findNext($phpcsFile, [T_VARIABLE, T_CONST, T_FUNCTION, T_CLASS], $modifierPointer + 1);
 		if (
 			$propertyPointer === null
 			|| $tokens[$propertyPointer]['code'] !== T_VARIABLE
@@ -89,32 +95,18 @@ public function process(File $phpcsFile, $visibilityPointer): void
 
 		$fix = $phpcsFile->addFixableError(
 			'Use of multi property definition is disallowed.',
-			$visibilityPointer,
-			self::CODE_DISALLOWED_MULTI_PROPERTY_DEFINITION
+			$modifierPointer,
+			self::CODE_DISALLOWED_MULTI_PROPERTY_DEFINITION,
 		);
 		if (!$fix) {
 			return;
 		}
 
-		$visibility = $tokens[$visibilityPointer]['content'];
-
-		$pointerAfterVisibility = TokenHelper::findNextEffective($phpcsFile, $visibilityPointer + 1);
+		$propertyStartPointer = PropertyHelper::getStartPointer($phpcsFile, $propertyPointer);
+		$pointerBeforeProperty = TokenHelper::findPreviousEffective($phpcsFile, $propertyPointer - 1);
 		$pointerBeforeSemicolon = TokenHelper::findPreviousEffective($phpcsFile, $semicolonPointer - 1);
 
-		$indentation = IndentationHelper::getIndentation($phpcsFile, $visibilityPointer);
-
-		$nameTokenCodes = TokenHelper::getNameTokenCodes();
-
-		$typeHint = null;
-		$typeHintStartPointer = TokenHelper::findNext($phpcsFile, $nameTokenCodes, $visibilityPointer + 1, $propertyPointer);
-		$typeHintEndPointer = null;
-		$pointerAfterTypeHint = null;
-		if ($typeHintStartPointer !== null) {
-			$typeHintEndPointer = TokenHelper::findNextExcluding($phpcsFile, $nameTokenCodes, $typeHintStartPointer + 1) - 1;
-			$typeHint = TokenHelper::getContent($phpcsFile, $typeHintStartPointer, $typeHintEndPointer);
-
-			$pointerAfterTypeHint = TokenHelper::findNextEffective($phpcsFile, $typeHintEndPointer + 1);
-		}
+		$indentation = IndentationHelper::getIndentation($phpcsFile, $propertyStartPointer);
 
 		$docCommentPointer = DocCommentHelper::findDocCommentOpenPointer($phpcsFile, $propertyPointer);
 		$docComment = $docCommentPointer !== null
@@ -129,32 +121,26 @@ public function process(File $phpcsFile, $visibilityPointer): void
 			];
 		}
 
-		$phpcsFile->fixer->beginChangeset();
-
-		$phpcsFile->fixer->addContent($visibilityPointer, ' ');
+		$propertyContent = TokenHelper::getContent($phpcsFile, $propertyStartPointer, $pointerBeforeProperty);
 
-		FixerHelper::removeBetween($phpcsFile, $visibilityPointer, $pointerAfterVisibility);
+		$phpcsFile->fixer->beginChangeset();
 
-		if ($typeHint !== null) {
-			$phpcsFile->fixer->addContent($typeHintEndPointer, ' ');
-			FixerHelper::removeBetween($phpcsFile, $typeHintEndPointer, $pointerAfterTypeHint);
-		}
+		FixerHelper::change($phpcsFile, $pointerBeforeProperty + 1, $propertyPointer - 1, ' ');
 
 		foreach ($commaPointers as $commaPointer) {
 			FixerHelper::removeBetween($phpcsFile, $data[$commaPointer]['pointerBeforeComma'], $commaPointer);
-
-			$phpcsFile->fixer->replaceToken(
+			FixerHelper::replace(
+				$phpcsFile,
 				$commaPointer,
 				sprintf(
-					';%s%s%s%s%s ',
+					';%s%s%s%s ',
 					$phpcsFile->eolChar,
 					$docComment !== null
 						? sprintf('%s%s%s', $indentation, $docComment, $phpcsFile->eolChar)
 						: '',
 					$indentation,
-					$visibility,
-					$typeHint !== null ? sprintf(' %s', $typeHint) : ''
-				)
+					$propertyContent,
+				),
 			);
 
 			FixerHelper::removeBetween($phpcsFile, $commaPointer, $data[$commaPointer]['pointerAfterComma']);
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/DisallowStringExpressionPropertyFetchSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/DisallowStringExpressionPropertyFetchSniff.php
index d34e68400..1a1a6d497 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/DisallowStringExpressionPropertyFetchSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/DisallowStringExpressionPropertyFetchSniff.php
@@ -45,7 +45,7 @@ public function process(File $phpcsFile, $objectOperatorPointer): void
 			$phpcsFile,
 			T_CONSTANT_ENCAPSED_STRING,
 			$curlyBracketOpenerPointer + 1,
-			$curlyBracketCloserPointer
+			$curlyBracketCloserPointer,
 		) !== null) {
 			return;
 		}
@@ -59,7 +59,7 @@ public function process(File $phpcsFile, $objectOperatorPointer): void
 		if (preg_match(
 			'~^(["\'])([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)\1$~',
 			$tokens[$curlyBracketOpenerPointer + 1]['content'],
-			$matches
+			$matches,
 		) !== 1) {
 			return;
 		}
@@ -67,7 +67,7 @@ public function process(File $phpcsFile, $objectOperatorPointer): void
 		$fix = $phpcsFile->addFixableError(
 			'String expression property fetch is disallowed, use identifier property fetch.',
 			$curlyBracketOpenerPointer,
-			self::CODE_DISALLOWED_STRING_EXPRESSION_PROPERTY_FETCH
+			self::CODE_DISALLOWED_STRING_EXPRESSION_PROPERTY_FETCH,
 		);
 
 		if (!$fix) {
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/EmptyLinesAroundClassBracesSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/EmptyLinesAroundClassBracesSniff.php
index 160d1d4ba..f0ffec97a 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/EmptyLinesAroundClassBracesSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/EmptyLinesAroundClassBracesSniff.php
@@ -26,11 +26,9 @@ class EmptyLinesAroundClassBracesSniff implements Sniff
 
 	public const CODE_INCORRECT_EMPTY_LINES_BEFORE_CLOSING_BRACE = 'IncorrectEmptyLinesBeforeClosingBrace';
 
-	/** @var int */
-	public $linesCountAfterOpeningBrace = 1;
+	public int $linesCountAfterOpeningBrace = 1;
 
-	/** @var int */
-	public $linesCountBeforeClosingBrace = 1;
+	public int $linesCountBeforeClosingBrace = 1;
 
 	/**
 	 * @return array
@@ -73,13 +71,13 @@ private function processOpeningBrace(File $phpcsFile, int $stackPointer): void
 				$openerPointer,
 				$lines === 0
 					? self::CODE_NO_EMPTY_LINE_AFTER_OPENING_BRACE
-					: self::CODE_MULTIPLE_EMPTY_LINES_AFTER_OPENING_BRACE
+					: self::CODE_MULTIPLE_EMPTY_LINES_AFTER_OPENING_BRACE,
 			);
 		} else {
 			$fix = $phpcsFile->addFixableError(sprintf(
 				'There must be exactly %d empty lines after %s opening brace.',
 				$this->linesCountAfterOpeningBrace,
-				$typeToken['content']
+				$typeToken['content'],
 			), $openerPointer, self::CODE_INCORRECT_EMPTY_LINES_AFTER_OPENING_BRACE);
 		}
 
@@ -98,7 +96,7 @@ private function processOpeningBrace(File $phpcsFile, int $stackPointer): void
 				if ($phpcsFile->fixer->getTokenContent($i) !== $phpcsFile->eolChar) {
 					break;
 				}
-				$phpcsFile->fixer->replaceToken($i, '');
+				FixerHelper::replace($phpcsFile, $i, '');
 			}
 		}
 
@@ -125,13 +123,13 @@ private function processClosingBrace(File $phpcsFile, int $stackPointer): void
 				$closerPointer,
 				$lines === 0
 					? self::CODE_NO_EMPTY_LINE_BEFORE_CLOSING_BRACE
-					: self::CODE_MULTIPLE_EMPTY_LINES_BEFORE_CLOSING_BRACE
+					: self::CODE_MULTIPLE_EMPTY_LINES_BEFORE_CLOSING_BRACE,
 			);
 		} else {
 			$fix = $phpcsFile->addFixableError(sprintf(
 				'There must be exactly %d empty lines before %s closing brace.',
 				$this->linesCountBeforeClosingBrace,
-				$typeToken['content']
+				$typeToken['content'],
 			), $closerPointer, self::CODE_INCORRECT_EMPTY_LINES_BEFORE_CLOSING_BRACE);
 		}
 
@@ -149,7 +147,7 @@ private function processClosingBrace(File $phpcsFile, int $stackPointer): void
 			FixerHelper::removeBetween(
 				$phpcsFile,
 				$previousPointerBeforeClosingBrace + $this->linesCountBeforeClosingBrace + 1,
-				$closerPointer
+				$closerPointer,
 			);
 		}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/EnumCaseSpacingSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/EnumCaseSpacingSniff.php
index 286d6ec27..0ad71c520 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/EnumCaseSpacingSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/EnumCaseSpacingSniff.php
@@ -34,7 +34,7 @@ protected function isNextMemberValid(File $phpcsFile, int $pointer): bool
 
 		$nextPointer = TokenHelper::findNext($phpcsFile, [T_FUNCTION, T_CONST, T_VARIABLE, T_USE, T_ENUM_CASE], $pointer + 1);
 
-		return $tokens[$nextPointer]['code'] === T_ENUM_CASE;
+		return $nextPointer !== null && $tokens[$nextPointer]['code'] === T_ENUM_CASE;
 	}
 
 	protected function addError(File $phpcsFile, int $pointer, int $minExpectedLines, int $maxExpectedLines, int $found): bool
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ForbiddenPublicPropertySniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ForbiddenPublicPropertySniff.php
index 58636062b..0082eefaa 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ForbiddenPublicPropertySniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ForbiddenPublicPropertySniff.php
@@ -4,15 +4,21 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
-use PHP_CodeSniffer\Util\Tokens;
 use SlevomatCodingStandard\Helpers\ClassHelper;
 use SlevomatCodingStandard\Helpers\PropertyHelper;
 use SlevomatCodingStandard\Helpers\StringHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
-use function array_merge;
+use function array_map;
+use function in_array;
+use const T_AS;
+use const T_CLASS;
+use const T_CONST;
+use const T_FUNCTION;
 use const T_PRIVATE;
+use const T_PRIVATE_SET;
 use const T_PROTECTED;
-use const T_VAR;
+use const T_PROTECTED_SET;
+use const T_READONLY;
 use const T_VARIABLE;
 
 final class ForbiddenPublicPropertySniff implements Sniff
@@ -20,58 +26,95 @@ final class ForbiddenPublicPropertySniff implements Sniff
 
 	public const CODE_FORBIDDEN_PUBLIC_PROPERTY = 'ForbiddenPublicProperty';
 
-	/** @var bool */
-	public $checkPromoted = false;
+	public bool $allowReadonly = false;
+
+	public bool $allowNonPublicSet = true;
+
+	public bool $checkPromoted = false;
 
 	/**
 	 * @return array
 	 */
 	public function register(): array
 	{
-		return [T_VARIABLE];
+		return TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES;
 	}
 
 	/**
 	 * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
-	 * @param int $variablePointer
+	 * @param int $pointer
 	 */
-	public function process(File $file, $variablePointer): void
+	public function process(File $phpcsFile, $pointer): void
 	{
-		if (!PropertyHelper::isProperty($file, $variablePointer, $this->checkPromoted)) {
+		$tokens = $phpcsFile->getTokens();
+
+		$asPointer = TokenHelper::findPreviousEffective($phpcsFile, $pointer - 1);
+		if ($tokens[$asPointer]['code'] === T_AS) {
 			return;
 		}
 
-		// skip Sniff classes, they have public properties for configuration (unfortunately)
-		if ($this->isSniffClass($file, $variablePointer)) {
+		$nextPointer = TokenHelper::findNextEffective($phpcsFile, $pointer + 1);
+		if (in_array($tokens[$nextPointer]['code'], TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES, true)) {
+			// We don't want to report the same property multiple times
 			return;
 		}
 
-		$scopeModifierToken = $this->getPropertyScopeModifier($file, $variablePointer);
-		if ($scopeModifierToken['code'] === T_PROTECTED || $scopeModifierToken['code'] === T_PRIVATE) {
+		// Ignore other class members with same mofidiers
+		$propertyPointer = TokenHelper::findNext($phpcsFile, [T_VARIABLE, T_CONST, T_FUNCTION, T_CLASS], $pointer + 1);
+		if (
+			$propertyPointer === null
+			|| $tokens[$propertyPointer]['code'] !== T_VARIABLE
+			|| !PropertyHelper::isProperty($phpcsFile, $propertyPointer, $this->checkPromoted)
+		) {
 			return;
 		}
 
-		$errorMessage = 'Do not use public properties. Use method access instead.';
-		$file->addError($errorMessage, $variablePointer, self::CODE_FORBIDDEN_PUBLIC_PROPERTY);
-	}
+		// Skip sniff classes, they have public properties for configuration (unfortunately)
+		if ($this->isSniffClass($phpcsFile, $propertyPointer)) {
+			return;
+		}
 
-	private function isSniffClass(File $file, int $position): bool
-	{
-		$classTokenPosition = ClassHelper::getClassPointer($file, $position);
-		$classNameToken = ClassHelper::getName($file, $classTokenPosition);
+		$propertyStartPointer = PropertyHelper::getStartPointer($phpcsFile, $propertyPointer);
 
-		return StringHelper::endsWith($classNameToken, 'Sniff');
+		$modifiersPointers = TokenHelper::findNextAll(
+			$phpcsFile,
+			TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES,
+			$propertyStartPointer,
+			$propertyPointer,
+		);
+		$modifiersCodes = array_map(static fn (int $modifierPointer) => $tokens[$modifierPointer]['code'], $modifiersPointers);
+
+		if (in_array(T_PROTECTED, $modifiersCodes, true) || in_array(T_PRIVATE, $modifiersCodes, true)) {
+			return;
+		}
+
+		if ($this->allowReadonly && in_array(T_READONLY, $modifiersCodes, true)) {
+			return;
+		}
+
+		if (
+			$this->allowNonPublicSet
+			&& (
+				in_array(T_PROTECTED_SET, $modifiersCodes, true)
+				|| in_array(T_PRIVATE_SET, $modifiersCodes, true)
+			)
+		) {
+			return;
+		}
+
+		$phpcsFile->addError(
+			'Do not use public properties. Use method access instead.',
+			$propertyPointer,
+			self::CODE_FORBIDDEN_PUBLIC_PROPERTY,
+		);
 	}
 
-	/**
-	 * @phpcsSuppress SlevomatCodingStandard.TypeHints.DisallowMixedTypeHint.DisallowedMixedTypeHint
-	 * @return array{code: int|string}
-	 */
-	private function getPropertyScopeModifier(File $file, int $position): array
+	private function isSniffClass(File $phpcsFile, int $position): bool
 	{
-		$scopeModifierPosition = TokenHelper::findPrevious($file, array_merge([T_VAR], Tokens::$scopeModifiers), $position - 1);
+		$classTokenPosition = ClassHelper::getClassPointer($phpcsFile, $position);
+		$classNameToken = ClassHelper::getName($phpcsFile, $classTokenPosition);
 
-		return $file->getTokens()[$scopeModifierPosition];
+		return StringHelper::endsWith($classNameToken, 'Sniff');
 	}
 
 }
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/MethodSpacingSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/MethodSpacingSniff.php
index afe4c7b0c..e21068788 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/MethodSpacingSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/MethodSpacingSniff.php
@@ -14,6 +14,8 @@
 use function array_key_exists;
 use function sprintf;
 use function str_repeat;
+use const T_ATTRIBUTE;
+use const T_ATTRIBUTE_END;
 use const T_FUNCTION;
 use const T_SEMICOLON;
 
@@ -22,11 +24,9 @@ class MethodSpacingSniff implements Sniff
 
 	public const CODE_INCORRECT_LINES_COUNT_BETWEEN_METHODS = 'IncorrectLinesCountBetweenMethods';
 
-	/** @var int */
-	public $minLinesCount = 1;
+	public int $minLinesCount = 1;
 
-	/** @var int */
-	public $maxLinesCount = 1;
+	public int $maxLinesCount = 1;
 
 	/**
 	 * @return array
@@ -62,17 +62,46 @@ public function process(File $phpcsFile, $methodPointer): void
 			return;
 		}
 
+		$nextMethodAttributeStartPointer = null;
 		$nextMethodDocCommentStartPointer = DocCommentHelper::findDocCommentOpenPointer($phpcsFile, $nextMethodPointer);
+
 		if (
 			$nextMethodDocCommentStartPointer !== null
 			&& $tokens[$tokens[$nextMethodDocCommentStartPointer]['comment_closer']]['line'] + 1 !== $tokens[$nextMethodPointer]['line']
 		) {
 			$nextMethodDocCommentStartPointer = null;
+		} else {
+			$nextMethodAttributeStartPointer = TokenHelper::findPrevious(
+				$phpcsFile,
+				T_ATTRIBUTE,
+				$nextMethodPointer - 1,
+				$methodEndPointer,
+			);
+
+			if ($nextMethodAttributeStartPointer !== null) {
+				do {
+					$pointerBefore = TokenHelper::findPreviousNonWhitespace(
+						$phpcsFile,
+						$nextMethodAttributeStartPointer - 1,
+						$methodEndPointer,
+					);
+
+					if ($tokens[$pointerBefore]['code'] === T_ATTRIBUTE_END) {
+						$nextMethodAttributeStartPointer = $tokens[$pointerBefore]['attribute_opener'];
+						continue;
+					}
+
+					break;
+				} while (true);
+			}
 		}
 
 		$nextMethodFirstLinePointer = $tokens[$nextMethodPointer]['line'] === $tokens[$methodEndPointer]['line']
 			? TokenHelper::findNextEffective($phpcsFile, $methodEndPointer + 1)
-			: TokenHelper::findFirstTokenOnLine($phpcsFile, $nextMethodDocCommentStartPointer ?? $nextMethodPointer);
+			: TokenHelper::findFirstTokenOnLine(
+				$phpcsFile,
+				$nextMethodDocCommentStartPointer ?? $nextMethodAttributeStartPointer ?? $nextMethodPointer,
+			);
 
 		if (TokenHelper::findNextNonWhitespace($phpcsFile, $methodEndPointer + 1, $nextMethodFirstLinePointer) !== null) {
 			return;
@@ -97,7 +126,7 @@ public function process(File $phpcsFile, $methodPointer): void
 		$fix = $phpcsFile->addFixableError(
 			sprintf($errorMessage, $this->minLinesCount, $this->maxLinesCount, $linesBetween ?? 0),
 			$methodPointer,
-			self::CODE_INCORRECT_LINES_COUNT_BETWEEN_METHODS
+			self::CODE_INCORRECT_LINES_COUNT_BETWEEN_METHODS,
 		);
 
 		if (!$fix) {
@@ -107,24 +136,33 @@ public function process(File $phpcsFile, $methodPointer): void
 		$phpcsFile->fixer->beginChangeset();
 
 		if ($linesBetween === null) {
-			$phpcsFile->fixer->addContent(
+			FixerHelper::add(
+				$phpcsFile,
 				$methodEndPointer,
 				$phpcsFile->eolChar . str_repeat($phpcsFile->eolChar, $this->minLinesCount) . IndentationHelper::getIndentation(
 					$phpcsFile,
-					TokenHelper::findFirstNonWhitespaceOnLine($phpcsFile, $methodPointer)
-				)
+					TokenHelper::findFirstNonWhitespaceOnLine($phpcsFile, $methodPointer),
+				),
 			);
 
 			FixerHelper::removeBetween($phpcsFile, $methodEndPointer, $nextMethodFirstLinePointer);
 
 		} elseif ($linesBetween > $this->maxLinesCount) {
-			$phpcsFile->fixer->addContent($methodEndPointer, str_repeat($phpcsFile->eolChar, $this->maxLinesCount + 1));
+			FixerHelper::add(
+				$phpcsFile,
+				$methodEndPointer,
+				str_repeat($phpcsFile->eolChar, $this->maxLinesCount + 1),
+			);
 
 			$firstPointerOnNextMethodLine = TokenHelper::findFirstTokenOnLine($phpcsFile, $nextMethodFirstLinePointer);
 
 			FixerHelper::removeBetween($phpcsFile, $methodEndPointer, $firstPointerOnNextMethodLine);
 		} else {
-			$phpcsFile->fixer->addContent($methodEndPointer, str_repeat($phpcsFile->eolChar, $this->minLinesCount - $linesBetween));
+			FixerHelper::add(
+				$phpcsFile,
+				$methodEndPointer,
+				str_repeat($phpcsFile->eolChar, $this->minLinesCount - $linesBetween),
+			);
 		}
 
 		$phpcsFile->fixer->endChangeset();
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/MissingClassGroupsException.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/MissingClassGroupsException.php
index 2faddecc9..36ca2bb73 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/MissingClassGroupsException.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/MissingClassGroupsException.php
@@ -15,8 +15,8 @@ public function __construct(array $groups)
 		parent::__construct(
 			sprintf(
 				'You need configure all class groups. These groups are missing from your configuration: %s.',
-				implode(', ', $groups)
-			)
+				implode(', ', $groups),
+			),
 		);
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ModernClassNameReferenceSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ModernClassNameReferenceSniff.php
index e58a453db..27f4a3747 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ModernClassNameReferenceSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ModernClassNameReferenceSniff.php
@@ -27,18 +27,17 @@ class ModernClassNameReferenceSniff implements Sniff
 	public const CODE_CLASS_NAME_REFERENCED_VIA_MAGIC_CONSTANT = 'ClassNameReferencedViaMagicConstant';
 	public const CODE_CLASS_NAME_REFERENCED_VIA_FUNCTION_CALL = 'ClassNameReferencedViaFunctionCall';
 
-	/** @var bool|null */
-	public $enableOnObjects = null;
+	public ?bool $enableOnObjects = null;
 
 	/**
 	 * @return array
 	 */
 	public function register(): array
 	{
-		$tokens = TokenHelper::getOnlyNameTokenCodes();
-		$tokens[] = T_CLASS_C;
-
-		return $tokens;
+		return [
+			T_CLASS_C,
+			...TokenHelper::ONLY_NAME_TOKEN_CODES,
+		];
 	}
 
 	/**
@@ -64,7 +63,7 @@ private function checkMagicConstant(File $phpcsFile, int $pointer): void
 		$fix = $phpcsFile->addFixableError(
 			'Class name referenced via magic constant.',
 			$pointer,
-			self::CODE_CLASS_NAME_REFERENCED_VIA_MAGIC_CONSTANT
+			self::CODE_CLASS_NAME_REFERENCED_VIA_MAGIC_CONSTANT,
 		);
 
 		if (!$fix) {
@@ -72,7 +71,7 @@ private function checkMagicConstant(File $phpcsFile, int $pointer): void
 		}
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->replaceToken($pointer, 'self::class');
+		FixerHelper::replace($phpcsFile, $pointer, 'self::class');
 		$phpcsFile->fixer->endChangeset();
 	}
 
@@ -105,7 +104,7 @@ private function checkFunctionCall(File $phpcsFile, int $functionPointer): void
 		$parameterPointer = TokenHelper::findNextEffective(
 			$phpcsFile,
 			$openParenthesisPointer + 1,
-			$tokens[$openParenthesisPointer]['parenthesis_closer']
+			$tokens[$openParenthesisPointer]['parenthesis_closer'],
 		);
 
 		$isObjectParameter = static function () use ($phpcsFile, $tokens, $openParenthesisPointer, $parameterPointer): bool {
@@ -143,9 +142,8 @@ private function checkFunctionCall(File $phpcsFile, int $functionPointer): void
 					return;
 				}
 
-				/** @var int $classPointer */
 				$classPointer = FunctionHelper::findClassPointer($phpcsFile, $functionPointer);
-				if (!ClassHelper::isFinal($phpcsFile, $classPointer)) {
+				if ($classPointer === null || !ClassHelper::isFinal($phpcsFile, $classPointer)) {
 					return;
 				}
 			}
@@ -158,7 +156,7 @@ private function checkFunctionCall(File $phpcsFile, int $functionPointer): void
 		$fix = $phpcsFile->addFixableError(
 			sprintf('Class name referenced via call of function %s().', $functionName),
 			$functionPointer,
-			self::CODE_CLASS_NAME_REFERENCED_VIA_FUNCTION_CALL
+			self::CODE_CLASS_NAME_REFERENCED_VIA_FUNCTION_CALL,
 		);
 
 		if (!$fix) {
@@ -167,7 +165,7 @@ private function checkFunctionCall(File $phpcsFile, int $functionPointer): void
 
 		$phpcsFile->fixer->beginChangeset();
 		if ($tokens[$functionPointer - 1]['code'] === T_NS_SEPARATOR) {
-			$phpcsFile->fixer->replaceToken($functionPointer - 1, '');
+			FixerHelper::replace($phpcsFile, $functionPointer - 1, '');
 		}
 
 		FixerHelper::change($phpcsFile, $functionPointer, $tokens[$openParenthesisPointer]['parenthesis_closer'], $fixedContent);
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ParentCallSpacingSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ParentCallSpacingSniff.php
index 2755349bc..95922d208 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ParentCallSpacingSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/ParentCallSpacingSniff.php
@@ -25,17 +25,13 @@
 class ParentCallSpacingSniff extends AbstractControlStructureSpacing
 {
 
-	/** @var int */
-	public $linesCountBefore = 1;
+	public int $linesCountBefore = 1;
 
-	/** @var int */
-	public $linesCountBeforeFirst = 0;
+	public int $linesCountBeforeFirst = 0;
 
-	/** @var int */
-	public $linesCountAfter = 1;
+	public int $linesCountAfter = 1;
 
-	/** @var int */
-	public $linesCountAfterLast = 0;
+	public int $linesCountAfterLast = 0;
 
 	/**
 	 * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
@@ -63,7 +59,7 @@ public function process(File $phpcsFile, $parentPointer): void
 			Tokens::$assignmentTokens,
 			Tokens::$equalityTokens,
 			Tokens::$booleanOperators,
-			[T_RETURN, T_YIELD, T_YIELD_FROM, T_COLON, T_STRING_CONCAT, T_INLINE_THEN, T_INLINE_ELSE, T_COALESCE, T_MATCH_ARROW]
+			[T_RETURN, T_YIELD, T_YIELD_FROM, T_COLON, T_STRING_CONCAT, T_INLINE_THEN, T_INLINE_ELSE, T_COALESCE, T_MATCH_ARROW],
 		);
 		if (in_array($tokens[$previousPointer]['code'], $tokensToIgnore, true)) {
 			return;
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/PropertyDeclarationSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/PropertyDeclarationSniff.php
index 48dd3ccbf..8d45b2684 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/PropertyDeclarationSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/PropertyDeclarationSniff.php
@@ -13,6 +13,7 @@
 use function array_key_exists;
 use function array_keys;
 use function array_map;
+use function array_search;
 use function asort;
 use function count;
 use function implode;
@@ -20,16 +21,26 @@
 use function preg_split;
 use function sprintf;
 use function strtolower;
+use const T_ABSTRACT;
 use const T_AS;
+use const T_CLASS;
 use const T_CONST;
 use const T_DOUBLE_COLON;
+use const T_FINAL;
 use const T_FUNCTION;
 use const T_NULLABLE;
+use const T_OPEN_CURLY_BRACKET;
+use const T_OPEN_PARENTHESIS;
 use const T_PRIVATE;
+use const T_PRIVATE_SET;
 use const T_PROTECTED;
+use const T_PROTECTED_SET;
 use const T_PUBLIC;
+use const T_PUBLIC_SET;
 use const T_READONLY;
+use const T_SEMICOLON;
 use const T_STATIC;
+use const T_TYPE_UNION;
 use const T_VAR;
 use const T_VARIABLE;
 use const T_WHITESPACE;
@@ -54,23 +65,21 @@ class PropertyDeclarationSniff implements Sniff
 	public const CODE_MULTIPLE_SPACES_BETWEEN_MODIFIERS = 'MultipleSpacesBetweenModifiers';
 
 	/** @var list|null */
-	public $modifiersOrder = [];
+	public ?array $modifiersOrder = [];
 
-	/** @var bool */
-	public $checkPromoted = false;
+	public bool $checkPromoted = false;
 
-	/** @var bool */
-	public $enableMultipleSpacesBetweenModifiersCheck = false;
+	public bool $enableMultipleSpacesBetweenModifiersCheck = false;
 
 	/** @var array>|null */
-	private $normalizedModifiersOrder = null;
+	private ?array $normalizedModifiersOrder = null;
 
 	/**
 	 * @return array
 	 */
 	public function register(): array
 	{
-		return TokenHelper::$propertyModifiersTokenCodes;
+		return TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES;
 	}
 
 	/**
@@ -87,17 +96,30 @@ public function process(File $phpcsFile, $modifierPointer): void
 		}
 
 		$nextPointer = TokenHelper::findNextEffective($phpcsFile, $modifierPointer + 1);
-		if (in_array($tokens[$nextPointer]['code'], TokenHelper::$propertyModifiersTokenCodes, true)) {
-			// We don't want to report the same property twice
+		if (in_array($tokens[$nextPointer]['code'], TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES, true)) {
+			// We don't want to report the same property multiple times
 			return;
 		}
 
-		if ($tokens[$nextPointer]['code'] === T_DOUBLE_COLON) {
-			// Ignore static::
-			return;
+		if ($tokens[$modifierPointer]['code'] === T_STATIC) {
+			if ($tokens[$nextPointer]['code'] === T_DOUBLE_COLON) {
+				// Ignore static::
+				return;
+			}
+
+			if ($tokens[$nextPointer]['code'] === T_OPEN_PARENTHESIS) {
+				// Ignore static()
+				return;
+			}
+
+			if (in_array($tokens[$nextPointer]['code'], [T_OPEN_CURLY_BRACKET, T_SEMICOLON, T_TYPE_UNION], true)) {
+				// Ignore "static" as return type hint of method
+				return;
+			}
 		}
 
-		$propertyPointer = TokenHelper::findNext($phpcsFile, [T_FUNCTION, T_CONST, T_VARIABLE], $modifierPointer + 1);
+		// Ignore other class members with same mofidiers
+		$propertyPointer = TokenHelper::findNext($phpcsFile, [T_CLASS, T_FUNCTION, T_CONST, T_VARIABLE], $modifierPointer + 1);
 
 		if ($propertyPointer === null || $tokens[$propertyPointer]['code'] !== T_VARIABLE) {
 			return;
@@ -107,15 +129,7 @@ public function process(File $phpcsFile, $modifierPointer): void
 			return;
 		}
 
-		$firstModifierPointer = $modifierPointer;
-		do {
-			$previousPointer = TokenHelper::findPreviousEffective($phpcsFile, $firstModifierPointer - 1);
-			if (!in_array($tokens[$previousPointer]['code'], TokenHelper::$propertyModifiersTokenCodes, true)) {
-				break;
-			}
-
-			$firstModifierPointer = $previousPointer;
-		} while (true);
+		$firstModifierPointer = PropertyHelper::getStartPointer($phpcsFile, $propertyPointer);
 
 		$this->checkModifiersOrder($phpcsFile, $propertyPointer, $firstModifierPointer, $modifierPointer);
 		$this->checkSpacesBetweenModifiers($phpcsFile, $propertyPointer, $firstModifierPointer, $modifierPointer);
@@ -126,9 +140,9 @@ private function checkModifiersOrder(File $phpcsFile, int $propertyPointer, int
 	{
 		$modifiersPointers = TokenHelper::findNextAll(
 			$phpcsFile,
-			TokenHelper::$propertyModifiersTokenCodes,
+			TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES,
 			$firstModifierPointer,
-			$lastModifierPointer + 1
+			$lastModifierPointer + 1,
 		);
 
 		if (count($modifiersPointers) < 2) {
@@ -136,19 +150,25 @@ private function checkModifiersOrder(File $phpcsFile, int $propertyPointer, int
 		}
 
 		$tokens = $phpcsFile->getTokens();
+
 		$modifiersGroups = $this->getNormalizedModifiersOrder();
 
 		$expectedModifiersPositions = [];
 		foreach ($modifiersPointers as $modifierPointer) {
+			$position = 0;
+
 			for ($i = 0; $i < count($modifiersGroups); $i++) {
-				if (in_array($tokens[$modifierPointer]['code'], $modifiersGroups[$i], true)) {
-					$expectedModifiersPositions[$modifierPointer] = $i;
+				$modifierPositionInGroup = array_search($tokens[$modifierPointer]['code'], $modifiersGroups[$i], true);
+				if ($modifierPositionInGroup !== false) {
+					$expectedModifiersPositions[$modifierPointer] = $position + $modifierPositionInGroup;
 					continue 2;
 				}
+
+				$position += count($modifiersGroups[$i]);
 			}
 
 			// Modifier position is not defined so add it to the end
-			$expectedModifiersPositions[$modifierPointer] = count($modifiersGroups);
+			$expectedModifiersPositions[$modifierPointer] = $position;
 		}
 
 		$error = false;
@@ -166,15 +186,14 @@ private function checkModifiersOrder(File $phpcsFile, int $propertyPointer, int
 			return;
 		}
 
-		$actualModifiers = array_map(static function (int $modifierPointer) use ($tokens): string {
-			return $tokens[$modifierPointer]['content'];
-		}, $modifiersPointers);
+		$actualModifiers = array_map(static fn (int $modifierPointer): string => $tokens[$modifierPointer]['content'], $modifiersPointers);
 		$actualModifiersFormatted = implode(' ', $actualModifiers);
 
 		asort($expectedModifiersPositions);
-		$expectedModifiers = array_map(static function (int $modifierPointer) use ($tokens): string {
-			return $tokens[$modifierPointer]['content'];
-		}, array_keys($expectedModifiersPositions));
+		$expectedModifiers = array_map(
+			static fn (int $modifierPointer): string => $tokens[$modifierPointer]['content'],
+			array_keys($expectedModifiersPositions),
+		);
 		$expectedModifiersFormatted = implode(' ', $expectedModifiers);
 
 		$fix = $phpcsFile->addFixableError(
@@ -182,10 +201,10 @@ private function checkModifiersOrder(File $phpcsFile, int $propertyPointer, int
 				'Incorrect order of modifiers "%s" of property %s, expected "%s".',
 				$actualModifiersFormatted,
 				$tokens[$propertyPointer]['content'],
-				$expectedModifiersFormatted
+				$expectedModifiersFormatted,
 			),
 			$firstModifierPointer,
-			self::CODE_INCORRECT_ORDER_OF_MODIFIERS
+			self::CODE_INCORRECT_ORDER_OF_MODIFIERS,
 		);
 		if (!$fix) {
 			return;
@@ -211,9 +230,9 @@ private function checkSpacesBetweenModifiers(
 
 		$modifiersPointers = TokenHelper::findNextAll(
 			$phpcsFile,
-			TokenHelper::$propertyModifiersTokenCodes,
+			TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES,
 			$firstModifierPointer,
-			$lastModifierPointer + 1
+			$lastModifierPointer + 1,
 		);
 
 		if (count($modifiersPointers) < 2) {
@@ -238,15 +257,16 @@ private function checkSpacesBetweenModifiers(
 		$fix = $phpcsFile->addFixableError(
 			sprintf('There must be exactly one space between modifiers of property %s.', $tokens[$propertyPointer]['content']),
 			$firstModifierPointer,
-			self::CODE_MULTIPLE_SPACES_BETWEEN_MODIFIERS
+			self::CODE_MULTIPLE_SPACES_BETWEEN_MODIFIERS,
 		);
 		if (!$fix) {
 			return;
 		}
 
-		$expectedModifiers = array_map(static function (int $modifierPointer) use ($tokens): string {
-			return $tokens[$modifierPointer]['content'];
-		}, $modifiersPointers);
+		$expectedModifiers = array_map(
+			static fn (int $modifierPointer): string => $tokens[$modifierPointer]['content'],
+			$modifiersPointers,
+		);
 		$expectedModifiersFormatted = implode(' ', $expectedModifiers);
 
 		$phpcsFile->fixer->beginChangeset();
@@ -260,9 +280,9 @@ private function checkTypeHintSpacing(File $phpcsFile, int $propertyPointer, int
 	{
 		$typeHintEndPointer = TokenHelper::findPrevious(
 			$phpcsFile,
-			TokenHelper::getTypeHintTokenCodes(),
+			TokenHelper::TYPE_HINT_TOKEN_CODES,
 			$propertyPointer - 1,
-			$lastModifierPointer
+			$lastModifierPointer,
 		);
 		if ($typeHintEndPointer === null) {
 			return;
@@ -284,14 +304,14 @@ private function checkTypeHintSpacing(File $phpcsFile, int $propertyPointer, int
 			$fix = $phpcsFile->addFixableError($errorMessage, $typeHintEndPointer, $errorCode);
 			if ($fix) {
 				$phpcsFile->fixer->beginChangeset();
-				$phpcsFile->fixer->addContent($lastModifierPointer, ' ');
+				FixerHelper::add($phpcsFile, $lastModifierPointer, ' ');
 				$phpcsFile->fixer->endChangeset();
 			}
 		} elseif ($tokens[$lastModifierPointer + 1]['content'] !== ' ') {
 			if ($nullabilitySymbolPointer !== null) {
 				$errorMessage = sprintf(
 					'There must be exactly one space before type hint nullability symbol of property %s.',
-					$propertyName
+					$propertyName,
 				);
 				$errorCode = self::CODE_MULTIPLE_SPACES_BEFORE_NULLABILITY_SYMBOL;
 			} else {
@@ -302,7 +322,7 @@ private function checkTypeHintSpacing(File $phpcsFile, int $propertyPointer, int
 			$fix = $phpcsFile->addFixableError($errorMessage, $lastModifierPointer, $errorCode);
 			if ($fix) {
 				$phpcsFile->fixer->beginChangeset();
-				$phpcsFile->fixer->replaceToken($lastModifierPointer + 1, ' ');
+				FixerHelper::replace($phpcsFile, $lastModifierPointer + 1, ' ');
 				$phpcsFile->fixer->endChangeset();
 			}
 		}
@@ -311,22 +331,22 @@ private function checkTypeHintSpacing(File $phpcsFile, int $propertyPointer, int
 			$fix = $phpcsFile->addFixableError(
 				sprintf('There must be exactly one space between type hint and property %s.', $propertyName),
 				$typeHintEndPointer,
-				self::CODE_NO_SPACE_BETWEEN_TYPE_HINT_AND_PROPERTY
+				self::CODE_NO_SPACE_BETWEEN_TYPE_HINT_AND_PROPERTY,
 			);
 			if ($fix) {
 				$phpcsFile->fixer->beginChangeset();
-				$phpcsFile->fixer->addContent($typeHintEndPointer, ' ');
+				FixerHelper::add($phpcsFile, $typeHintEndPointer, ' ');
 				$phpcsFile->fixer->endChangeset();
 			}
 		} elseif ($tokens[$typeHintEndPointer + 1]['content'] !== ' ') {
 			$fix = $phpcsFile->addFixableError(
 				sprintf('There must be exactly one space between type hint and property %s.', $propertyName),
 				$typeHintEndPointer,
-				self::CODE_MULTIPLE_SPACES_BETWEEN_TYPE_HINT_AND_PROPERTY
+				self::CODE_MULTIPLE_SPACES_BETWEEN_TYPE_HINT_AND_PROPERTY,
 			);
 			if ($fix) {
 				$phpcsFile->fixer->beginChangeset();
-				$phpcsFile->fixer->replaceToken($typeHintEndPointer + 1, ' ');
+				FixerHelper::replace($phpcsFile, $typeHintEndPointer + 1, ' ');
 				$phpcsFile->fixer->endChangeset();
 			}
 		}
@@ -342,14 +362,14 @@ private function checkTypeHintSpacing(File $phpcsFile, int $propertyPointer, int
 		$fix = $phpcsFile->addFixableError(
 			sprintf('There must be no whitespace between type hint nullability symbol and type hint of property %s.', $propertyName),
 			$typeHintStartPointer,
-			self::CODE_WHITESPACE_AFTER_NULLABILITY_SYMBOL
+			self::CODE_WHITESPACE_AFTER_NULLABILITY_SYMBOL,
 		);
 		if (!$fix) {
 			return;
 		}
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->replaceToken($nullabilitySymbolPointer + 1, '');
+		FixerHelper::replace($phpcsFile, $nullabilitySymbolPointer + 1, '');
 		$phpcsFile->fixer->endChangeset();
 	}
 
@@ -363,7 +383,8 @@ private function getNormalizedModifiersOrder(): array
 
 			if ($modifiersGroups === []) {
 				$modifiersGroups = [
-					'var, public, protected, private',
+					'final, abstract',
+					'var, public, public(set), protected, protected(set), private, private(set)',
 					'static, readonly',
 				];
 			}
@@ -371,10 +392,15 @@ private function getNormalizedModifiersOrder(): array
 			$this->normalizedModifiersOrder = [];
 
 			$mapping = [
+				'final' => T_FINAL,
+				'abstract' => T_ABSTRACT,
 				'var' => T_VAR,
 				'public' => T_PUBLIC,
+				'public(set)' => T_PUBLIC_SET,
 				'protected' => T_PROTECTED,
+				'protected(set)' => T_PROTECTED_SET,
 				'private' => T_PRIVATE,
+				'private(set)' => T_PRIVATE_SET,
 				'static' => T_STATIC,
 				'readonly' => T_READONLY,
 			];
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/PropertySpacingSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/PropertySpacingSniff.php
index e7adf9697..040c45b97 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/PropertySpacingSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/PropertySpacingSniff.php
@@ -8,15 +8,9 @@
 use function in_array;
 use function sprintf;
 use const T_AS;
+use const T_CLASS;
 use const T_CONST;
 use const T_FUNCTION;
-use const T_PRIVATE;
-use const T_PROTECTED;
-use const T_PUBLIC;
-use const T_READONLY;
-use const T_STATIC;
-use const T_USE;
-use const T_VAR;
 use const T_VARIABLE;
 
 class PropertySpacingSniff extends AbstractPropertyConstantAndEnumCaseSpacing
@@ -29,7 +23,7 @@ class PropertySpacingSniff extends AbstractPropertyConstantAndEnumCaseSpacing
 	 */
 	public function register(): array
 	{
-		return [T_VAR, T_PUBLIC, T_PROTECTED, T_PRIVATE, T_READONLY, T_STATIC];
+		return TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES;
 	}
 
 	/**
@@ -46,12 +40,13 @@ public function process(File $phpcsFile, $pointer): int
 		}
 
 		$nextPointer = TokenHelper::findNextEffective($phpcsFile, $pointer + 1);
-		if (in_array($tokens[$nextPointer]['code'], [T_VAR, T_PUBLIC, T_PROTECTED, T_PRIVATE, T_READONLY, T_STATIC], true)) {
-			// We don't want to report the same property twice
+		if (in_array($tokens[$nextPointer]['code'], TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES, true)) {
+			// We don't want to report the same property multiple times
 			return $nextPointer;
 		}
 
-		$propertyPointer = TokenHelper::findNext($phpcsFile, [T_VARIABLE, T_FUNCTION, T_CONST, T_USE], $pointer + 1);
+		// Ignore other class members with same mofidiers
+		$propertyPointer = TokenHelper::findNext($phpcsFile, [T_VARIABLE, T_FUNCTION, T_CONST, T_CLASS], $pointer + 1);
 		if (
 			$propertyPointer === null
 			|| $tokens[$propertyPointer]['code'] !== T_VARIABLE
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/RequireAbstractOrFinalSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/RequireAbstractOrFinalSniff.php
index 6b21041a3..1442e7be3 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/RequireAbstractOrFinalSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/RequireAbstractOrFinalSniff.php
@@ -4,6 +4,7 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use function in_array;
 use const T_ABSTRACT;
@@ -47,7 +48,7 @@ public function process(File $phpcsFile, $classPointer): void
 		$fix = $phpcsFile->addFixableError(
 			'All classes should be declared using either the "abstract" or "final" keyword.',
 			$classPointer,
-			self::CODE_NO_ABSTRACT_OR_FINAL
+			self::CODE_NO_ABSTRACT_OR_FINAL,
 		);
 
 		if (!$fix) {
@@ -55,7 +56,7 @@ public function process(File $phpcsFile, $classPointer): void
 		}
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->addContentBefore($classPointer, 'final ');
+		FixerHelper::addBefore($phpcsFile, $classPointer, 'final ');
 		$phpcsFile->fixer->endChangeset();
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/RequireConstructorPropertyPromotionSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/RequireConstructorPropertyPromotionSniff.php
index d1736c8aa..436cdb345 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/RequireConstructorPropertyPromotionSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/RequireConstructorPropertyPromotionSniff.php
@@ -16,6 +16,7 @@
 use SlevomatCodingStandard\Helpers\TypeHint;
 use function array_filter;
 use function array_reverse;
+use function array_values;
 use function count;
 use function in_array;
 use function sprintf;
@@ -38,7 +39,6 @@
 use const T_OBJECT_OPERATOR;
 use const T_OPEN_CURLY_BRACKET;
 use const T_OPEN_PARENTHESIS;
-use const T_READONLY;
 use const T_SEMICOLON;
 use const T_SWITCH;
 use const T_VARIABLE;
@@ -48,8 +48,7 @@ class RequireConstructorPropertyPromotionSniff implements Sniff
 
 	public const CODE_REQUIRED_CONSTRUCTOR_PROPERTY_PROMOTION = 'RequiredConstructorPropertyPromotion';
 
-	/** @var bool|null */
-	public $enable = null;
+	public ?bool $enable = null;
 
 	/**
 	 * @return array
@@ -93,9 +92,9 @@ public function process(File $phpcsFile, $functionPointer): void
 		foreach ($parameterPointers as $parameterPointer) {
 			$pointerBefore = TokenHelper::findPrevious($phpcsFile, [T_COMMA, T_OPEN_PARENTHESIS], $parameterPointer - 1);
 
-			$visibilityPointer = TokenHelper::findNextEffective($phpcsFile, $pointerBefore + 1);
+			$modifierPointer = TokenHelper::findNextEffective($phpcsFile, $pointerBefore + 1);
 
-			if (in_array($tokens[$visibilityPointer]['code'], Tokens::$scopeModifiers, true)) {
+			if (in_array($tokens[$modifierPointer]['code'], TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES, true)) {
 				continue;
 			}
 
@@ -139,6 +138,12 @@ public function process(File $phpcsFile, $functionPointer): void
 					continue;
 				}
 
+				$propertyEndPointer = PropertyHelper::getEndPointer($phpcsFile, $propertyPointer);
+				if ($tokens[$propertyEndPointer]['code'] === T_CLOSE_CURLY_BRACKET) {
+					// Ignore property with hooks
+					continue;
+				}
+
 				if ($this->isPropertyDocCommentUseful($phpcsFile, $propertyPointer)) {
 					continue;
 				}
@@ -165,7 +170,7 @@ public function process(File $phpcsFile, $functionPointer): void
 				$fix = $phpcsFile->addFixableError(
 					sprintf('Required promotion of property %s.', $propertyName),
 					$propertyPointer,
-					self::CODE_REQUIRED_CONSTRUCTOR_PROPERTY_PROMOTION
+					self::CODE_REQUIRED_CONSTRUCTOR_PROPERTY_PROMOTION,
 				);
 
 				if (!$fix) {
@@ -175,20 +180,18 @@ public function process(File $phpcsFile, $functionPointer): void
 				$propertyDocCommentOpenerPointer = DocCommentHelper::findDocCommentOpenPointer($phpcsFile, $propertyPointer);
 				$pointerBeforeProperty = TokenHelper::findFirstTokenOnLine(
 					$phpcsFile,
-					$propertyDocCommentOpenerPointer ?? $propertyPointer
+					$propertyDocCommentOpenerPointer ?? $propertyPointer,
 				);
-				$propertyEndPointer = TokenHelper::findNext($phpcsFile, T_SEMICOLON, $propertyPointer + 1);
+				$propertyStartPointer = PropertyHelper::getStartPointer($phpcsFile, $propertyPointer);
+				$propertyEndPointer = PropertyHelper::getEndPointer($phpcsFile, $propertyPointer);
 
-				$visibilityPointer = TokenHelper::findPrevious(
+				$modifiersPointers = TokenHelper::findNextAll(
 					$phpcsFile,
-					Tokens::$scopeModifiers,
-					$propertyPointer - 1,
-					$pointerBeforeProperty
+					TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES,
+					$propertyStartPointer,
+					$propertyPointer,
 				);
-				$visibility = $tokens[$visibilityPointer]['content'];
-
-				$readonlyPointer = TokenHelper::findPrevious($phpcsFile, T_READONLY, $propertyPointer - 1, $pointerBeforeProperty);
-				$isReadonly = $readonlyPointer !== null;
+				$modifiers = TokenHelper::getContent($phpcsFile, $modifiersPointers[0], $modifiersPointers[count($modifiersPointers) - 1]);
 
 				$propertyEqualPointer = TokenHelper::findNext($phpcsFile, T_EQUAL, $propertyPointer + 1, $propertyEndPointer);
 				$propertyDefaultValue = $propertyEqualPointer !== null
@@ -198,10 +201,14 @@ public function process(File $phpcsFile, $functionPointer): void
 				$propertyEndPointer = TokenHelper::findNext($phpcsFile, T_SEMICOLON, $propertyPointer + 1);
 				$pointerAfterProperty = TokenHelper::findFirstTokenOnLine(
 					$phpcsFile,
-					TokenHelper::findNextNonWhitespace($phpcsFile, $propertyEndPointer + 1)
+					TokenHelper::findNextNonWhitespace($phpcsFile, $propertyEndPointer + 1),
 				);
 
-				$pointerBeforeParameterStart = TokenHelper::findPrevious($phpcsFile, [T_COMMA, T_OPEN_PARENTHESIS], $parameterPointer - 1);
+				$pointerBeforeParameterStart = TokenHelper::findPrevious(
+					$phpcsFile,
+					[T_COMMA, T_OPEN_PARENTHESIS, T_ATTRIBUTE_END],
+					$parameterPointer - 1,
+				);
 				$parameterStartPointer = TokenHelper::findNextEffective($phpcsFile, $pointerBeforeParameterStart + 1);
 
 				$parameterEqualPointer = TokenHelper::findNextEffective($phpcsFile, $parameterPointer + 1);
@@ -214,14 +221,14 @@ public function process(File $phpcsFile, $functionPointer): void
 
 				FixerHelper::removeBetweenIncluding($phpcsFile, $pointerBeforeProperty, $pointerAfterProperty - 1);
 
-				if ($isReadonly) {
-					$phpcsFile->fixer->addContentBefore($parameterStartPointer, 'readonly ');
-				}
-
-				$phpcsFile->fixer->addContentBefore($parameterStartPointer, sprintf('%s ', $visibility));
+				FixerHelper::addBefore($phpcsFile, $parameterStartPointer, sprintf('%s ', $modifiers));
 
 				if (!$parameterHasDefaultValue && $propertyDefaultValue !== null) {
-					$phpcsFile->fixer->addContent($parameterPointer, sprintf(' = %s', $propertyDefaultValue));
+					FixerHelper::add(
+						$phpcsFile,
+						$parameterPointer,
+						sprintf(' = %s', $propertyDefaultValue),
+					);
 				}
 
 				FixerHelper::removeBetweenIncluding($phpcsFile, $pointerBeforeAssignment, $pointerAfterAssignment);
@@ -289,7 +296,7 @@ private function getParameterPointers(File $phpcsFile, int $functionPointer): ar
 			$phpcsFile,
 			T_VARIABLE,
 			$tokens[$functionPointer]['parenthesis_opener'] + 1,
-			$tokens[$functionPointer]['parenthesis_closer']
+			$tokens[$functionPointer]['parenthesis_closer'],
 		);
 	}
 
@@ -300,17 +307,15 @@ private function getPropertyPointers(File $phpcsFile, int $classPointer): array
 	{
 		$tokens = $phpcsFile->getTokens();
 
-		return array_filter(
+		return array_values(array_filter(
 			TokenHelper::findNextAll(
 				$phpcsFile,
 				T_VARIABLE,
 				$tokens[$classPointer]['scope_opener'] + 1,
-				$tokens[$classPointer]['scope_closer']
+				$tokens[$classPointer]['scope_closer'],
 			),
-			static function (int $variablePointer) use ($phpcsFile): bool {
-				return PropertyHelper::isProperty($phpcsFile, $variablePointer);
-			}
-		);
+			static fn (int $variablePointer): bool => PropertyHelper::isProperty($phpcsFile, $variablePointer),
+		));
 	}
 
 	private function isPropertyDocCommentUseful(File $phpcsFile, int $propertyPointer): bool
@@ -340,7 +345,7 @@ private function isPropertyWithAttribute(File $phpcsFile, int $propertyPointer):
 		$previousPointer = TokenHelper::findPrevious(
 			$phpcsFile,
 			[T_ATTRIBUTE_END, T_SEMICOLON, T_OPEN_CURLY_BRACKET, T_CLOSE_CURLY_BRACKET],
-			$propertyPointer - 1
+			$propertyPointer - 1,
 		);
 
 		return $tokens[$previousPointer]['code'] === T_ATTRIBUTE_END;
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/RequireMultiLineMethodSignatureSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/RequireMultiLineMethodSignatureSniff.php
index abac22a86..d1f6fe9ea 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/RequireMultiLineMethodSignatureSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/RequireMultiLineMethodSignatureSniff.php
@@ -22,23 +22,21 @@ class RequireMultiLineMethodSignatureSniff extends AbstractMethodSignature
 	public const CODE_REQUIRED_MULTI_LINE_SIGNATURE = 'RequiredMultiLineSignature';
 	private const DEFAULT_MIN_LINE_LENGTH = 121;
 
-	/** @var int|null */
-	public $minLineLength = null;
+	public ?int $minLineLength = null;
 
-	/** @var int|null */
-	public $minParametersCount = null;
+	public ?int $minParametersCount = null;
 
 	/** @var list */
-	public $includedMethodPatterns = [];
+	public array $includedMethodPatterns = [];
 
 	/** @var list|null */
-	public $includedMethodNormalizedPatterns;
+	public ?array $includedMethodNormalizedPatterns = null;
 
 	/** @var list */
-	public $excludedMethodPatterns = [];
+	public array $excludedMethodPatterns = [];
 
 	/** @var list|null */
-	public $excludedMethodNormalizedPatterns;
+	public ?array $excludedMethodNormalizedPatterns = null;
 
 	/**
 	 * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
@@ -77,7 +75,6 @@ public function process(File $phpcsFile, $methodPointer): void
 		}
 
 		$signature = $this->getSignature($phpcsFile, $signatureStartPointer, $signatureEndPointer);
-		$signatureWithoutTabIndentation = $this->getSignatureWithoutTabs($phpcsFile, $signature);
 		$methodName = FunctionHelper::getName($phpcsFile, $methodPointer);
 
 		if (
@@ -94,7 +91,7 @@ public function process(File $phpcsFile, $methodPointer): void
 			return;
 		}
 
-		if ($this->minLineLength !== null && $this->minLineLength !== 0 && strlen($signatureWithoutTabIndentation) < $this->minLineLength) {
+		if ($this->minLineLength !== null && $this->minLineLength !== 0 && strlen($signature) < $this->minLineLength) {
 			return;
 		}
 
@@ -117,18 +114,22 @@ public function process(File $phpcsFile, $methodPointer): void
 				$phpcsFile,
 				T_COMMA,
 				$parameter['token'] - 1,
-				$tokens[$methodPointer]['parenthesis_opener']
+				$tokens[$methodPointer]['parenthesis_opener'],
 			);
 			if ($pointerBeforeParameter === null) {
 				$pointerBeforeParameter = $tokens[$methodPointer]['parenthesis_opener'];
 			}
 
-			$phpcsFile->fixer->addContent($pointerBeforeParameter, $phpcsFile->eolChar . IndentationHelper::addIndentation($indentation));
+			FixerHelper::add(
+				$phpcsFile,
+				$pointerBeforeParameter,
+				$phpcsFile->eolChar . IndentationHelper::addIndentation($phpcsFile, $indentation),
+			);
 
 			FixerHelper::removeWhitespaceAfter($phpcsFile, $pointerBeforeParameter);
 		}
 
-		$phpcsFile->fixer->addContentBefore($tokens[$methodPointer]['parenthesis_closer'], $phpcsFile->eolChar . $indentation);
+		FixerHelper::addBefore($phpcsFile, $tokens[$methodPointer]['parenthesis_closer'], $phpcsFile->eolChar . $indentation);
 
 		$phpcsFile->fixer->endChangeset();
 	}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/RequireSelfReferenceSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/RequireSelfReferenceSniff.php
index 50c7b3332..70a1628d8 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/RequireSelfReferenceSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/RequireSelfReferenceSniff.php
@@ -45,7 +45,7 @@ public function process(File $phpcsFile, $openTagPointer): void
 
 		$referencedNames = array_merge(
 			ReferencedNameHelper::getAllReferencedNames($phpcsFile, $openTagPointer),
-			ReferencedNameHelper::getAllReferencedNamesInAttributes($phpcsFile, $openTagPointer)
+			ReferencedNameHelper::getAllReferencedNamesInAttributes($phpcsFile, $openTagPointer),
 		);
 
 		foreach ($referencedNames as $referencedName) {
@@ -72,7 +72,7 @@ public function process(File $phpcsFile, $openTagPointer): void
 			$resolvedName = NamespaceHelper::resolveClassName(
 				$phpcsFile,
 				$referencedName->getNameAsReferencedInFile(),
-				$referencedName->getStartPointer()
+				$referencedName->getStartPointer(),
 			);
 
 			if ($className !== $resolvedName) {
@@ -82,7 +82,7 @@ public function process(File $phpcsFile, $openTagPointer): void
 			$fix = $phpcsFile->addFixableError(
 				'"self" for local reference is required.',
 				$referencedName->getStartPointer(),
-				self::CODE_REQUIRED_SELF_REFERENCE
+				self::CODE_REQUIRED_SELF_REFERENCE,
 			);
 			if (!$fix) {
 				continue;
@@ -96,17 +96,21 @@ public function process(File $phpcsFile, $openTagPointer): void
 				$attributeContent = TokenHelper::getContent(
 					$phpcsFile,
 					$referencedName->getStartPointer(),
-					$referencedName->getEndPointer()
+					$referencedName->getEndPointer(),
 				);
 				$fixedAttributeContent = preg_replace(
 					'~(?<=\W)' . preg_quote($referencedName->getNameAsReferencedInFile(), '~') . '(?=\W)~',
 					'self',
-					$attributeContent
+					$attributeContent,
+				);
+				FixerHelper::replace(
+					$phpcsFile,
+					$referencedName->getStartPointer(),
+					$fixedAttributeContent,
 				);
-				$phpcsFile->fixer->replaceToken($referencedName->getStartPointer(), $fixedAttributeContent);
 
 			} else {
-				$phpcsFile->fixer->replaceToken($referencedName->getStartPointer(), 'self');
+				FixerHelper::replace($phpcsFile, $referencedName->getStartPointer(), 'self');
 			}
 
 			FixerHelper::removeBetweenIncluding($phpcsFile, $referencedName->getStartPointer() + 1, $referencedName->getEndPointer());
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/RequireSingleLineMethodSignatureSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/RequireSingleLineMethodSignatureSniff.php
index 4a2342ead..40b0161be 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/RequireSingleLineMethodSignatureSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/RequireSingleLineMethodSignatureSniff.php
@@ -17,20 +17,19 @@ class RequireSingleLineMethodSignatureSniff extends AbstractMethodSignature
 
 	public const CODE_REQUIRED_SINGLE_LINE_SIGNATURE = 'RequiredSingleLineSignature';
 
-	/** @var int */
-	public $maxLineLength = 120;
+	public int $maxLineLength = 120;
 
 	/** @var list */
-	public $includedMethodPatterns = [];
+	public array $includedMethodPatterns = [];
 
 	/** @var list|null */
-	public $includedMethodNormalizedPatterns;
+	public ?array $includedMethodNormalizedPatterns = null;
 
 	/** @var list */
-	public $excludedMethodPatterns = [];
+	public array $excludedMethodPatterns = [];
 
 	/** @var list|null */
-	public $excludedMethodNormalizedPatterns;
+	public ?array $excludedMethodNormalizedPatterns = null;
 
 	/**
 	 * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
@@ -53,7 +52,6 @@ public function process(File $phpcsFile, $methodPointer): void
 		}
 
 		$signature = $this->getSignature($phpcsFile, $signatureStartPointer, $signatureEndPointer);
-		$signatureWithoutTabIndentation = $this->getSignatureWithoutTabs($phpcsFile, $signature);
 		$methodName = FunctionHelper::getName($phpcsFile, $methodPointer);
 
 		if (
@@ -70,7 +68,7 @@ public function process(File $phpcsFile, $methodPointer): void
 			return;
 		}
 
-		if ($this->maxLineLength !== 0 && strlen($signatureWithoutTabIndentation) > $this->maxLineLength) {
+		if ($this->maxLineLength !== 0 && strlen($signature) > $this->maxLineLength) {
 			return;
 		}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/TraitUseDeclarationSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/TraitUseDeclarationSniff.php
index 0ed15b4e1..49cd8bea5 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/TraitUseDeclarationSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/TraitUseDeclarationSniff.php
@@ -7,6 +7,7 @@
 use SlevomatCodingStandard\Helpers\ClassHelper;
 use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
+use function sprintf;
 use const T_ANON_CLASS;
 use const T_CLASS;
 use const T_COMMA;
@@ -61,7 +62,7 @@ private function checkDeclaration(File $phpcsFile, int $usePointer): void
 			$phpcsFile->addError(
 				'Multiple traits per use statement are forbidden.',
 				$usePointer,
-				self::CODE_MULTIPLE_TRAITS_PER_DECLARATION
+				self::CODE_MULTIPLE_TRAITS_PER_DECLARATION,
 			);
 			return;
 		}
@@ -69,7 +70,7 @@ private function checkDeclaration(File $phpcsFile, int $usePointer): void
 		$fix = $phpcsFile->addFixableError(
 			'Multiple traits per use statement are forbidden.',
 			$usePointer,
-			self::CODE_MULTIPLE_TRAITS_PER_DECLARATION
+			self::CODE_MULTIPLE_TRAITS_PER_DECLARATION,
 		);
 
 		if (!$fix) {
@@ -92,7 +93,12 @@ private function checkDeclaration(File $phpcsFile, int $usePointer): void
 		foreach ($otherCommaPointers as $otherCommaPointer) {
 			$pointerAfterComma = TokenHelper::findNextEffective($phpcsFile, $otherCommaPointer + 1);
 
-			FixerHelper::change($phpcsFile, $otherCommaPointer, $pointerAfterComma - 1, ';' . $phpcsFile->eolChar . $indentation . 'use ');
+			FixerHelper::change(
+				$phpcsFile,
+				$otherCommaPointer,
+				$pointerAfterComma - 1,
+				sprintf(';%s%suse ', $phpcsFile->eolChar, $indentation),
+			);
 		}
 
 		$phpcsFile->fixer->endChangeset();
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/TraitUseSpacingSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/TraitUseSpacingSniff.php
index 0a4f4ef71..651dcf8a6 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/TraitUseSpacingSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/TraitUseSpacingSniff.php
@@ -29,20 +29,15 @@ class TraitUseSpacingSniff implements Sniff
 	public const CODE_INCORRECT_LINES_COUNT_BETWEEN_USES = 'IncorrectLinesCountBetweenUses';
 	public const CODE_INCORRECT_LINES_COUNT_AFTER_LAST_USE = 'IncorrectLinesCountAfterLastUse';
 
-	/** @var int */
-	public $linesCountBeforeFirstUse = 1;
+	public int $linesCountBeforeFirstUse = 1;
 
-	/** @var int */
-	public $linesCountBeforeFirstUseWhenFirstInClass = null;
+	public ?int $linesCountBeforeFirstUseWhenFirstInClass = null;
 
-	/** @var int */
-	public $linesCountBetweenUses = 0;
+	public int $linesCountBetweenUses = 0;
 
-	/** @var int */
-	public $linesCountAfterLastUse = 1;
+	public ?int $linesCountAfterLastUse = 1;
 
-	/** @var int */
-	public $linesCountAfterLastUseWhenLastInClass = 1;
+	public int $linesCountAfterLastUseWhenLastInClass = 1;
 
 	/**
 	 * @return array
@@ -65,10 +60,10 @@ public function process(File $phpcsFile, $classPointer): void
 	{
 		$this->linesCountBeforeFirstUse = SniffSettingsHelper::normalizeInteger($this->linesCountBeforeFirstUse);
 		$this->linesCountBeforeFirstUseWhenFirstInClass = SniffSettingsHelper::normalizeNullableInteger(
-			$this->linesCountBeforeFirstUseWhenFirstInClass
+			$this->linesCountBeforeFirstUseWhenFirstInClass,
 		);
 		$this->linesCountBetweenUses = SniffSettingsHelper::normalizeInteger($this->linesCountBetweenUses);
-		$this->linesCountAfterLastUse = SniffSettingsHelper::normalizeInteger($this->linesCountAfterLastUse);
+		$this->linesCountAfterLastUse = SniffSettingsHelper::normalizeNullableInteger($this->linesCountAfterLastUse);
 		$this->linesCountAfterLastUseWhenLastInClass = SniffSettingsHelper::normalizeInteger($this->linesCountAfterLastUseWhenLastInClass);
 
 		$usePointers = ClassHelper::getTraitUsePointers($phpcsFile, $classPointer);
@@ -123,10 +118,10 @@ private function checkLinesBeforeFirstUse(File $phpcsFile, int $firstUsePointer)
 				'Expected %d line%s before first use statement, found %d.',
 				$requiredLinesCountBeforeFirstUse,
 				$requiredLinesCountBeforeFirstUse === 1 ? '' : 's',
-				$actualLinesCountBeforeFirstUse
+				$actualLinesCountBeforeFirstUse,
 			),
 			$firstUsePointer,
-			self::CODE_INCORRECT_LINES_COUNT_BEFORE_FIRST_USE
+			self::CODE_INCORRECT_LINES_COUNT_BEFORE_FIRST_USE,
 		);
 
 		if (!$fix) {
@@ -138,7 +133,7 @@ private function checkLinesBeforeFirstUse(File $phpcsFile, int $firstUsePointer)
 			T_WHITESPACE,
 			$phpcsFile->eolChar,
 			$firstUsePointer,
-			$pointerBeforeFirstUse
+			$pointerBeforeFirstUse,
 		);
 
 		$phpcsFile->fixer->beginChangeset();
@@ -173,13 +168,18 @@ private function checkLinesAfterLastUse(File $phpcsFile, int $lastUsePointer): v
 				T_WHITESPACE,
 				$phpcsFile->eolChar,
 				$whitespaceEnd - 1,
-				$lastUseEndPointer
+				$lastUseEndPointer,
 			);
 			$whitespaceEnd = $lastEolPointer ?? $lastUseEndPointer;
 		}
 		$whitespaceAfterLastUse = TokenHelper::getContent($phpcsFile, $lastUseEndPointer + 1, $whitespaceEnd);
 
 		$requiredLinesCountAfterLastUse = $isAtTheEndOfClass ? $this->linesCountAfterLastUseWhenLastInClass : $this->linesCountAfterLastUse;
+
+		if ($requiredLinesCountAfterLastUse === null) {
+			return;
+		}
+
 		$actualLinesCountAfterLastUse = substr_count($whitespaceAfterLastUse, $phpcsFile->eolChar) - 1;
 
 		if ($actualLinesCountAfterLastUse === $requiredLinesCountAfterLastUse) {
@@ -191,10 +191,10 @@ private function checkLinesAfterLastUse(File $phpcsFile, int $lastUsePointer): v
 				'Expected %d line%s after last use statement, found %d.',
 				$requiredLinesCountAfterLastUse,
 				$requiredLinesCountAfterLastUse === 1 ? '' : 's',
-				$actualLinesCountAfterLastUse
+				$actualLinesCountAfterLastUse,
 			),
 			$lastUsePointer,
-			self::CODE_INCORRECT_LINES_COUNT_AFTER_LAST_USE
+			self::CODE_INCORRECT_LINES_COUNT_AFTER_LAST_USE,
 		);
 
 		if (!$fix) {
@@ -243,7 +243,7 @@ private function checkLinesBetweenUses(File $phpcsFile, array $usePointers): voi
 				$useStartPointer = TokenHelper::findNext(
 					$phpcsFile,
 					Tokens::$commentTokens,
-					TokenHelper::findPreviousEffective($phpcsFile, $pointerBeforeUse - 1) + 1
+					TokenHelper::findPreviousEffective($phpcsFile, $pointerBeforeUse - 1) + 1,
 				);
 			}
 
@@ -259,7 +259,7 @@ private function checkLinesBetweenUses(File $phpcsFile, array $usePointers): voi
 					'Expected %d line%s between same types of use statement, found %d.',
 					$this->linesCountBetweenUses,
 					$this->linesCountBetweenUses === 1 ? '' : 's',
-					$actualLinesCountAfterPreviousUse
+					$actualLinesCountAfterPreviousUse,
 				),
 				$usePointer,
 				self::CODE_INCORRECT_LINES_COUNT_BETWEEN_USES,
@@ -285,7 +285,7 @@ private function checkLinesBetweenUses(File $phpcsFile, array $usePointers): voi
 				T_WHITESPACE,
 				$phpcsFile->eolChar,
 				$usePointer,
-				$previousUseEndPointer
+				$previousUseEndPointer,
 			);
 
 			$phpcsFile->fixer->beginChangeset();
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/UselessLateStaticBindingSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/UselessLateStaticBindingSniff.php
index 754d4c3f4..01306dcd3 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/UselessLateStaticBindingSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Classes/UselessLateStaticBindingSniff.php
@@ -6,6 +6,7 @@
 use PHP_CodeSniffer\Sniffs\Sniff;
 use PHP_CodeSniffer\Util\Tokens;
 use SlevomatCodingStandard\Helpers\ClassHelper;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use function array_reverse;
 use function in_array;
@@ -50,14 +51,14 @@ public function process(File $phpcsFile, $staticPointer): void
 			break;
 		}
 
-		if (!ClassHelper::isFinal($phpcsFile, $classPointer)) {
+		if ($classPointer === null || !ClassHelper::isFinal($phpcsFile, $classPointer)) {
 			return;
 		}
 
 		$fix = $phpcsFile->addFixableError(
 			'Useless late static binding because class is final.',
 			$staticPointer,
-			self::CODE_USELESS_LATE_STATIC_BINDING
+			self::CODE_USELESS_LATE_STATIC_BINDING,
 		);
 
 		if (!$fix) {
@@ -65,7 +66,7 @@ public function process(File $phpcsFile, $staticPointer): void
 		}
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->replaceToken($staticPointer, 'self');
+		FixerHelper::replace($phpcsFile, $staticPointer, 'self');
 		$phpcsFile->fixer->endChangeset();
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/AbstractRequireOneLineDocComment.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/AbstractRequireOneLineDocComment.php
index 3c1104618..00cde5625 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/AbstractRequireOneLineDocComment.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/AbstractRequireOneLineDocComment.php
@@ -70,7 +70,7 @@ public function process(File $phpcsFile, $docCommentStartPointer): void
 				$phpcsFile,
 				[T_DOC_COMMENT_WHITESPACE],
 				$startingPointer + 1,
-				$docCommentEndPointer + 1
+				$docCommentEndPointer + 1,
 			);
 
 			if ($tokens[$currentLinePointer]['line'] === $tokens[$nextEffectivePointer]['line']) {
@@ -97,7 +97,7 @@ public function process(File $phpcsFile, $docCommentStartPointer): void
 				T_DOC_COMMENT_STAR,
 			],
 			$docCommentStartPointer + 1,
-			$docCommentEndPointer
+			$docCommentEndPointer,
 		);
 		$contentEndPointer = TokenHelper::findPreviousExcluding(
 			$phpcsFile,
@@ -106,7 +106,7 @@ public function process(File $phpcsFile, $docCommentStartPointer): void
 				T_DOC_COMMENT_STAR,
 			],
 			$docCommentEndPointer - 1,
-			$docCommentStartPointer
+			$docCommentStartPointer,
 		);
 
 		if ($contentStartPointer === null) {
@@ -119,17 +119,21 @@ public function process(File $phpcsFile, $docCommentStartPointer): void
 		for ($i = $docCommentStartPointer + 1; $i < $docCommentEndPointer; $i++) {
 			if ($i >= $contentStartPointer && $i <= $contentEndPointer) {
 				if ($i === $contentEndPointer) {
-					$phpcsFile->fixer->replaceToken($i, rtrim($phpcsFile->fixer->getTokenContent($i), ' '));
+					FixerHelper::replace(
+						$phpcsFile,
+						$i,
+						rtrim($phpcsFile->fixer->getTokenContent($i), ' '),
+					);
 				}
 
 				continue;
 			}
 
-			$phpcsFile->fixer->replaceToken($i, '');
+			FixerHelper::replace($phpcsFile, $i, '');
 		}
 
-		$phpcsFile->fixer->addContentBefore($contentStartPointer, ' ');
-		$phpcsFile->fixer->addContentBefore($docCommentEndPointer, ' ');
+		FixerHelper::addBefore($phpcsFile, $contentStartPointer, ' ');
+		FixerHelper::addBefore($phpcsFile, $docCommentEndPointer, ' ');
 
 		$phpcsFile->fixer->endChangeset();
 	}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/AnnotationNameSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/AnnotationNameSniff.php
index 26c223418..12d75a31f 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/AnnotationNameSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/AnnotationNameSniff.php
@@ -12,7 +12,6 @@
 use function array_combine;
 use function array_key_exists;
 use function array_map;
-use function array_merge;
 use function array_unique;
 use function implode;
 use function ltrim;
@@ -147,10 +146,10 @@ class AnnotationNameSniff implements Sniff
 	];
 
 	/** @var list|null */
-	public $annotations;
+	public ?array $annotations = null;
 
 	/** @var array|null */
-	private $normalizedAnnotations;
+	private ?array $normalizedAnnotations = null;
 
 	/**
 	 * @return array
@@ -188,7 +187,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 			$fullyQualifiedAnnotationName = NamespaceHelper::resolveClassName(
 				$phpcsFile,
 				$annotationNameWithoutAtSign,
-				$annotation->getStartPointer()
+				$annotation->getStartPointer(),
 			);
 
 			if (NamespaceHelper::normalizeToCanonicalName($fullyQualifiedAnnotationName) !== $annotationNameWithoutAtSign) {
@@ -198,7 +197,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 			$fix = $phpcsFile->addFixableError(
 				sprintf('Annotation name is incorrect. Expected %s, found %s.', $correctAnnotationName, $annotation->getName()),
 				$annotation->getStartPointer(),
-				self::CODE_ANNOTATION_NAME_INCORRECT
+				self::CODE_ANNOTATION_NAME_INCORRECT,
 			);
 			if (!$fix) {
 				continue;
@@ -206,7 +205,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 
 			$phpcsFile->fixer->beginChangeset();
 
-			$phpcsFile->fixer->replaceToken($annotation->getStartPointer(), $correctAnnotationName);
+			FixerHelper::replace($phpcsFile, $annotation->getStartPointer(), $correctAnnotationName);
 
 			$phpcsFile->fixer->endChangeset();
 		}
@@ -219,7 +218,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 			'~\{(' . implode('|', $correctAnnotationNames) . ')\}~i',
 			$docCommentContent,
 			$matches,
-			PREG_OFFSET_CAPTURE
+			PREG_OFFSET_CAPTURE,
 		) === 0) {
 			return;
 		}
@@ -234,7 +233,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 			$fix = $phpcsFile->addFixableError(
 				sprintf('Annotation name is incorrect. Expected %s, found %s.', $correctAnnotationName, $match[0]),
 				$docCommentOpenPointer,
-				self::CODE_ANNOTATION_NAME_INCORRECT
+				self::CODE_ANNOTATION_NAME_INCORRECT,
 			);
 			if (!$fix) {
 				continue;
@@ -244,14 +243,14 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 
 			$fixedDocCommentContent = substr($docCommentContent, 0, $match[1]) . $correctAnnotationName . substr(
 				$docCommentContent,
-				$match[1] + strlen($match[0])
+				$match[1] + strlen($match[0]),
 			);
 
 			FixerHelper::change(
 				$phpcsFile,
 				$docCommentOpenPointer,
 				$tokens[$docCommentOpenPointer]['comment_closer'],
-				$fixedDocCommentContent
+				$fixedDocCommentContent,
 			);
 
 			$phpcsFile->fixer->endChangeset();
@@ -268,11 +267,12 @@ private function getNormalizedAnnotationNames(): array
 		}
 
 		if ($this->annotations !== null) {
-			$annotationNames = array_map(static function (string $annotationName): string {
-				return ltrim($annotationName, '@');
-			}, SniffSettingsHelper::normalizeArray($this->annotations));
+			$annotationNames = array_map(
+				static fn (string $annotationName): string => ltrim($annotationName, '@'),
+				SniffSettingsHelper::normalizeArray($this->annotations),
+			);
 		} else {
-			$annotationNames = array_merge(self::STANDARD_ANNOTATIONS, self::PHPUNIT_ANNOTATIONS, self::STATIC_ANALYSIS_ANNOTATIONS);
+			$annotationNames = [...self::STANDARD_ANNOTATIONS, ...self::PHPUNIT_ANNOTATIONS, ...self::STATIC_ANALYSIS_ANNOTATIONS];
 
 			foreach (self::STATIC_ANALYSIS_ANNOTATIONS as $annotationName) {
 				if (strpos($annotationName, 'psalm') === 0) {
@@ -285,13 +285,12 @@ private function getNormalizedAnnotationNames(): array
 			}
 		}
 
-		$annotationNames = array_map(static function (string $annotationName): string {
-			return '@' . $annotationName;
-		}, array_unique($annotationNames));
+		$annotationNames = array_map(static fn (string $annotationName): string => '@' . $annotationName, array_unique($annotationNames));
 
-		$this->normalizedAnnotations = array_combine(array_map(static function (string $annotationName): string {
-			return strtolower($annotationName);
-		}, $annotationNames), $annotationNames);
+		$this->normalizedAnnotations = array_combine(
+			array_map(static fn (string $annotationName): string => strtolower($annotationName), $annotationNames),
+			$annotationNames,
+		);
 
 		return $this->normalizedAnnotations;
 	}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/DeprecatedAnnotationDeclarationSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/DeprecatedAnnotationDeclarationSniff.php
index 633403d2b..c821eb52d 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/DeprecatedAnnotationDeclarationSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/DeprecatedAnnotationDeclarationSniff.php
@@ -42,7 +42,7 @@ public function process(File $phpcsFile, $docCommentStartPointer): void
 			$phpcsFile->addError(
 				'Deprecated annotation must have a description.',
 				$annotation->getStartPointer(),
-				self::MISSING_DESCRIPTION
+				self::MISSING_DESCRIPTION,
 			);
 		}
 	}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/DisallowCommentAfterCodeSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/DisallowCommentAfterCodeSniff.php
index b7ae8c53f..bc110ab9f 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/DisallowCommentAfterCodeSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/DisallowCommentAfterCodeSniff.php
@@ -10,7 +10,6 @@
 use SlevomatCodingStandard\Helpers\IndentationHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use function array_key_exists;
-use function array_merge;
 use function in_array;
 use function strlen;
 use function substr;
@@ -32,8 +31,7 @@ class DisallowCommentAfterCodeSniff implements Sniff
 	 */
 	public function register(): array
 	{
-		/** @phpstan-var array */
-		return array_merge(TokenHelper::$inlineCommentTokenCodes, [T_DOC_COMMENT_OPEN_TAG]);
+		return [...TokenHelper::INLINE_COMMENT_TOKEN_CODES, T_DOC_COMMENT_OPEN_TAG];
 	}
 
 	/**
@@ -102,28 +100,29 @@ public function process(File $phpcsFile, $commentPointer): void
 			&& in_array(
 				$tokens[$tokens[$firstNonWhiteSpacePointerBeforeComment]['scope_condition']]['code'],
 				[T_ELSEIF, T_ELSE, T_CLOSURE],
-				true
+				true,
 			)
 		) {
-			$phpcsFile->fixer->addContent(
+			FixerHelper::add(
+				$phpcsFile,
 				$firstNonWhiteSpacePointerBeforeComment,
-				$phpcsFile->eolChar . IndentationHelper::addIndentation($indentation) . $commentContent
+				$phpcsFile->eolChar . IndentationHelper::addIndentation($phpcsFile, $indentation) . $commentContent,
 			);
 		} elseif ($tokens[$firstNonWhitespacePointerOnLine]['code'] === T_CLOSE_CURLY_BRACKET) {
-			$phpcsFile->fixer->addContent($firstNonWhiteSpacePointerBeforeComment, $phpcsFile->eolChar . $indentation . $commentContent);
+			FixerHelper::add($phpcsFile, $firstNonWhiteSpacePointerBeforeComment, $phpcsFile->eolChar . $indentation . $commentContent);
 		} elseif (isset(Tokens::$stringTokens[$tokens[$firstPointerOnLine]['code']])) {
 			$prevNonStringToken = TokenHelper::findPreviousExcluding(
 				$phpcsFile,
 				[T_WHITESPACE] + Tokens::$stringTokens,
-				$firstPointerOnLine - 1
+				$firstPointerOnLine - 1,
 			);
 			$firstTokenOnNonStringTokenLine = TokenHelper::findFirstTokenOnLine($phpcsFile, $prevNonStringToken);
 			$firstNonWhitespacePointerOnNonStringTokenLine = TokenHelper::findFirstNonWhitespaceOnLine($phpcsFile, $prevNonStringToken);
 			$prevLineIndentation = IndentationHelper::getIndentation($phpcsFile, $firstNonWhitespacePointerOnNonStringTokenLine);
-			$phpcsFile->fixer->addContentBefore($firstTokenOnNonStringTokenLine, $prevLineIndentation . $commentContent);
+			FixerHelper::addBefore($phpcsFile, $firstTokenOnNonStringTokenLine, $prevLineIndentation . $commentContent);
 			$phpcsFile->fixer->addNewline($firstNonWhiteSpacePointerBeforeComment);
 		} else {
-			$phpcsFile->fixer->addContentBefore($firstPointerOnLine, $indentation . $commentContent);
+			FixerHelper::addBefore($phpcsFile, $firstPointerOnLine, $indentation . $commentContent);
 			$phpcsFile->fixer->addNewline($firstNonWhiteSpacePointerBeforeComment);
 		}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/DisallowOneLinePropertyDocCommentSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/DisallowOneLinePropertyDocCommentSniff.php
index bbb4e8102..d7018dfea 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/DisallowOneLinePropertyDocCommentSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/DisallowOneLinePropertyDocCommentSniff.php
@@ -5,6 +5,7 @@
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
 use SlevomatCodingStandard\Helpers\DocCommentHelper;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\PropertyHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use function rtrim;
@@ -56,10 +57,10 @@ public function process(File $phpcsFile, $propertyPointer): void
 		$fix = $phpcsFile->addFixableError(
 			sprintf(
 				'Found one-line comment for property %s, use multi-line comment instead.',
-				PropertyHelper::getFullyQualifiedName($phpcsFile, $propertyPointer)
+				PropertyHelper::getFullyQualifiedName($phpcsFile, $propertyPointer),
 			),
 			$docCommentStartPointer,
-			self::CODE_ONE_LINE_PROPERTY_COMMENT
+			self::CODE_ONE_LINE_PROPERTY_COMMENT,
 		);
 
 		if (!$fix) {
@@ -69,37 +70,21 @@ public function process(File $phpcsFile, $propertyPointer): void
 		$commentWhitespacePointer = TokenHelper::findPrevious($phpcsFile, [T_WHITESPACE], $docCommentStartPointer);
 		$indent = ($commentWhitespacePointer !== null ? $tokens[$commentWhitespacePointer]['content'] : '') . ' ';
 
-		/** empty comment is not split into start & end tokens properly */
-		if ($tokens[$docCommentStartPointer]['content'] === '/***/') {
-			$phpcsFile->fixer->beginChangeset();
-
-			$phpcsFile->fixer->replaceToken($docCommentStartPointer, '/**');
-			$phpcsFile->fixer->addNewline($docCommentStartPointer);
-			$phpcsFile->fixer->addContent($docCommentStartPointer, $indent);
-			$phpcsFile->fixer->addContent($docCommentStartPointer, '*');
-			$phpcsFile->fixer->addNewline($docCommentStartPointer);
-			$phpcsFile->fixer->addContent($docCommentStartPointer, $indent);
-			$phpcsFile->fixer->addContent($docCommentStartPointer, '*/');
-
-			$phpcsFile->fixer->endChangeset();
-
-			return;
-		}
-
 		$phpcsFile->fixer->beginChangeset();
 
 		$phpcsFile->fixer->addNewline($docCommentStartPointer);
-		$phpcsFile->fixer->addContent($docCommentStartPointer, $indent);
-		$phpcsFile->fixer->addContent($docCommentStartPointer, '*');
+		FixerHelper::add($phpcsFile, $docCommentStartPointer, $indent);
+		FixerHelper::add($phpcsFile, $docCommentStartPointer, '*');
 
 		if ($docCommentEndPointer - 1 !== $docCommentStartPointer) {
-			$phpcsFile->fixer->replaceToken(
+			FixerHelper::replace(
+				$phpcsFile,
 				$docCommentEndPointer - 1,
-				rtrim($phpcsFile->fixer->getTokenContent($docCommentEndPointer - 1), ' ')
+				rtrim($phpcsFile->fixer->getTokenContent($docCommentEndPointer - 1), ' '),
 			);
 		}
 
-		$phpcsFile->fixer->addContentBefore($docCommentEndPointer, $indent);
+		FixerHelper::addBefore($phpcsFile, $docCommentEndPointer, $indent);
 		$phpcsFile->fixer->addNewlineBefore($docCommentEndPointer);
 
 		$phpcsFile->fixer->endChangeset();
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/DocCommentSpacingSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/DocCommentSpacingSniff.php
index f2ac58b73..3cd2ff630 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/DocCommentSpacingSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/DocCommentSpacingSniff.php
@@ -48,26 +48,21 @@ class DocCommentSpacingSniff implements Sniff
 	public const CODE_INCORRECT_ORDER_OF_ANNOTATIONS_GROUPS = 'IncorrectOrderOfAnnotationsGroup';
 	public const CODE_INCORRECT_ORDER_OF_ANNOTATIONS_IN_GROUP = 'IncorrectOrderOfAnnotationsInGroup';
 
-	/** @var int */
-	public $linesCountBeforeFirstContent = 0;
+	public int $linesCountBeforeFirstContent = 0;
 
-	/** @var int */
-	public $linesCountBetweenDescriptionAndAnnotations = 1;
+	public int $linesCountBetweenDescriptionAndAnnotations = 1;
 
-	/** @var int */
-	public $linesCountBetweenDifferentAnnotationsTypes = 0;
+	public int $linesCountBetweenDifferentAnnotationsTypes = 0;
 
-	/** @var int */
-	public $linesCountBetweenAnnotationsGroups = 1;
+	public int $linesCountBetweenAnnotationsGroups = 1;
 
-	/** @var int */
-	public $linesCountAfterLastContent = 0;
+	public int $linesCountAfterLastContent = 0;
 
 	/** @var list */
-	public $annotationsGroups = [];
+	public array $annotationsGroups = [];
 
 	/** @var array>|null */
-	private $normalizedAnnotationsGroups = null;
+	private ?array $normalizedAnnotationsGroups = null;
 
 	/**
 	 * @return array
@@ -87,10 +82,10 @@ public function process(File $phpcsFile, $docCommentOpenerPointer): void
 	{
 		$this->linesCountBeforeFirstContent = SniffSettingsHelper::normalizeInteger($this->linesCountBeforeFirstContent);
 		$this->linesCountBetweenDescriptionAndAnnotations = SniffSettingsHelper::normalizeInteger(
-			$this->linesCountBetweenDescriptionAndAnnotations
+			$this->linesCountBetweenDescriptionAndAnnotations,
 		);
 		$this->linesCountBetweenDifferentAnnotationsTypes = SniffSettingsHelper::normalizeInteger(
-			$this->linesCountBetweenDifferentAnnotationsTypes
+			$this->linesCountBetweenDifferentAnnotationsTypes,
 		);
 		$this->linesCountBetweenAnnotationsGroups = SniffSettingsHelper::normalizeInteger($this->linesCountBetweenAnnotationsGroups);
 		$this->linesCountAfterLastContent = SniffSettingsHelper::normalizeInteger($this->linesCountAfterLastContent);
@@ -105,7 +100,7 @@ public function process(File $phpcsFile, $docCommentOpenerPointer): void
 			$phpcsFile,
 			[T_DOC_COMMENT_WHITESPACE, T_DOC_COMMENT_STAR],
 			$docCommentOpenerPointer + 1,
-			$tokens[$docCommentOpenerPointer]['comment_closer']
+			$tokens[$docCommentOpenerPointer]['comment_closer'],
 		) === null) {
 			return;
 		}
@@ -120,13 +115,11 @@ public function process(File $phpcsFile, $docCommentOpenerPointer): void
 		$firstContentEndPointer = $parsedDocComment->getNodeEndPointer(
 			$phpcsFile,
 			$parsedDocComment->getNode()->children[0],
-			$firstContentStartPointer
+			$firstContentStartPointer,
 		);
 
 		$annotations = AnnotationHelper::getAnnotations($phpcsFile, $docCommentOpenerPointer);
-		usort($annotations, static function (Annotation $a, Annotation $b): int {
-			return $a->getStartPointer() <=> $b->getStartPointer();
-		});
+		usort($annotations, static fn (Annotation $a, Annotation $b): int => $a->getStartPointer() <=> $b->getStartPointer());
 		$annotationsCount = count($annotations);
 
 		$firstAnnotationPointer = $annotationsCount > 0 ? $annotations[0]->getStartPointer() : null;
@@ -142,7 +135,7 @@ public function process(File $phpcsFile, $docCommentOpenerPointer): void
 			$docCommentOpenerPointer,
 			$firstContentStartPointer,
 			$firstContentEndPointer,
-			$firstAnnotationPointer
+			$firstAnnotationPointer,
 		);
 
 		if (count($annotations) > 1) {
@@ -157,7 +150,7 @@ public function process(File $phpcsFile, $docCommentOpenerPointer): void
 			$phpcsFile,
 			$docCommentOpenerPointer,
 			$tokens[$docCommentOpenerPointer]['comment_closer'],
-			$lastContentEndPointer
+			$lastContentEndPointer,
 		);
 	}
 
@@ -178,10 +171,10 @@ private function checkLinesBeforeFirstContent(File $phpcsFile, int $docCommentOp
 				'Expected %d line%s before first content, found %d.',
 				$this->linesCountBeforeFirstContent,
 				$this->linesCountBeforeFirstContent === 1 ? '' : 's',
-				$linesCountBeforeFirstContent
+				$linesCountBeforeFirstContent,
 			),
 			$firstContentStartPointer,
-			self::CODE_INCORRECT_LINES_COUNT_BEFORE_FIRST_CONTENT
+			self::CODE_INCORRECT_LINES_COUNT_BEFORE_FIRST_CONTENT,
 		);
 
 		if (!$fix) {
@@ -195,10 +188,10 @@ private function checkLinesBeforeFirstContent(File $phpcsFile, int $docCommentOp
 		FixerHelper::change($phpcsFile, $docCommentOpenerPointer, $firstContentStartPointer - 1, '/**' . $phpcsFile->eolChar);
 
 		for ($i = 1; $i <= $this->linesCountBeforeFirstContent; $i++) {
-			$phpcsFile->fixer->addContent($docCommentOpenerPointer, sprintf('%s *%s', $indentation, $phpcsFile->eolChar));
+			FixerHelper::add($phpcsFile, $docCommentOpenerPointer, sprintf('%s *%s', $indentation, $phpcsFile->eolChar));
 		}
 
-		$phpcsFile->fixer->addContentBefore($firstContentStartPointer, $indentation . ' * ');
+		FixerHelper::addBefore($phpcsFile, $firstContentStartPointer, $indentation . ' * ');
 
 		$phpcsFile->fixer->endChangeset();
 	}
@@ -227,12 +220,12 @@ private function checkLinesBetweenDescriptionAndFirstAnnotation(
 		$whitespaceBetweenDescriptionAndFirstAnnotation .= TokenHelper::getContent(
 			$phpcsFile,
 			$firstContentEndPointer + 1,
-			$firstAnnotationPointer - 1
+			$firstAnnotationPointer - 1,
 		);
 
 		$linesCountBetweenDescriptionAndAnnotations = max(
 			substr_count($whitespaceBetweenDescriptionAndFirstAnnotation, $phpcsFile->eolChar) - 1,
-			0
+			0,
 		);
 		if ($linesCountBetweenDescriptionAndAnnotations === $this->linesCountBetweenDescriptionAndAnnotations) {
 			return;
@@ -243,10 +236,10 @@ private function checkLinesBetweenDescriptionAndFirstAnnotation(
 				'Expected %d line%s between description and annotations, found %d.',
 				$this->linesCountBetweenDescriptionAndAnnotations,
 				$this->linesCountBetweenDescriptionAndAnnotations === 1 ? '' : 's',
-				$linesCountBetweenDescriptionAndAnnotations
+				$linesCountBetweenDescriptionAndAnnotations,
 			),
 			$firstAnnotationPointer,
-			self::CODE_INCORRECT_LINES_COUNT_BETWEEN_DESCRIPTION_AND_ANNOTATIONS
+			self::CODE_INCORRECT_LINES_COUNT_BETWEEN_DESCRIPTION_AND_ANNOTATIONS,
 		);
 
 		if (!$fix) {
@@ -262,10 +255,10 @@ private function checkLinesBetweenDescriptionAndFirstAnnotation(
 		FixerHelper::removeBetween($phpcsFile, $firstContentEndPointer, $firstAnnotationPointer);
 
 		for ($i = 1; $i <= $this->linesCountBetweenDescriptionAndAnnotations; $i++) {
-			$phpcsFile->fixer->addContent($firstContentEndPointer, sprintf('%s *%s', $indentation, $phpcsFile->eolChar));
+			FixerHelper::add($phpcsFile, $firstContentEndPointer, sprintf('%s *%s', $indentation, $phpcsFile->eolChar));
 		}
 
-		$phpcsFile->fixer->addContentBefore($firstAnnotationPointer, $indentation . ' * ');
+		FixerHelper::addBefore($phpcsFile, $firstAnnotationPointer, $indentation . ' * ');
 
 		$phpcsFile->fixer->endChangeset();
 	}
@@ -292,7 +285,7 @@ private function checkLinesBetweenDifferentAnnotationsTypes(File $phpcsFile, int
 			$whitespaceAfterPreviousAnnotation = TokenHelper::getContent(
 				$phpcsFile,
 				$previousAnnotation->getEndPointer() + 1,
-				$annotation->getStartPointer() - 1
+				$annotation->getStartPointer() - 1,
 			);
 
 			$linesCountAfterPreviousAnnotation = max(substr_count($whitespaceAfterPreviousAnnotation, $phpcsFile->eolChar) - 1, 0);
@@ -307,10 +300,10 @@ private function checkLinesBetweenDifferentAnnotationsTypes(File $phpcsFile, int
 					'Expected %d line%s between different annotations types, found %d.',
 					$this->linesCountBetweenDifferentAnnotationsTypes,
 					$this->linesCountBetweenDifferentAnnotationsTypes === 1 ? '' : 's',
-					$linesCountAfterPreviousAnnotation
+					$linesCountAfterPreviousAnnotation,
 				),
 				$annotation->getStartPointer(),
-				self::CODE_INCORRECT_LINES_COUNT_BETWEEN_DIFFERENT_ANNOTATIONS_TYPES
+				self::CODE_INCORRECT_LINES_COUNT_BETWEEN_DIFFERENT_ANNOTATIONS_TYPES,
 			);
 
 			if (!$fix) {
@@ -325,10 +318,10 @@ private function checkLinesBetweenDifferentAnnotationsTypes(File $phpcsFile, int
 			$phpcsFile->fixer->addNewline($previousAnnotation->getEndPointer());
 
 			for ($i = 1; $i <= $this->linesCountBetweenDifferentAnnotationsTypes; $i++) {
-				$phpcsFile->fixer->addContent($previousAnnotation->getEndPointer(), sprintf('%s *%s', $indentation, $phpcsFile->eolChar));
+				FixerHelper::add($phpcsFile, $previousAnnotation->getEndPointer(), sprintf('%s *%s', $indentation, $phpcsFile->eolChar));
 			}
 
-			$phpcsFile->fixer->addContentBefore($annotation->getStartPointer(), $indentation . ' * ');
+			FixerHelper::addBefore($phpcsFile, $annotation->getStartPointer(), $indentation . ' * ');
 
 			$phpcsFile->fixer->endChangeset();
 
@@ -397,10 +390,10 @@ private function checkLinesBetweenAnnotationsGroups(File $phpcsFile, int $docCom
 					'Expected %d line%s between annotations groups, found %d.',
 					$this->linesCountBetweenAnnotationsGroups,
 					$this->linesCountBetweenAnnotationsGroups === 1 ? '' : 's',
-					$actualLinesCountBetweenAnnotationsGroups
+					$actualLinesCountBetweenAnnotationsGroups,
 				),
 				$firstAnnotationInActualGroup->getStartPointer(),
-				self::CODE_INCORRECT_LINES_COUNT_BETWEEN_ANNOTATIONS_GROUPS
+				self::CODE_INCORRECT_LINES_COUNT_BETWEEN_ANNOTATIONS_GROUPS,
 			);
 
 			if (!$fix) {
@@ -417,19 +410,21 @@ private function checkLinesBetweenAnnotationsGroups(File $phpcsFile, int $docCom
 			FixerHelper::removeBetween(
 				$phpcsFile,
 				$lastAnnotationInPreviousGroup->getEndPointer(),
-				$firstAnnotationInActualGroup->getStartPointer()
+				$firstAnnotationInActualGroup->getStartPointer(),
 			);
 
 			for ($i = 1; $i <= $this->linesCountBetweenAnnotationsGroups; $i++) {
-				$phpcsFile->fixer->addContent(
+				FixerHelper::add(
+					$phpcsFile,
 					$lastAnnotationInPreviousGroup->getEndPointer(),
-					sprintf('%s *%s', $indentation, $phpcsFile->eolChar)
+					sprintf('%s *%s', $indentation, $phpcsFile->eolChar),
 				);
 			}
 
-			$phpcsFile->fixer->addContentBefore(
+			FixerHelper::addBefore(
+				$phpcsFile,
 				$firstAnnotationInActualGroup->getStartPointer(),
-				$indentation . ' * '
+				$indentation . ' * ',
 			);
 
 			$phpcsFile->fixer->endChangeset();
@@ -447,9 +442,7 @@ private function checkAnnotationsGroupsOrder(
 		array $annotations
 	): void
 	{
-		$getAnnotationsPointers = static function (Annotation $annotation): int {
-			return $annotation->getStartPointer();
-		};
+		$getAnnotationsPointers = static fn (Annotation $annotation): int => $annotation->getStartPointer();
 
 		$equals = static function (array $firstAnnotationsGroup, array $secondAnnotationsGroup) use ($getAnnotationsPointers): bool {
 			$firstAnnotationsPointers = array_map($getAnnotationsPointers, $firstAnnotationsGroup);
@@ -495,7 +488,7 @@ private function checkAnnotationsGroupsOrder(
 			$fix = $phpcsFile->addFixableError(
 				'Incorrect annotations group.',
 				$annotationsGroup[0]->getStartPointer(),
-				self::CODE_INCORRECT_ANNOTATIONS_GROUP
+				self::CODE_INCORRECT_ANNOTATIONS_GROUP,
 			);
 		}
 
@@ -505,7 +498,7 @@ private function checkAnnotationsGroupsOrder(
 			$fix = $phpcsFile->addFixableError(
 				'Incorrect annotations group.',
 				$annotationsGroups[0][0]->getStartPointer(),
-				self::CODE_INCORRECT_ANNOTATIONS_GROUP
+				self::CODE_INCORRECT_ANNOTATIONS_GROUP,
 			);
 		}
 
@@ -520,7 +513,6 @@ private function checkAnnotationsGroupsOrder(
 			$positionsMappedToGroups = array_keys($annotationsGroupsPositions);
 			$tmp = array_values($annotationsGroupsPositions);
 			asort($tmp);
-			/** @var list $normalizedAnnotationsGroupsPositions */
 			$normalizedAnnotationsGroupsPositions = array_combine(array_keys($positionsMappedToGroups), array_keys($tmp));
 
 			foreach ($normalizedAnnotationsGroupsPositions as $normalizedAnnotationsGroupPosition => $sortedAnnotationsGroupPosition) {
@@ -531,7 +523,7 @@ private function checkAnnotationsGroupsOrder(
 				$fix = $phpcsFile->addFixableError(
 					'Incorrect order of annotations groups.',
 					$annotationsGroups[$positionsMappedToGroups[$normalizedAnnotationsGroupPosition]][0]->getStartPointer(),
-					self::CODE_INCORRECT_ORDER_OF_ANNOTATIONS_GROUPS
+					self::CODE_INCORRECT_ORDER_OF_ANNOTATIONS_GROUPS,
 				);
 				break;
 			}
@@ -556,7 +548,7 @@ private function checkAnnotationsGroupsOrder(
 				$fix = $phpcsFile->addFixableError(
 					'Incorrect order of annotations in group.',
 					$annotation->getStartPointer(),
-					self::CODE_INCORRECT_ORDER_OF_ANNOTATIONS_IN_GROUP
+					self::CODE_INCORRECT_ORDER_OF_ANNOTATIONS_IN_GROUP,
 				);
 				break;
 			}
@@ -588,7 +580,7 @@ private function checkAnnotationsGroupsOrder(
 					'%s * %s%s',
 					$indentation,
 					trim(TokenHelper::getContent($phpcsFile, $sortedAnnotation->getStartPointer(), $sortedAnnotation->getEndPointer())),
-					$phpcsFile->eolChar
+					$phpcsFile->eolChar,
 				);
 			}
 		}
@@ -601,14 +593,14 @@ private function checkAnnotationsGroupsOrder(
 			T_DOC_COMMENT_WHITESPACE,
 			$phpcsFile->eolChar,
 			$firstAnnotation->getStartPointer() - 1,
-			$docCommentOpenerPointer
+			$docCommentOpenerPointer,
 		);
 		$docCommentContentEndPointer = TokenHelper::findNextContent(
 			$phpcsFile,
 			T_DOC_COMMENT_WHITESPACE,
 			$phpcsFile->eolChar,
 			$lastAnnotation->getEndPointer() + 1,
-			$docCommentCloserPointer
+			$docCommentCloserPointer,
 		);
 
 		if ($docCommentContentEndPointer === null) {
@@ -622,7 +614,7 @@ private function checkAnnotationsGroupsOrder(
 				$phpcsFile,
 				$docCommentOpenerPointer,
 				$docCommentContentEndPointer,
-				'/**' . $phpcsFile->eolChar . $fixedAnnotations
+				'/**' . $phpcsFile->eolChar . $fixedAnnotations,
 			);
 		} else {
 			FixerHelper::change($phpcsFile, $endOfLineBeforeFirstAnnotation + 1, $docCommentContentEndPointer, $fixedAnnotations);
@@ -682,7 +674,7 @@ function (Annotation $firstAnnotation, Annotation $secondAnnotation) use ($expec
 					return $expectedOrder !== 0
 						? $expectedOrder
 						: $firstAnnotation->getStartPointer() <=> $secondAnnotation->getStartPointer();
-				}
+				},
 			);
 		}
 
@@ -690,7 +682,7 @@ function (Annotation $firstAnnotation, Annotation $secondAnnotation) use ($expec
 			$sortedAnnotationsGroups[] = $annotationsNotInAnyGroup;
 		}
 
-		return $sortedAnnotationsGroups;
+		return array_values($sortedAnnotationsGroups);
 	}
 
 	private function isAnnotationNameInAnnotationNamespace(string $annotationNamespace, string $annotationName): bool
@@ -736,10 +728,10 @@ private function checkLinesAfterLastContent(
 				'Expected %d line%s after last content, found %d.',
 				$this->linesCountAfterLastContent,
 				$this->linesCountAfterLastContent === 1 ? '' : 's',
-				$linesCountAfterLastContent
+				$linesCountAfterLastContent,
 			),
 			$lastContentEndPointer,
-			self::CODE_INCORRECT_LINES_COUNT_AFTER_LAST_CONTENT
+			self::CODE_INCORRECT_LINES_COUNT_AFTER_LAST_CONTENT,
 		);
 
 		if (!$fix) {
@@ -755,10 +747,10 @@ private function checkLinesAfterLastContent(
 		$phpcsFile->fixer->addNewline($lastContentEndPointer);
 
 		for ($i = 1; $i <= $this->linesCountAfterLastContent; $i++) {
-			$phpcsFile->fixer->addContent($lastContentEndPointer, sprintf('%s *%s', $indentation, $phpcsFile->eolChar));
+			FixerHelper::add($phpcsFile, $lastContentEndPointer, sprintf('%s *%s', $indentation, $phpcsFile->eolChar));
 		}
 
-		$phpcsFile->fixer->addContentBefore($docCommentCloserPointer, $indentation . ' ');
+		FixerHelper::addBefore($phpcsFile, $docCommentCloserPointer, $indentation . ' ');
 
 		$phpcsFile->fixer->endChangeset();
 	}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/EmptyCommentSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/EmptyCommentSniff.php
index ad5fda84e..4617a6ced 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/EmptyCommentSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/EmptyCommentSniff.php
@@ -80,7 +80,7 @@ public function process(File $phpcsFile, $commentStartPointer): void
 
 		FixerHelper::removeBetween($phpcsFile, $pointerBeforeWhitespaceBeforeComment, $commentStartPointer);
 
-		$phpcsFile->fixer->addContent($pointerBeforeWhitespaceBeforeComment, $fixedWhitespaceBeforeComment);
+		FixerHelper::add($phpcsFile, $pointerBeforeWhitespaceBeforeComment, $fixedWhitespaceBeforeComment);
 
 		FixerHelper::removeBetweenIncluding($phpcsFile, $commentStartPointer, $commentEndPointer);
 
@@ -97,9 +97,9 @@ public function process(File $phpcsFile, $commentStartPointer): void
 			$fixedWhitespaceAfterComment = preg_replace(
 				'~^[ \\t]*' . $phpcsFile->eolChar . '~',
 				'',
-				$tokens[$whitespacePointerAfterComment]['content']
+				$tokens[$whitespacePointerAfterComment]['content'],
 			);
-			$phpcsFile->fixer->replaceToken($whitespacePointerAfterComment, $fixedWhitespaceAfterComment);
+			FixerHelper::replace($phpcsFile, $whitespacePointerAfterComment, $fixedWhitespaceAfterComment);
 		}
 
 		$phpcsFile->fixer->endChangeset();
@@ -120,7 +120,7 @@ private function getCommentContent(File $phpcsFile, int $commentStartPointer, in
 			return TokenHelper::getContent($phpcsFile, $commentStartPointer + 1, $commentEndPointer - 1);
 		}
 
-		if (preg_match('~^(?://|#)(.*)~', $tokens[$commentStartPointer]['content'], $matches) !== 0) {
+		if (preg_match('~^(?://|#)(.*)~', $tokens[$commentStartPointer]['content'], $matches) === 1) {
 			return $matches[1];
 		}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/ForbiddenAnnotationsSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/ForbiddenAnnotationsSniff.php
index bbce185bc..b97261b04 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/ForbiddenAnnotationsSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/ForbiddenAnnotationsSniff.php
@@ -23,10 +23,10 @@ class ForbiddenAnnotationsSniff implements Sniff
 	public const CODE_ANNOTATION_FORBIDDEN = 'AnnotationForbidden';
 
 	/** @var list */
-	public $forbiddenAnnotations = [];
+	public array $forbiddenAnnotations = [];
 
 	/** @var list|null */
-	private $normalizedForbiddenAnnotations;
+	private ?array $normalizedForbiddenAnnotations = null;
 
 	/**
 	 * @return array
@@ -56,7 +56,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 			$fix = $phpcsFile->addFixableError(
 				sprintf('Use of annotation %s is forbidden.', $annotation->getName()),
 				$annotation->getStartPointer(),
-				self::CODE_ANNOTATION_FORBIDDEN
+				self::CODE_ANNOTATION_FORBIDDEN,
 			);
 			if (!$fix) {
 				continue;
@@ -66,7 +66,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 				$phpcsFile,
 				T_DOC_COMMENT_STAR,
 				$annotation->getStartPointer() - 1,
-				$docCommentOpenPointer
+				$docCommentOpenPointer,
 			);
 			$annotationStartPointer = $starPointer ?? $annotation->getStartPointer();
 
@@ -74,7 +74,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 			$nextPointer = TokenHelper::findNext(
 				$phpcsFile,
 				[T_DOC_COMMENT_TAG, T_DOC_COMMENT_CLOSE_TAG],
-				$annotation->getEndPointer() + 1
+				$annotation->getEndPointer() + 1,
 			);
 			if ($tokens[$nextPointer]['code'] === T_DOC_COMMENT_TAG) {
 				$nextPointer = TokenHelper::findPrevious($phpcsFile, T_DOC_COMMENT_STAR, $nextPointer - 1);
@@ -85,7 +85,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 				$pointerBeforeWhitespace = TokenHelper::findPreviousExcluding(
 					$phpcsFile,
 					[T_DOC_COMMENT_WHITESPACE, T_DOC_COMMENT_STAR],
-					$annotationStartPointer - 1
+					$annotationStartPointer - 1,
 				);
 				/** @var int $annotationStartPointer */
 				$annotationStartPointer = TokenHelper::findNext($phpcsFile, T_DOC_COMMENT_STAR, $pointerBeforeWhitespace + 1);
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/ForbiddenCommentsSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/ForbiddenCommentsSniff.php
index f89881ab3..bb5d3c628 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/ForbiddenCommentsSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/ForbiddenCommentsSniff.php
@@ -9,7 +9,6 @@
 use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\SniffSettingsHelper;
 use function array_key_exists;
-use function is_array;
 use function preg_match;
 use function preg_replace;
 use function sprintf;
@@ -21,7 +20,7 @@ class ForbiddenCommentsSniff implements Sniff
 	public const CODE_COMMENT_FORBIDDEN = 'CommentForbidden';
 
 	/** @var list */
-	public $forbiddenCommentPatterns = [];
+	public array $forbiddenCommentPatterns = [];
 
 	/**
 	 * @return array
@@ -60,7 +59,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 				$fix = $phpcsFile->addFixableError(
 					sprintf('Documentation comment contains forbidden comment "%s".', $comment->getContent()),
 					$comment->getPointer(),
-					self::CODE_COMMENT_FORBIDDEN
+					self::CODE_COMMENT_FORBIDDEN,
 				);
 
 				if (!$fix) {
@@ -71,7 +70,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 
 				$fixedDocComment = preg_replace($forbiddenCommentPattern, '', $comment->getContent());
 
-				$phpcsFile->fixer->replaceToken($comment->getPointer(), $fixedDocComment);
+				FixerHelper::replace($phpcsFile, $comment->getPointer(), $fixedDocComment);
 
 				for ($i = $comment->getPointer() - 1; $i > $docCommentOpenPointer; $i--) {
 					$contentWithoutSpaces = preg_replace('~ +$~', '', $tokens[$i]['content'], -1, $replacedCount);
@@ -80,14 +79,13 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 						break;
 					}
 
-					$phpcsFile->fixer->replaceToken($i, $contentWithoutSpaces);
+					FixerHelper::replace($phpcsFile, $i, $contentWithoutSpaces);
 				}
 
 				$docCommentContent = '';
 				for ($i = $docCommentOpenPointer + 1; $i < $tokens[$docCommentOpenPointer]['comment_closer']; $i++) {
-					/** @var string|array<(string|int)> $token */
 					$token = $phpcsFile->fixer->getTokenContent($i);
-					$docCommentContent .= is_array($token) ? $token['content'] : $token;
+					$docCommentContent .= $token;
 				}
 
 				if (preg_match('~^[\\s\*]*$~', $docCommentContent) !== 0) {
@@ -97,16 +95,16 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 						'',
 						$tokens[$pointerBeforeDocComment]['content'],
 						-1,
-						$replacedCount
+						$replacedCount,
 					);
 					if ($replacedCount !== 0) {
-						$phpcsFile->fixer->replaceToken($pointerBeforeDocComment, $contentBeforeWithoutSpaces);
+						FixerHelper::replace($phpcsFile, $pointerBeforeDocComment, $contentBeforeWithoutSpaces);
 					}
 
 					FixerHelper::removeBetweenIncluding(
 						$phpcsFile,
 						$docCommentOpenPointer,
-						$tokens[$docCommentOpenPointer]['comment_closer']
+						$tokens[$docCommentOpenPointer]['comment_closer'],
 					);
 
 					$pointerAfterDocComment = $tokens[$docCommentOpenPointer]['comment_closer'] + 1;
@@ -116,10 +114,10 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 							'',
 							$tokens[$pointerAfterDocComment]['content'],
 							-1,
-							$replacedCount
+							$replacedCount,
 						);
 						if ($replacedCount !== 0) {
-							$phpcsFile->fixer->replaceToken($pointerAfterDocComment, $contentAfterWithoutSpaces);
+							FixerHelper::replace($phpcsFile, $pointerAfterDocComment, $contentAfterWithoutSpaces);
 						}
 					}
 				}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/InlineDocCommentDeclarationSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/InlineDocCommentDeclarationSniff.php
index 1ce816b11..d9ed4648e 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/InlineDocCommentDeclarationSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/InlineDocCommentDeclarationSniff.php
@@ -46,11 +46,9 @@ class InlineDocCommentDeclarationSniff implements Sniff
 	public const CODE_MISSING_VARIABLE = 'MissingVariable';
 	public const CODE_NO_ASSIGNMENT = 'NoAssignment';
 
-	/** @var bool */
-	public $allowDocCommentAboveReturn = false;
+	public bool $allowDocCommentAboveReturn = false;
 
-	/** @var bool */
-	public $allowAboveNonAssignment = false;
+	public bool $allowAboveNonAssignment = false;
 
 	/**
 	 * @return array
@@ -84,14 +82,14 @@ public function process(File $phpcsFile, $commentOpenPointer): void
 
 				$pointerAfterCommentClosePointer = TokenHelper::findNextEffective(
 					$phpcsFile,
-					$tokens[$pointerAfterCommentClosePointer]['attribute_closer'] + 1
+					$tokens[$pointerAfterCommentClosePointer]['attribute_closer'] + 1,
 				);
 			} while (true);
 
 			if (in_array(
 				$tokens[$pointerAfterCommentClosePointer]['code'],
 				[T_PRIVATE, T_PROTECTED, T_PUBLIC, T_READONLY, T_FINAL, T_CONST],
-				true
+				true,
 			)) {
 				return;
 			}
@@ -122,7 +120,7 @@ public function process(File $phpcsFile, $commentOpenPointer): void
 
 		if ($this->allowDocCommentAboveReturn) {
 			$pointerAfterCommentClosePointer = TokenHelper::findNextEffective($phpcsFile, $commentClosePointer + 1);
-			if ($tokens[$pointerAfterCommentClosePointer]['code'] === T_RETURN) {
+			if ($pointerAfterCommentClosePointer === null || $tokens[$pointerAfterCommentClosePointer]['code'] === T_RETURN) {
 				return;
 			}
 		}
@@ -142,7 +140,7 @@ private function checkCommentType(File $phpcsFile, int $commentOpenPointer): voi
 		$fix = $phpcsFile->addFixableError(
 			'Invalid comment type /* */ for inline documentation comment, use /** */.',
 			$commentOpenPointer,
-			self::CODE_INVALID_COMMENT_TYPE
+			self::CODE_INVALID_COMMENT_TYPE,
 		);
 
 		if (!$fix) {
@@ -150,7 +148,11 @@ private function checkCommentType(File $phpcsFile, int $commentOpenPointer): voi
 		}
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->replaceToken($commentOpenPointer, sprintf('/**%s', substr($tokens[$commentOpenPointer]['content'], 2)));
+		FixerHelper::replace(
+			$phpcsFile,
+			$commentOpenPointer,
+			sprintf('/**%s', substr($tokens[$commentOpenPointer]['content'], 2)),
+		);
 		$phpcsFile->fixer->endChangeset();
 	}
 
@@ -186,10 +188,10 @@ private function checkFormat(File $phpcsFile, array $annotations): void
 					sprintf(
 						'Invalid inline documentation comment format "@var %1$s", expected "@var type %2$s Optional description".',
 						$annotationContent,
-						$variableName
+						$variableName,
 					),
 					$annotation->getStartPointer(),
-					self::CODE_INVALID_FORMAT
+					self::CODE_INVALID_FORMAT,
 				);
 
 				continue;
@@ -200,10 +202,10 @@ private function checkFormat(File $phpcsFile, array $annotations): void
 					'Invalid inline documentation comment format "@var %1$s", expected "@var %2$s %3$s".',
 					$annotationContent,
 					$type,
-					$variableName
+					$variableName,
 				),
 				$annotation->getStartPointer(),
-				self::CODE_INVALID_FORMAT
+				self::CODE_INVALID_FORMAT,
 			);
 
 			if (!$fix) {
@@ -212,13 +214,14 @@ private function checkFormat(File $phpcsFile, array $annotations): void
 
 			$phpcsFile->fixer->beginChangeset();
 
-			$phpcsFile->fixer->addContent(
+			FixerHelper::add(
+				$phpcsFile,
 				$annotation->getStartPointer(),
 				sprintf(
 					' %s %s ',
 					$type,
-					$variableName
-				)
+					$variableName,
+				),
 			);
 
 			FixerHelper::removeBetweenIncluding($phpcsFile, $annotation->getStartPointer() + 1, $annotation->getEndPointer());
@@ -373,7 +376,7 @@ private function checkVariable(File $phpcsFile, array $annotations, int $docComm
 						T_VARIABLE,
 						$variableName,
 						$listParenthesisOpener + 1,
-						$tokens[$listParenthesisOpener]['parenthesis_closer']
+						$tokens[$listParenthesisOpener]['parenthesis_closer'],
 					);
 					if ($variablePointerInList === null) {
 						if ($tryNo === 2) {
@@ -398,7 +401,7 @@ private function checkVariable(File $phpcsFile, array $annotations, int $docComm
 						T_VARIABLE,
 						$variableName,
 						$codePointer + 1,
-						$tokens[$codePointer]['bracket_closer']
+						$tokens[$codePointer]['bracket_closer'],
 					);
 					if ($variablePointerInList === null) {
 						if ($tryNo === 2) {
@@ -414,7 +417,7 @@ private function checkVariable(File $phpcsFile, array $annotations, int $docComm
 						T_VARIABLE,
 						$variableName,
 						$tokens[$codePointer]['parenthesis_opener'] + 1,
-						$tokens[$codePointer]['parenthesis_closer']
+						$tokens[$codePointer]['parenthesis_closer'],
 					);
 					if ($parameterPointer === null) {
 						if ($tryNo === 2) {
@@ -431,7 +434,7 @@ private function checkVariable(File $phpcsFile, array $annotations, int $docComm
 							T_VARIABLE,
 							$variableName,
 							$tokens[$codePointer]['parenthesis_opener'] + 1,
-							$tokens[$codePointer]['parenthesis_closer']
+							$tokens[$codePointer]['parenthesis_closer'],
 						);
 						if ($variablePointerInWhile === null) {
 							if ($tryNo === 2) {
@@ -454,14 +457,14 @@ private function checkVariable(File $phpcsFile, array $annotations, int $docComm
 							$phpcsFile,
 							T_AS,
 							$tokens[$codePointer]['parenthesis_opener'] + 1,
-							$tokens[$codePointer]['parenthesis_closer']
+							$tokens[$codePointer]['parenthesis_closer'],
 						);
 						$variablePointerInForeach = TokenHelper::findNextContent(
 							$phpcsFile,
 							T_VARIABLE,
 							$variableName,
 							$asPointer + 1,
-							$tokens[$codePointer]['parenthesis_closer']
+							$tokens[$codePointer]['parenthesis_closer'],
 						);
 						if ($variablePointerInForeach === null) {
 							if ($tryNo === 2) {
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/RequireOneLinePropertyDocCommentSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/RequireOneLinePropertyDocCommentSniff.php
index 0c04e2d20..2749bd466 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/RequireOneLinePropertyDocCommentSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/RequireOneLinePropertyDocCommentSniff.php
@@ -54,7 +54,7 @@ protected function addError(File $phpcsFile, int $docCommentStartPointer): bool
 		return $phpcsFile->addFixableError(
 			sprintf($error, PropertyHelper::getFullyQualifiedName($phpcsFile, $propertyPointer)),
 			$docCommentStartPointer,
-			self::CODE_MULTI_LINE_PROPERTY_COMMENT
+			self::CODE_MULTI_LINE_PROPERTY_COMMENT,
 		);
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/UselessFunctionDocCommentSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/UselessFunctionDocCommentSniff.php
index 502b058ec..180563a78 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/UselessFunctionDocCommentSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/UselessFunctionDocCommentSniff.php
@@ -23,10 +23,10 @@ class UselessFunctionDocCommentSniff implements Sniff
 	public const CODE_USELESS_DOC_COMMENT = 'UselessDocComment';
 
 	/** @var list */
-	public $traversableTypeHints = [];
+	public array $traversableTypeHints = [];
 
-	/** @var array|null */
-	private $normalizedTraversableTypeHints;
+	/** @var list|null */
+	private ?array $normalizedTraversableTypeHints = null;
 
 	/**
 	 * @return array
@@ -66,7 +66,7 @@ public function process(File $phpcsFile, $functionPointer): void
 				$functionPointer,
 				$returnTypeHint,
 				$returnAnnotation,
-				$this->getTraversableTypeHints()
+				$this->getTraversableTypeHints(),
 			)
 		) {
 			return;
@@ -85,7 +85,7 @@ public function process(File $phpcsFile, $functionPointer): void
 				$functionPointer,
 				$parameterTypeHints[$parameterName],
 				$parameterAnnotation,
-				$this->getTraversableTypeHints()
+				$this->getTraversableTypeHints(),
 			)) {
 				return;
 			}
@@ -101,10 +101,10 @@ public function process(File $phpcsFile, $functionPointer): void
 			sprintf(
 				'%s %s() does not need documentation comment.',
 				FunctionHelper::getTypeLabel($phpcsFile, $functionPointer),
-				FunctionHelper::getFullyQualifiedName($phpcsFile, $functionPointer)
+				FunctionHelper::getFullyQualifiedName($phpcsFile, $functionPointer),
 			),
 			$functionPointer,
-			self::CODE_USELESS_DOC_COMMENT
+			self::CODE_USELESS_DOC_COMMENT,
 		);
 		if (!$fix) {
 			return;
@@ -126,16 +126,17 @@ public function process(File $phpcsFile, $functionPointer): void
 	}
 
 	/**
-	 * @return array
+	 * @return list
 	 */
 	private function getTraversableTypeHints(): array
 	{
 		if ($this->normalizedTraversableTypeHints === null) {
-			$this->normalizedTraversableTypeHints = array_map(static function (string $typeHint): string {
-				return NamespaceHelper::isFullyQualifiedName($typeHint)
-					? $typeHint
-					: sprintf('%s%s', NamespaceHelper::NAMESPACE_SEPARATOR, $typeHint);
-			}, SniffSettingsHelper::normalizeArray($this->traversableTypeHints));
+			$this->normalizedTraversableTypeHints = array_map(
+				static fn (string $typeHint): string => NamespaceHelper::isFullyQualifiedName($typeHint)
+						? $typeHint
+						: sprintf('%s%s', NamespaceHelper::NAMESPACE_SEPARATOR, $typeHint),
+				SniffSettingsHelper::normalizeArray($this->traversableTypeHints),
+			);
 		}
 		return $this->normalizedTraversableTypeHints;
 	}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/UselessInheritDocCommentSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/UselessInheritDocCommentSniff.php
index 4add28612..e36d8bcb1 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/UselessInheritDocCommentSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Commenting/UselessInheritDocCommentSniff.php
@@ -8,7 +8,6 @@
 use SlevomatCodingStandard\Helpers\FunctionHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use SlevomatCodingStandard\Helpers\TypeHintHelper;
-use function array_merge;
 use function in_array;
 use function preg_match;
 use const T_ATTRIBUTE;
@@ -56,8 +55,8 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 		do {
 			$docCommentOwnerPointer = TokenHelper::findNext(
 				$phpcsFile,
-				array_merge(TokenHelper::$functionTokenCodes, TokenHelper::getTypeHintTokenCodes(), [T_ATTRIBUTE]),
-				$searchPointer
+				[...TokenHelper::FUNCTION_TOKEN_CODES, ...TokenHelper::TYPE_HINT_TOKEN_CODES, T_ATTRIBUTE],
+				$searchPointer,
 			);
 
 			if ($docCommentOwnerPointer === null) {
@@ -73,7 +72,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 
 		} while (true);
 
-		if (in_array($tokens[$docCommentOwnerPointer]['code'], TokenHelper::$functionTokenCodes, true)) {
+		if (in_array($tokens[$docCommentOwnerPointer]['code'], TokenHelper::FUNCTION_TOKEN_CODES, true)) {
 			$returnTypeHint = FunctionHelper::findReturnTypeHint($phpcsFile, $docCommentOwnerPointer);
 			if ($returnTypeHint === null) {
 				return;
@@ -98,7 +97,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 		$fix = $phpcsFile->addFixableError(
 			'Useless documentation comment with @inheritDoc.',
 			$docCommentOpenPointer,
-			self::CODE_USELESS_INHERIT_DOC_COMMENT
+			self::CODE_USELESS_INHERIT_DOC_COMMENT,
 		);
 
 		if (!$fix) {
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Complexity/CognitiveSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Complexity/CognitiveSniff.php
index a42830ad3..5532fa9f3 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Complexity/CognitiveSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Complexity/CognitiveSniff.php
@@ -6,6 +6,7 @@
 use PHP_CodeSniffer\Sniffs\Sniff;
 use PHP_CodeSniffer\Util\Tokens;
 use SlevomatCodingStandard\Helpers\FunctionHelper;
+use SlevomatCodingStandard\Helpers\TokenHelper;
 use function array_filter;
 use function array_pop;
 use function array_splice;
@@ -28,6 +29,7 @@
 use const T_IF;
 use const T_INLINE_ELSE;
 use const T_INLINE_THEN;
+use const T_OPEN_CURLY_BRACKET;
 use const T_OPEN_PARENTHESIS;
 use const T_SEMICOLON;
 use const T_SWITCH;
@@ -105,22 +107,20 @@ class CognitiveSniff implements Sniff
 	 * @deprecated
 	 * @var ?int maximum allowed complexity
 	 */
-	public $maxComplexity = null;
+	public ?int $maxComplexity = null;
 
 	/** @var int complexity which will raise warning */
-	public $warningThreshold = 6;
+	public int $warningThreshold = 6;
 
 	/** @var int complexity which will raise error */
-	public $errorThreshold = 6;
+	public int $errorThreshold = 6;
 
-	/** @var int */
-	private $cognitiveComplexity = 0;
+	private int $cognitiveComplexity = 0;
 
 	/** @var int|string */
 	private $lastBooleanOperator = 0;
 
-	/** @var File */
-	private $phpcsFile;
+	private File $phpcsFile;
 
 	/**
 	 * @return array
@@ -235,9 +235,9 @@ public function computeForFunctionFromTokensAndPosition(int $position): int
 			if (!$addNestingIncrement) {
 				continue;
 			}
-			$measuredNestingLevel = count(array_filter($levelStack, static function (array $token) {
-				return in_array($token['code'], self::NESTING_INCREMENTS, true);
-			}));
+			$measuredNestingLevel = count(
+				array_filter($levelStack, static fn (array $token) => in_array($token['code'], self::NESTING_INCREMENTS, true)),
+			);
 			if ($isNestingToken) {
 				$measuredNestingLevel--;
 			}
@@ -250,6 +250,16 @@ public function computeForFunctionFromTokensAndPosition(int $position): int
 		return $this->cognitiveComplexity;
 	}
 
+	protected function isPartOfDo(File $phpcsFile, int $whilePointer): bool
+	{
+		$tokens = $phpcsFile->getTokens();
+
+		$parenthesisCloserPointer = $tokens[$whilePointer]['parenthesis_closer'];
+		$pointerAfterParenthesisCloser = TokenHelper::findNextEffective($phpcsFile, $parenthesisCloserPointer + 1);
+
+		return $tokens[$pointerAfterParenthesisCloser]['code'] !== T_OPEN_CURLY_BRACKET;
+	}
+
 	/**
 	 * Keep track of consecutive matching boolean operators, that don't receive increment.
 	 *
@@ -288,7 +298,9 @@ private function isIncrementingToken(array $token, array $tokens, int $position)
 		$code = $token['code'];
 
 		if (isset(self::INCREMENTS[$code])) {
-			return true;
+			return $token['code'] === T_WHILE
+				? !$this->isPartOfDo($this->phpcsFile, $position)
+				: true;
 		}
 
 		// B1. ternary operator
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/AbstractControlStructureSpacing.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/AbstractControlStructureSpacing.php
index 2c1bb8077..bb78ca8ae 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/AbstractControlStructureSpacing.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/AbstractControlStructureSpacing.php
@@ -13,7 +13,6 @@
 use Throwable;
 use function array_key_exists;
 use function array_map;
-use function array_values;
 use function count;
 use function in_array;
 use function sprintf;
@@ -82,7 +81,7 @@ abstract class AbstractControlStructureSpacing implements Sniff
 	protected const KEYWORD_YIELD_FROM = 'yield_from';
 
 	/** @var array<(string|int)>|null */
-	private $tokensToCheck;
+	private ?array $tokensToCheck = null;
 
 	/**
 	 * @return list
@@ -167,7 +166,7 @@ protected function checkLinesBefore(File $phpcsFile, int $controlStructurePointe
 			$whitespaceBefore .= substr($tokens[$pointerBefore]['content'], strlen('eolChar)) === $phpcsFile->eolChar;
 		if ($hasCommentWithLineEndBefore) {
 			$whitespaceBefore .= $phpcsFile->eolChar;
@@ -192,12 +191,12 @@ protected function checkLinesBefore(File $phpcsFile, int $controlStructurePointe
 				$requiredLinesCountBefore,
 				$requiredLinesCountBefore === 1 ? '' : 's',
 				$tokens[$controlStructurePointer]['content'],
-				$actualLinesCountBefore
+				$actualLinesCountBefore,
 			),
 			$controlStructurePointer,
 			$isFirstControlStructure
 				? self::CODE_INCORRECT_LINES_COUNT_BEFORE_FIRST_CONTROL_STRUCTURE
-				: self::CODE_INCORRECT_LINES_COUNT_BEFORE_CONTROL_STRUCTURE
+				: self::CODE_INCORRECT_LINES_COUNT_BEFORE_CONTROL_STRUCTURE,
 		);
 
 		if (!$fix) {
@@ -208,19 +207,23 @@ protected function checkLinesBefore(File $phpcsFile, int $controlStructurePointe
 			$phpcsFile,
 			T_WHITESPACE,
 			$phpcsFile->eolChar,
-			$controlStructureStartPointer - 1
+			$controlStructureStartPointer - 1,
 		);
 
 		$phpcsFile->fixer->beginChangeset();
 
 		if ($tokens[$pointerBefore]['code'] === T_OPEN_TAG) {
-			$phpcsFile->fixer->replaceToken($pointerBefore, 'fixer->addNewline($pointerBefore);
@@ -262,11 +265,13 @@ protected function checkLinesAfter(File $phpcsFile, int $controlStructurePointer
 		$isCommentAfterOnSameLine = false;
 		$pointerAfter = $notWhitespacePointerAfter;
 
-		$isControlStructureEndAfterPointer = static function (int $pointer) use ($tokens, $controlStructurePointer): bool {
-			return in_array($tokens[$controlStructurePointer]['code'], [T_CASE, T_DEFAULT], true)
+		$isControlStructureEndAfterPointer = static fn (int $pointer): bool => in_array(
+			$tokens[$controlStructurePointer]['code'],
+			[T_CASE, T_DEFAULT],
+			true,
+		)
 				? $tokens[$pointer]['code'] === T_CLOSE_CURLY_BRACKET
 				: in_array($tokens[$pointer]['code'], [T_CLOSE_CURLY_BRACKET, T_CASE, T_DEFAULT], true);
-		};
 
 		if ($hasCommentAfter) {
 			if ($tokens[$notWhitespacePointerAfter]['line'] === $tokens[$controlStructureEndPointer]['line'] + 1) {
@@ -300,12 +305,12 @@ protected function checkLinesAfter(File $phpcsFile, int $controlStructurePointer
 				$requiredLinesCountAfter,
 				$requiredLinesCountAfter === 1 ? '' : 's',
 				$tokens[$controlStructurePointer]['content'],
-				$actualLinesCountAfter
+				$actualLinesCountAfter,
 			),
 			$controlStructurePointer,
 			$isLastControlStructure
 				? self::CODE_INCORRECT_LINES_COUNT_AFTER_LAST_CONTROL_STRUCTURE
-				: self::CODE_INCORRECT_LINES_COUNT_AFTER_CONTROL_STRUCTURE
+				: self::CODE_INCORRECT_LINES_COUNT_AFTER_CONTROL_STRUCTURE,
 		);
 
 		if (!$fix) {
@@ -362,7 +367,7 @@ private function getTokensToCheck(): array
 				self::KEYWORD_YIELD_FROM => T_YIELD_FROM,
 			];
 
-			$this->tokensToCheck = array_values(array_map(
+			$this->tokensToCheck = array_map(
 				static function (string $keyword) use ($supportedKeywords, $supportedTokens) {
 					if (!in_array($keyword, $supportedKeywords, true)) {
 						throw new UnsupportedKeywordException($keyword);
@@ -370,13 +375,11 @@ static function (string $keyword) use ($supportedKeywords, $supportedTokens) {
 
 					return $supportedTokens[$keyword];
 				},
-				SniffSettingsHelper::normalizeArray($this->getKeywordsToCheck())
-			));
+				SniffSettingsHelper::normalizeArray($this->getKeywordsToCheck()),
+			);
 
 			if (count($this->tokensToCheck) === 0) {
-				$this->tokensToCheck = array_map(static function (string $keyword) use ($supportedTokens) {
-					return $supportedTokens[$keyword];
-				}, $supportedKeywords);
+				$this->tokensToCheck = array_map(static fn (string $keyword) => $supportedTokens[$keyword], $supportedKeywords);
 			}
 		}
 
@@ -394,7 +397,7 @@ private function findControlStructureEnd(File $phpcsFile, int $controlStructureP
 
 			$pointerAfterParenthesisCloser = TokenHelper::findNextEffective(
 				$phpcsFile,
-				$tokens[$controlStructurePointer]['parenthesis_closer'] + 1
+				$tokens[$controlStructurePointer]['parenthesis_closer'] + 1,
 			);
 			if ($pointerAfterParenthesisCloser !== null && $tokens[$pointerAfterParenthesisCloser]['code'] === T_COLON) {
 				throw new Exception('"if" without curly braces is not supported.');
@@ -456,7 +459,7 @@ private function findControlStructureEnd(File $phpcsFile, int $controlStructureP
 				$phpcsFile,
 				[T_CASE, T_DEFAULT],
 				$controlStructurePointer + 1,
-				$tokens[$switchPointer]['scope_closer']
+				$tokens[$switchPointer]['scope_closer'],
 			);
 
 			foreach ($pointers as $pointer) {
@@ -469,7 +472,7 @@ private function findControlStructureEnd(File $phpcsFile, int $controlStructureP
 						$pointerBeforeCaseOrDefault = TokenHelper::findPreviousExcluding(
 							$phpcsFile,
 							T_WHITESPACE,
-							$pointerBeforeCaseOrDefault - 1
+							$pointerBeforeCaseOrDefault - 1,
 						);
 					}
 
@@ -483,7 +486,7 @@ private function findControlStructureEnd(File $phpcsFile, int $controlStructureP
 		$nextPointer = TokenHelper::findNext(
 			$phpcsFile,
 			[T_SEMICOLON, T_ANON_CLASS, T_CLOSURE, T_FN, T_OPEN_SHORT_ARRAY],
-			$controlStructurePointer + 1
+			$controlStructurePointer + 1,
 		);
 		if ($tokens[$nextPointer]['code'] === T_SEMICOLON) {
 			return $nextPointer;
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/AbstractLineCondition.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/AbstractLineCondition.php
index 613a94da8..9609385c6 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/AbstractLineCondition.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/AbstractLineCondition.php
@@ -4,7 +4,6 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
-use SlevomatCodingStandard\Helpers\IndentationHelper;
 use SlevomatCodingStandard\Helpers\SniffSettingsHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use function array_key_exists;
@@ -26,7 +25,7 @@ abstract class AbstractLineCondition implements Sniff
 	protected const DO_CONTROL_STRUCTURE = 'do';
 
 	/** @var list */
-	public $checkedControlStructures = [
+	public array $checkedControlStructures = [
 		self::IF_CONTROL_STRUCTURE,
 		self::WHILE_CONTROL_STRUCTURE,
 		self::DO_CONTROL_STRUCTURE,
@@ -108,7 +107,7 @@ protected function getLineStart(File $phpcsFile, int $pointer): string
 	{
 		$firstPointerOnLine = TokenHelper::findFirstTokenOnLine($phpcsFile, $pointer);
 
-		return IndentationHelper::convertTabsToSpaces($phpcsFile, TokenHelper::getContent($phpcsFile, $firstPointerOnLine, $pointer));
+		return TokenHelper::getContent($phpcsFile, $firstPointerOnLine, $pointer);
 	}
 
 	protected function getCondition(File $phpcsFile, int $parenthesisOpenerPointer, int $parenthesisCloserPointer): string
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/AssignmentInConditionSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/AssignmentInConditionSniff.php
index 56165449e..8042fb98a 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/AssignmentInConditionSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/AssignmentInConditionSniff.php
@@ -19,8 +19,7 @@ class AssignmentInConditionSniff implements Sniff
 
 	public const CODE_ASSIGNMENT_IN_CONDITION = 'AssignmentInCondition';
 
-	/** @var bool */
-	public $ignoreAssignmentsInsideFunctionCalls = false;
+	public bool $ignoreAssignmentsInsideFunctionCalls = false;
 
 	/**
 	 * @return array
@@ -80,9 +79,9 @@ private function processCondition(File $phpcsFile, int $parenthesisOpener, int $
 		$tokens = $phpcsFile->getTokens();
 
 		foreach ($equalsTokenPointers as $equalsTokenPointer) {
+			/** @var non-empty-list $parenthesisStarts */
 			$parenthesisStarts = array_keys($tokens[$equalsTokenPointer]['nested_parenthesis']);
 
-			/** @var int $insideParenthesis */
 			$insideParenthesis = max($parenthesisStarts);
 			if ($insideParenthesis === $parenthesisOpener) {
 				$this->error($phpcsFile, $conditionType, $equalsTokenPointer);
@@ -91,9 +90,9 @@ private function processCondition(File $phpcsFile, int $parenthesisOpener, int $
 
 			$functionCall = TokenHelper::findPrevious(
 				$phpcsFile,
-				TokenHelper::getOnlyNameTokenCodes(),
+				TokenHelper::ONLY_NAME_TOKEN_CODES,
 				$insideParenthesis,
-				$parenthesisOpener
+				$parenthesisOpener,
 			);
 			if ($functionCall !== null) {
 				continue;
@@ -108,7 +107,7 @@ private function error(File $phpcsFile, string $conditionType, int $equalsTokenP
 		$phpcsFile->addError(
 			sprintf('Assignment in %s condition is not allowed.', $conditionType),
 			$equalsTokenPointer,
-			self::CODE_ASSIGNMENT_IN_CONDITION
+			self::CODE_ASSIGNMENT_IN_CONDITION,
 		);
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/BlockControlStructureSpacingSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/BlockControlStructureSpacingSniff.php
index ab7821ab1..3247e2247 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/BlockControlStructureSpacingSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/BlockControlStructureSpacingSniff.php
@@ -13,20 +13,16 @@
 class BlockControlStructureSpacingSniff extends AbstractControlStructureSpacing
 {
 
-	/** @var int */
-	public $linesCountBefore = 1;
+	public int $linesCountBefore = 1;
 
-	/** @var int */
-	public $linesCountBeforeFirst = 0;
+	public int $linesCountBeforeFirst = 0;
 
-	/** @var int */
-	public $linesCountAfter = 1;
+	public int $linesCountAfter = 1;
 
-	/** @var int */
-	public $linesCountAfterLast = 0;
+	public int $linesCountAfterLast = 0;
 
 	/** @var list */
-	public $controlStructures = [];
+	public array $controlStructures = [];
 
 	/**
 	 * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/DisallowContinueWithoutIntegerOperandInSwitchSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/DisallowContinueWithoutIntegerOperandInSwitchSniff.php
index 69bfc566d..f3f94e918 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/DisallowContinueWithoutIntegerOperandInSwitchSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/DisallowContinueWithoutIntegerOperandInSwitchSniff.php
@@ -4,6 +4,7 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use function array_reverse;
 use function current;
@@ -48,7 +49,7 @@ public function process(File $phpcsFile, $continuePointer): void
 		$fix = $phpcsFile->addFixableError(
 			'Usage of "continue" without integer operand in "switch" is disallowed, use "break" instead.',
 			$continuePointer,
-			self::CODE_DISALLOWED_CONTINUE_WITHOUT_INTEGER_OPERAND_IN_SWITCH
+			self::CODE_DISALLOWED_CONTINUE_WITHOUT_INTEGER_OPERAND_IN_SWITCH,
 		);
 
 		if (!$fix) {
@@ -56,7 +57,7 @@ public function process(File $phpcsFile, $continuePointer): void
 		}
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->replaceToken($continuePointer, 'break');
+		FixerHelper::replace($phpcsFile, $continuePointer, 'break');
 		$phpcsFile->fixer->endChangeset();
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/DisallowShortTernaryOperatorSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/DisallowShortTernaryOperatorSniff.php
index 59c1eba76..dc9fed5f1 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/DisallowShortTernaryOperatorSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/DisallowShortTernaryOperatorSniff.php
@@ -4,6 +4,7 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use function sprintf;
 use const T_INLINE_ELSE;
@@ -15,8 +16,7 @@ class DisallowShortTernaryOperatorSniff implements Sniff
 
 	public const CODE_DISALLOWED_SHORT_TERNARY_OPERATOR = 'DisallowedShortTernaryOperator';
 
-	/** @var bool */
-	public $fixable = true;
+	public bool $fixable = true;
 
 	/**
 	 * @return array
@@ -64,7 +64,11 @@ public function process(File $phpcsFile, $inlineThenPointer): void
 
 		$phpcsFile->fixer->beginChangeset();
 
-		$phpcsFile->fixer->addContent($inlineThenPointer, sprintf(' %s ', $tokens[$previousPointer]['content']));
+		FixerHelper::add(
+			$phpcsFile,
+			$inlineThenPointer,
+			sprintf(' %s ', $tokens[$previousPointer]['content']),
+		);
 
 		$phpcsFile->fixer->endChangeset();
 	}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/DisallowTrailingMultiLineTernaryOperatorSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/DisallowTrailingMultiLineTernaryOperatorSniff.php
index f37763053..1a2657330 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/DisallowTrailingMultiLineTernaryOperatorSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/DisallowTrailingMultiLineTernaryOperatorSniff.php
@@ -47,7 +47,7 @@ public function process(File $phpcsFile, $inlineThenPointer): void
 		$fix = $phpcsFile->addFixableError(
 			'Ternary operator should be reformatted as leading the line.',
 			$inlineThenPointer,
-			self::CODE_TRAILING_MULTI_LINE_TERNARY_OPERATOR_USED
+			self::CODE_TRAILING_MULTI_LINE_TERNARY_OPERATOR_USED,
 		);
 
 		if (!$fix) {
@@ -62,10 +62,11 @@ public function process(File $phpcsFile, $inlineThenPointer): void
 		$pointerAfterInlineElse = TokenHelper::findNextExcluding($phpcsFile, [T_WHITESPACE], $inlineElsePointer + 1);
 
 		$indentation = IndentationHelper::addIndentation(
+			$phpcsFile,
 			IndentationHelper::getIndentation(
 				$phpcsFile,
-				TokenHelper::findFirstNonWhitespaceOnLine($phpcsFile, $inlineThenPointer)
-			)
+				TokenHelper::findFirstNonWhitespaceOnLine($phpcsFile, $inlineThenPointer),
+			),
 		);
 
 		$phpcsFile->fixer->beginChangeset();
@@ -73,14 +74,14 @@ public function process(File $phpcsFile, $inlineThenPointer): void
 		FixerHelper::removeBetween($phpcsFile, $pointerBeforeInlineThen, $inlineThenPointer);
 		FixerHelper::removeBetween($phpcsFile, $inlineThenPointer, $pointerAfterInlineThen);
 
-		$phpcsFile->fixer->addContentBefore($inlineThenPointer, $phpcsFile->eolChar . $indentation);
-		$phpcsFile->fixer->addContentBefore($pointerAfterInlineThen, ' ');
+		FixerHelper::addBefore($phpcsFile, $inlineThenPointer, $phpcsFile->eolChar . $indentation);
+		FixerHelper::addBefore($phpcsFile, $pointerAfterInlineThen, ' ');
 
 		FixerHelper::removeBetween($phpcsFile, $pointerBeforeInlineElse, $inlineElsePointer);
 		FixerHelper::removeBetween($phpcsFile, $inlineElsePointer, $pointerAfterInlineElse);
 
-		$phpcsFile->fixer->addContentBefore($inlineElsePointer, $phpcsFile->eolChar . $indentation);
-		$phpcsFile->fixer->addContentBefore($pointerAfterInlineElse, ' ');
+		FixerHelper::addBefore($phpcsFile, $inlineElsePointer, $phpcsFile->eolChar . $indentation);
+		FixerHelper::addBefore($phpcsFile, $pointerAfterInlineElse, ' ');
 
 		$phpcsFile->fixer->endChangeset();
 	}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/EarlyExitSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/EarlyExitSniff.php
index fd33700a3..38c93bcb1 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/EarlyExitSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/EarlyExitSniff.php
@@ -38,14 +38,11 @@ class EarlyExitSniff implements Sniff
 	public const CODE_USELESS_ELSEIF = 'UselessElseIf';
 	public const CODE_USELESS_ELSE = 'UselessElse';
 
-	/** @var bool */
-	public $ignoreStandaloneIfInScope = false;
+	public bool $ignoreStandaloneIfInScope = false;
 
-	/** @var bool */
-	public $ignoreOneLineTrailingIf = false;
+	public bool $ignoreOneLineTrailingIf = false;
 
-	/** @var bool */
-	public $ignoreTrailingIfWithOneInstruction = false;
+	public bool $ignoreTrailingIfWithOneInstruction = false;
 
 	/**
 	 * @return array
@@ -96,7 +93,7 @@ private function processElse(File $phpcsFile, int $elsePointer): void
 			$phpcsFile,
 			T_FUNCTION,
 			$tokens[$elsePointer]['scope_opener'] + 1,
-			$tokens[$elsePointer]['scope_closer']
+			$tokens[$elsePointer]['scope_closer'],
 		) !== null) {
 			return;
 		}
@@ -111,7 +108,7 @@ private function processElse(File $phpcsFile, int $elsePointer): void
 			$conditionEarlyExitPointer = $this->findEarlyExitInScope(
 				$phpcsFile,
 				$tokens[$conditionPointer]['scope_opener'],
-				$tokens[$conditionPointer]['scope_closer']
+				$tokens[$conditionPointer]['scope_closer'],
 			);
 
 			if ($conditionPointer === $elsePointer) {
@@ -148,12 +145,12 @@ private function processElse(File $phpcsFile, int $elsePointer): void
 			$negativeIfCondition = ConditionHelper::getNegativeCondition(
 				$phpcsFile,
 				$tokens[$ifPointer]['parenthesis_opener'],
-				$tokens[$ifPointer]['parenthesis_closer']
+				$tokens[$ifPointer]['parenthesis_closer'],
 			);
-			$afterIfCode = IndentationHelper::fixIndentation(
+			$afterIfCode = IndentationHelper::removeIndentation(
 				$phpcsFile,
 				$ifCodePointers,
-				IndentationHelper::getIndentation($phpcsFile, $ifPointer)
+				IndentationHelper::getIndentation($phpcsFile, $ifPointer),
 			);
 
 			$ifContent = sprintf('if %s {%s}%s%s', $negativeIfCondition, $elseCode, $phpcsFile->eolChar, $afterIfCode);
@@ -174,10 +171,10 @@ private function processElse(File $phpcsFile, int $elsePointer): void
 		}
 
 		$elseCodePointers = $this->getScopeCodePointers($phpcsFile, $elsePointer);
-		$afterIfCode = IndentationHelper::fixIndentation(
+		$afterIfCode = IndentationHelper::removeIndentation(
 			$phpcsFile,
 			$elseCodePointers,
-			IndentationHelper::getIndentation($phpcsFile, $ifPointer)
+			IndentationHelper::getIndentation($phpcsFile, $ifPointer),
 		);
 
 		$phpcsFile->fixer->beginChangeset();
@@ -188,7 +185,7 @@ private function processElse(File $phpcsFile, int $elsePointer): void
 			$phpcsFile,
 			$tokens[$previousConditionPointer]['scope_closer'] + 1,
 			$tokens[$elsePointer]['scope_closer'],
-			$previousConditionContent
+			$previousConditionContent,
 		);
 
 		$phpcsFile->fixer->endChangeset();
@@ -209,7 +206,7 @@ private function processElseIf(File $phpcsFile, int $elseIfPointer): void
 			$phpcsFile,
 			T_FUNCTION,
 			$tokens[$elseIfPointer]['scope_opener'] + 1,
-			$tokens[$elseIfPointer]['scope_closer']
+			$tokens[$elseIfPointer]['scope_closer'],
 		) !== null) {
 			return;
 		}
@@ -218,7 +215,7 @@ private function processElseIf(File $phpcsFile, int $elseIfPointer): void
 			$conditionEarlyExitPointer = $this->findEarlyExitInScope(
 				$phpcsFile,
 				$tokens[$conditionPointer]['scope_opener'],
-				$tokens[$conditionPointer]['scope_closer']
+				$tokens[$conditionPointer]['scope_closer'],
 			);
 
 			if ($conditionPointer === $elseIfPointer) {
@@ -246,9 +243,10 @@ private function processElseIf(File $phpcsFile, int $elseIfPointer): void
 		$phpcsFile->fixer->addNewline($pointerBeforeElseIfPointer);
 		$phpcsFile->fixer->addNewline($pointerBeforeElseIfPointer);
 
-		$phpcsFile->fixer->replaceToken(
+		FixerHelper::replace(
+			$phpcsFile,
 			$elseIfPointer,
-			sprintf('%sif', IndentationHelper::getIndentation($phpcsFile, $allConditionsPointers[0]))
+			sprintf('%sif', IndentationHelper::getIndentation($phpcsFile, $allConditionsPointers[0])),
 		);
 
 		$phpcsFile->fixer->endChangeset();
@@ -295,7 +293,7 @@ private function processIf(File $phpcsFile, int $ifPointer): void
 						$phpcsFile,
 						T_SEMICOLON,
 						$searchStartPointer,
-						$pointerBeforeScopeCloser
+						$pointerBeforeScopeCloser,
 					);
 					if ($anotherSemicolonPointer === null) {
 						break;
@@ -333,14 +331,14 @@ private function processIf(File $phpcsFile, int $ifPointer): void
 		$ifCodePointers = $this->getScopeCodePointers($phpcsFile, $ifPointer);
 		$ifIndentation = IndentationHelper::getIndentation($phpcsFile, $ifPointer);
 		$earlyExitCode = $this->getEarlyExitCode($tokens[$scopePointer]['code']);
-		$earlyExitCodeIndentation = IndentationHelper::addIndentation($ifIndentation);
+		$earlyExitCodeIndentation = IndentationHelper::addIndentation($phpcsFile, $ifIndentation);
 
 		$negativeIfCondition = ConditionHelper::getNegativeCondition(
 			$phpcsFile,
 			$tokens[$ifPointer]['parenthesis_opener'],
-			$tokens[$ifPointer]['parenthesis_closer']
+			$tokens[$ifPointer]['parenthesis_closer'],
 		);
-		$afterIfCode = IndentationHelper::fixIndentation($phpcsFile, $ifCodePointers, $ifIndentation);
+		$afterIfCode = IndentationHelper::removeIndentation($phpcsFile, $ifCodePointers, $ifIndentation);
 
 		$ifContent = sprintf(
 			'if %s {%s%s%s;%s%s}%s%s',
@@ -351,7 +349,7 @@ private function processIf(File $phpcsFile, int $ifPointer): void
 			$phpcsFile->eolChar,
 			$ifIndentation,
 			$phpcsFile->eolChar,
-			$afterIfCode
+			$afterIfCode,
 		);
 
 		$phpcsFile->fixer->beginChangeset();
@@ -403,7 +401,7 @@ private function findEarlyExitInScope(File $phpcsFile, int $startPointer, int $e
 				if ($this->findEarlyExitInScope(
 					$phpcsFile,
 					$tokens[$conditionPointer]['scope_opener'],
-					$tokens[$conditionPointer]['scope_closer']
+					$tokens[$conditionPointer]['scope_closer'],
 				) === null) {
 					return null;
 				}
@@ -412,7 +410,12 @@ private function findEarlyExitInScope(File $phpcsFile, int $startPointer, int $e
 
 		$lastSemicolonInScopePointer = TokenHelper::findPreviousEffective($phpcsFile, $endPointer - 1, $startPointer);
 		return $tokens[$lastSemicolonInScopePointer]['code'] === T_SEMICOLON
-			? TokenHelper::findPreviousLocal($phpcsFile, TokenHelper::$earlyExitTokenCodes, $lastSemicolonInScopePointer - 1, $startPointer)
+			? TokenHelper::findPreviousLocal(
+				$phpcsFile,
+				TokenHelper::EARLY_EXIT_TOKEN_CODES,
+				$lastSemicolonInScopePointer - 1,
+				$startPointer,
+			)
 			: null;
 	}
 
@@ -460,13 +463,13 @@ private function getAllConditionsPointers(File $phpcsFile, int $conditionPointer
 
 					if (!array_key_exists('scope_closer', $tokens[$currentConditionPointer])) {
 						throw new Exception(
-							sprintf('"%s" without curly braces is not supported.', $tokens[$currentConditionPointer]['content'])
+							sprintf('"%s" without curly braces is not supported.', $tokens[$currentConditionPointer]['content']),
 						);
 					}
 
 					$currentConditionPointer = TokenHelper::findNextEffective(
 						$phpcsFile,
-						$tokens[$currentConditionPointer]['scope_closer'] + 1
+						$tokens[$currentConditionPointer]['scope_closer'] + 1,
 					);
 				}
 			}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/JumpStatementsSpacingSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/JumpStatementsSpacingSniff.php
index 334fbbcee..b56db0244 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/JumpStatementsSpacingSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/JumpStatementsSpacingSniff.php
@@ -25,32 +25,24 @@
 class JumpStatementsSpacingSniff extends AbstractControlStructureSpacing
 {
 
-	/** @var int */
-	public $linesCountBefore = 1;
+	public int $linesCountBefore = 1;
 
-	/** @var int */
-	public $linesCountBeforeFirst = 0;
+	public int $linesCountBeforeFirst = 0;
 
-	/** @var int|null */
-	public $linesCountBeforeWhenFirstInCaseOrDefault = null;
+	public ?int $linesCountBeforeWhenFirstInCaseOrDefault = null;
 
-	/** @var int */
-	public $linesCountAfter = 1;
+	public int $linesCountAfter = 1;
 
-	/** @var int */
-	public $linesCountAfterLast = 0;
+	public int $linesCountAfterLast = 0;
 
-	/** @var int|null */
-	public $linesCountAfterWhenLastInCaseOrDefault = null;
+	public ?int $linesCountAfterWhenLastInCaseOrDefault = null;
 
-	/** @var int|null */
-	public $linesCountAfterWhenLastInLastCaseOrDefault = null;
+	public ?int $linesCountAfterWhenLastInLastCaseOrDefault = null;
 
-	/** @var bool */
-	public $allowSingleLineYieldStacking = true;
+	public bool $allowSingleLineYieldStacking = true;
 
 	/** @var list */
-	public $jumpStatements = [];
+	public array $jumpStatements = [];
 
 	/**
 	 * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
@@ -61,15 +53,15 @@ public function process(File $phpcsFile, $jumpStatementPointer): void
 		$this->linesCountBefore = SniffSettingsHelper::normalizeInteger($this->linesCountBefore);
 		$this->linesCountBeforeFirst = SniffSettingsHelper::normalizeInteger($this->linesCountBeforeFirst);
 		$this->linesCountBeforeWhenFirstInCaseOrDefault = SniffSettingsHelper::normalizeNullableInteger(
-			$this->linesCountBeforeWhenFirstInCaseOrDefault
+			$this->linesCountBeforeWhenFirstInCaseOrDefault,
 		);
 		$this->linesCountAfter = SniffSettingsHelper::normalizeInteger($this->linesCountAfter);
 		$this->linesCountAfterLast = SniffSettingsHelper::normalizeInteger($this->linesCountAfterLast);
 		$this->linesCountAfterWhenLastInCaseOrDefault = SniffSettingsHelper::normalizeNullableInteger(
-			$this->linesCountAfterWhenLastInCaseOrDefault
+			$this->linesCountAfterWhenLastInCaseOrDefault,
 		);
 		$this->linesCountAfterWhenLastInLastCaseOrDefault = SniffSettingsHelper::normalizeNullableInteger(
-			$this->linesCountAfterWhenLastInLastCaseOrDefault
+			$this->linesCountAfterWhenLastInLastCaseOrDefault,
 		);
 
 		if ($this->isOneOfYieldSpecialCases($phpcsFile, $jumpStatementPointer)) {
@@ -234,7 +226,7 @@ private function isThrowExpression(File $phpcsFile, int $jumpStatementPointer):
 		return !in_array(
 			$tokens[$pointerBefore]['code'],
 			[T_SEMICOLON, T_COLON, T_OPEN_CURLY_BRACKET, T_CLOSE_CURLY_BRACKET, T_OPEN_TAG],
-			true
+			true,
 		);
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/LanguageConstructWithParenthesesSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/LanguageConstructWithParenthesesSniff.php
index b7f4eecf8..e26ebf874 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/LanguageConstructWithParenthesesSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/LanguageConstructWithParenthesesSniff.php
@@ -4,6 +4,7 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use function in_array;
 use function sprintf;
@@ -75,7 +76,7 @@ public function process(File $phpcsFile, $languageConstructPointer): void
 		$containsContentBetweenParentheses = TokenHelper::findNextEffective(
 			$phpcsFile,
 			$openParenthesisPointer + 1,
-			$closeParenthesisPointer
+			$closeParenthesisPointer,
 		) !== null;
 		if ($tokens[$languageConstructPointer]['code'] === T_EXIT && $containsContentBetweenParentheses) {
 			return;
@@ -84,18 +85,18 @@ public function process(File $phpcsFile, $languageConstructPointer): void
 		$fix = $phpcsFile->addFixableError(
 			sprintf('Usage of language construct "%s" with parentheses is disallowed.', $tokens[$languageConstructPointer]['content']),
 			$languageConstructPointer,
-			self::CODE_USED_WITH_PARENTHESES
+			self::CODE_USED_WITH_PARENTHESES,
 		);
 		if (!$fix) {
 			return;
 		}
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->replaceToken($openParenthesisPointer, '');
+		FixerHelper::replace($phpcsFile, $openParenthesisPointer, '');
 		if ($tokens[$openParenthesisPointer - 1]['code'] !== T_WHITESPACE && $containsContentBetweenParentheses) {
-			$phpcsFile->fixer->addContent($openParenthesisPointer, ' ');
+			FixerHelper::add($phpcsFile, $openParenthesisPointer, ' ');
 		}
-		$phpcsFile->fixer->replaceToken($closeParenthesisPointer, '');
+		FixerHelper::replace($phpcsFile, $closeParenthesisPointer, '');
 		$phpcsFile->fixer->endChangeset();
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/NewWithParenthesesSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/NewWithParenthesesSniff.php
index 1d0b66782..04549c213 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/NewWithParenthesesSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/NewWithParenthesesSniff.php
@@ -5,6 +5,7 @@
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
 use SlevomatCodingStandard\Helpers\AttributeHelper;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use const T_ANON_CLASS;
 use const T_ATTRIBUTE;
@@ -18,6 +19,7 @@
 use const T_INLINE_THEN;
 use const T_NEW;
 use const T_OPEN_PARENTHESIS;
+use const T_READONLY;
 use const T_SEMICOLON;
 
 class NewWithParenthesesSniff implements Sniff
@@ -49,7 +51,7 @@ public function process(File $phpcsFile, $newPointer): void
 			$nextPointer = AttributeHelper::getAttributeTarget($phpcsFile, $nextPointer);
 		}
 
-		if ($tokens[$nextPointer]['code'] === T_ANON_CLASS) {
+		if ($tokens[$nextPointer]['code'] === T_ANON_CLASS || $tokens[$nextPointer]['code'] === T_READONLY) {
 			return;
 		}
 
@@ -73,7 +75,7 @@ public function process(File $phpcsFile, $newPointer): void
 					T_CLOSE_PARENTHESIS,
 					T_DOUBLE_ARROW,
 				],
-				$shouldBeOpenParenthesisPointer
+				$shouldBeOpenParenthesisPointer,
 			);
 
 			if (
@@ -97,7 +99,7 @@ public function process(File $phpcsFile, $newPointer): void
 		$fix = $phpcsFile->addFixableError(
 			'Usage of "new" without parentheses is disallowed.',
 			$newPointer,
-			self::CODE_MISSING_PARENTHESES
+			self::CODE_MISSING_PARENTHESES,
 		);
 		if (!$fix) {
 			return;
@@ -107,7 +109,7 @@ public function process(File $phpcsFile, $newPointer): void
 		$classNameEndPointer = TokenHelper::findPreviousEffective($phpcsFile, $shouldBeOpenParenthesisPointer - 1);
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->addContent($classNameEndPointer, '()');
+		FixerHelper::add($phpcsFile, $classNameEndPointer, '()');
 		$phpcsFile->fixer->endChangeset();
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/NewWithoutParenthesesSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/NewWithoutParenthesesSniff.php
index 6ea0cfb54..378ff3ccc 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/NewWithoutParenthesesSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/NewWithoutParenthesesSniff.php
@@ -65,7 +65,7 @@ public function process(File $phpcsFile, $newPointer): void
 					T_CLOSE_PARENTHESIS,
 					T_DOUBLE_ARROW,
 				],
-				$parenthesisOpenerPointer
+				$parenthesisOpenerPointer,
 			);
 
 			if (
@@ -97,7 +97,7 @@ public function process(File $phpcsFile, $newPointer): void
 		FixerHelper::removeBetweenIncluding(
 			$phpcsFile,
 			$parenthesisOpenerPointer,
-			$tokens[$parenthesisOpenerPointer]['parenthesis_closer']
+			$tokens[$parenthesisOpenerPointer]['parenthesis_closer'],
 		);
 
 		$phpcsFile->fixer->endChangeset();
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireMultiLineConditionSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireMultiLineConditionSniff.php
index 62f911dc5..0b798ffbe 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireMultiLineConditionSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireMultiLineConditionSniff.php
@@ -20,14 +20,11 @@ class RequireMultiLineConditionSniff extends AbstractLineCondition
 
 	public const CODE_REQUIRED_MULTI_LINE_CONDITION = 'RequiredMultiLineCondition';
 
-	/** @var int */
-	public $minLineLength = 121;
+	public int $minLineLength = 121;
 
-	/** @var bool */
-	public $booleanOperatorOnPreviousLine = false;
+	public bool $booleanOperatorOnPreviousLine = false;
 
-	/** @var bool */
-	public $alwaysSplitAllConditionParts = false;
+	public bool $alwaysSplitAllConditionParts = false;
 
 	/**
 	 * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
@@ -50,7 +47,7 @@ public function process(File $phpcsFile, $controlStructurePointer): void
 			$phpcsFile,
 			Tokens::$booleanOperators,
 			$parenthesisOpenerPointer + 1,
-			$parenthesisCloserPointer
+			$parenthesisCloserPointer,
 		);
 
 		if ($booleanOperatorPointers === []) {
@@ -78,10 +75,10 @@ public function process(File $phpcsFile, $controlStructurePointer): void
 		$fix = $phpcsFile->addFixableError(
 			sprintf(
 				'Condition of "%s" should be split to more lines so each condition part is on its own line.',
-				$this->getControlStructureName($phpcsFile, $controlStructurePointer)
+				$this->getControlStructureName($phpcsFile, $controlStructurePointer),
 			),
 			$controlStructurePointer,
-			self::CODE_REQUIRED_MULTI_LINE_CONDITION
+			self::CODE_REQUIRED_MULTI_LINE_CONDITION,
 		);
 
 		if (!$fix) {
@@ -92,12 +89,12 @@ public function process(File $phpcsFile, $controlStructurePointer): void
 			$phpcsFile,
 			$conditionStartsOnNewLine
 				? $conditionStartPointer
-				: TokenHelper::findFirstNonWhitespaceOnLine($phpcsFile, $parenthesisOpenerPointer)
+				: TokenHelper::findFirstNonWhitespaceOnLine($phpcsFile, $parenthesisOpenerPointer),
 		);
 
 		$conditionIndentation = $conditionStartsOnNewLine
 			? $controlStructureIndentation
-			: IndentationHelper::addIndentation($controlStructureIndentation);
+			: IndentationHelper::addIndentation($phpcsFile, $controlStructureIndentation);
 
 		$innerConditionLevel = 0;
 
@@ -105,7 +102,7 @@ public function process(File $phpcsFile, $controlStructurePointer): void
 
 		if (!$conditionStartsOnNewLine) {
 			FixerHelper::removeWhitespaceBefore($phpcsFile, $conditionStartPointer);
-			$phpcsFile->fixer->addContentBefore($conditionStartPointer, $phpcsFile->eolChar . $conditionIndentation);
+			FixerHelper::addBefore($phpcsFile, $conditionStartPointer, $phpcsFile->eolChar . $conditionIndentation);
 		}
 
 		for ($i = $conditionStartPointer; $i <= $conditionEndPointer; $i++) {
@@ -114,7 +111,7 @@ public function process(File $phpcsFile, $controlStructurePointer): void
 					$phpcsFile,
 					Tokens::$booleanOperators,
 					$i + 1,
-					$tokens[$i]['parenthesis_closer']
+					$tokens[$i]['parenthesis_closer'],
 				) !== null;
 
 				$innerConditionLevel++;
@@ -122,16 +119,22 @@ public function process(File $phpcsFile, $controlStructurePointer): void
 				if ($containsBooleanOperator) {
 					FixerHelper::removeWhitespaceAfter($phpcsFile, $i);
 
-					$phpcsFile->fixer->addContent(
+					FixerHelper::add(
+						$phpcsFile,
 						$i,
-						$phpcsFile->eolChar . IndentationHelper::addIndentation($conditionIndentation, $innerConditionLevel)
+						$phpcsFile->eolChar . IndentationHelper::addIndentation($phpcsFile, $conditionIndentation, $innerConditionLevel),
 					);
 
 					FixerHelper::removeWhitespaceBefore($phpcsFile, $tokens[$i]['parenthesis_closer']);
 
-					$phpcsFile->fixer->addContentBefore(
+					FixerHelper::addBefore(
+						$phpcsFile,
 						$tokens[$i]['parenthesis_closer'],
-						$phpcsFile->eolChar . IndentationHelper::addIndentation($conditionIndentation, $innerConditionLevel - 1)
+						$phpcsFile->eolChar . IndentationHelper::addIndentation(
+							$phpcsFile,
+							$conditionIndentation,
+							$innerConditionLevel - 1,
+						),
 					);
 				}
 
@@ -149,11 +152,15 @@ public function process(File $phpcsFile, $controlStructurePointer): void
 
 			$innerConditionIndentation = $conditionIndentation;
 			if ($innerConditionLevel > 0) {
-				$innerConditionIndentation = IndentationHelper::addIndentation($innerConditionIndentation, $innerConditionLevel);
+				$innerConditionIndentation = IndentationHelper::addIndentation(
+					$phpcsFile,
+					$innerConditionIndentation,
+					$innerConditionLevel,
+				);
 			}
 
 			if ($this->booleanOperatorOnPreviousLine) {
-				$phpcsFile->fixer->addContent($i, $phpcsFile->eolChar . $innerConditionIndentation);
+				FixerHelper::add($phpcsFile, $i, $phpcsFile->eolChar . $innerConditionIndentation);
 
 				FixerHelper::removeWhitespaceAfter($phpcsFile, $i);
 
@@ -163,12 +170,12 @@ public function process(File $phpcsFile, $controlStructurePointer): void
 
 			FixerHelper::removeWhitespaceBefore($phpcsFile, $i);
 
-			$phpcsFile->fixer->addContentBefore($i, $phpcsFile->eolChar . $innerConditionIndentation);
+			FixerHelper::addBefore($phpcsFile, $i, $phpcsFile->eolChar . $innerConditionIndentation);
 		}
 
 		if (!$conditionEndsOnNewLine) {
 			FixerHelper::removeWhitespaceAfter($phpcsFile, $conditionEndPointer);
-			$phpcsFile->fixer->addContent($conditionEndPointer, $phpcsFile->eolChar . $controlStructureIndentation);
+			FixerHelper::add($phpcsFile, $conditionEndPointer, $phpcsFile->eolChar . $controlStructureIndentation);
 		}
 
 		$phpcsFile->fixer->endChangeset();
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireMultiLineTernaryOperatorSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireMultiLineTernaryOperatorSniff.php
index 09ae72377..d465836d8 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireMultiLineTernaryOperatorSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireMultiLineTernaryOperatorSniff.php
@@ -9,7 +9,6 @@
 use SlevomatCodingStandard\Helpers\SniffSettingsHelper;
 use SlevomatCodingStandard\Helpers\TernaryOperatorHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
-use function array_merge;
 use function in_array;
 use function strlen;
 use function substr;
@@ -25,11 +24,9 @@ class RequireMultiLineTernaryOperatorSniff implements Sniff
 
 	public const CODE_MULTI_LINE_TERNARY_OPERATOR_NOT_USED = 'MultiLineTernaryOperatorNotUsed';
 
-	/** @var int */
-	public $lineLengthLimit = 0;
+	public int $lineLengthLimit = 0;
 
-	/** @var int|null */
-	public $minExpressionsLength = null;
+	public ?int $minExpressionsLength = null;
 
 	/**
 	 * @return array
@@ -90,7 +87,7 @@ public function process(File $phpcsFile, $inlineThenPointer): void
 		$fix = $phpcsFile->addFixableError(
 			'Ternary operator should be reformatted to more lines.',
 			$inlineThenPointer,
-			self::CODE_MULTI_LINE_TERNARY_OPERATOR_NOT_USED
+			self::CODE_MULTI_LINE_TERNARY_OPERATOR_NOT_USED,
 		);
 
 		if (!$fix) {
@@ -104,12 +101,9 @@ public function process(File $phpcsFile, $inlineThenPointer): void
 		$phpcsFile->fixer->beginChangeset();
 
 		FixerHelper::removeBetween($phpcsFile, $pointerBeforeInlineThen, $inlineThenPointer);
-
-		$phpcsFile->fixer->addContentBefore($inlineThenPointer, $phpcsFile->eolChar . $indentation);
-
+		FixerHelper::addBefore($phpcsFile, $inlineThenPointer, $phpcsFile->eolChar . $indentation);
 		FixerHelper::removeBetween($phpcsFile, $pointerBeforeInlineElse, $inlineElsePointer);
-
-		$phpcsFile->fixer->addContentBefore($inlineElsePointer, $phpcsFile->eolChar . $indentation);
+		FixerHelper::addBefore($phpcsFile, $inlineElsePointer, $phpcsFile->eolChar . $indentation);
 
 		$phpcsFile->fixer->endChangeset();
 	}
@@ -124,8 +118,8 @@ private function getEndOfLineBefore(File $phpcsFile, int $pointer): int
 		while (true) {
 			$possibleEndOfLinePointer = TokenHelper::findPrevious(
 				$phpcsFile,
-				array_merge([T_WHITESPACE, T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO], TokenHelper::$inlineCommentTokenCodes),
-				$startPointer
+				[T_WHITESPACE, T_OPEN_TAG, T_OPEN_TAG_WITH_ECHO, ...TokenHelper::INLINE_COMMENT_TOKEN_CODES],
+				$startPointer,
 			);
 			if (
 				$tokens[$possibleEndOfLinePointer]['code'] === T_WHITESPACE
@@ -144,7 +138,7 @@ private function getEndOfLineBefore(File $phpcsFile, int $pointer): int
 			}
 
 			if (
-				in_array($tokens[$possibleEndOfLinePointer]['code'], TokenHelper::$inlineCommentTokenCodes, true)
+				in_array($tokens[$possibleEndOfLinePointer]['code'], TokenHelper::INLINE_COMMENT_TOKEN_CODES, true)
 				&& substr($tokens[$possibleEndOfLinePointer]['content'], -1) === $phpcsFile->eolChar
 			) {
 				$endOfLineBefore = $possibleEndOfLinePointer;
@@ -164,15 +158,7 @@ private function getIndentation(File $phpcsFile, int $endOfLinePointer): string
 		$pointerAfterWhitespace = TokenHelper::findNextNonWhitespace($phpcsFile, $endOfLinePointer + 1);
 		$actualIndentation = TokenHelper::getContent($phpcsFile, $endOfLinePointer + 1, $pointerAfterWhitespace - 1);
 
-		if (strlen($actualIndentation) !== 0) {
-			return $actualIndentation . (substr(
-				$actualIndentation,
-				-1
-			) === IndentationHelper::TAB_INDENT ? IndentationHelper::TAB_INDENT : IndentationHelper::SPACES_INDENT);
-		}
-
-		$tabPointer = TokenHelper::findPreviousContent($phpcsFile, T_WHITESPACE, IndentationHelper::TAB_INDENT, $endOfLinePointer - 1);
-		return $tabPointer !== null ? IndentationHelper::TAB_INDENT : IndentationHelper::SPACES_INDENT;
+		return IndentationHelper::addIndentation($phpcsFile, $actualIndentation);
 	}
 
 }
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireNullCoalesceEqualOperatorSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireNullCoalesceEqualOperatorSniff.php
index 03823e00f..6d966fe51 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireNullCoalesceEqualOperatorSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireNullCoalesceEqualOperatorSniff.php
@@ -7,10 +7,22 @@
 use PHP_CodeSniffer\Util\Tokens;
 use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\IdentificatorHelper;
+use SlevomatCodingStandard\Helpers\IndentationHelper;
 use SlevomatCodingStandard\Helpers\SniffSettingsHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
+use function array_keys;
+use function count;
+use function in_array;
+use function range;
+use function sprintf;
+use function trim;
 use const T_COALESCE;
+use const T_ELSE;
+use const T_ELSEIF;
 use const T_EQUAL;
+use const T_IF;
+use const T_IS_IDENTICAL;
+use const T_NULL;
 use const T_SEMICOLON;
 
 class RequireNullCoalesceEqualOperatorSniff implements Sniff
@@ -18,8 +30,9 @@ class RequireNullCoalesceEqualOperatorSniff implements Sniff
 
 	public const CODE_REQUIRED_NULL_COALESCE_EQUAL_OPERATOR = 'RequiredNullCoalesceEqualOperator';
 
-	/** @var bool|null */
-	public $enable = null;
+	public ?bool $enable = null;
+
+	public bool $checkIfConditions = false;
 
 	/**
 	 * @return array
@@ -43,6 +56,12 @@ public function process(File $phpcsFile, $equalPointer): void
 			return;
 		}
 
+		$this->checkCoalesce($phpcsFile, $equalPointer);
+		$this->checkIf($phpcsFile, $equalPointer);
+	}
+
+	private function checkCoalesce(File $phpcsFile, int $equalPointer): void
+	{
 		/** @var int $variableStartPointer */
 		$variableStartPointer = TokenHelper::findNextEffective($phpcsFile, $equalPointer + 1);
 		$variableEndPointer = IdentificatorHelper::findEndPointer($phpcsFile, $variableStartPointer);
@@ -82,7 +101,7 @@ public function process(File $phpcsFile, $equalPointer): void
 		$fix = $phpcsFile->addFixableError(
 			'Use "??=" operator instead of "=" and "??".',
 			$equalPointer,
-			self::CODE_REQUIRED_NULL_COALESCE_EQUAL_OPERATOR
+			self::CODE_REQUIRED_NULL_COALESCE_EQUAL_OPERATOR,
 		);
 
 		if (!$fix) {
@@ -96,4 +115,100 @@ public function process(File $phpcsFile, $equalPointer): void
 		$phpcsFile->fixer->endChangeset();
 	}
 
+	private function checkIf(File $phpcsFile, int $equalPointer): void
+	{
+		if (!$this->checkIfConditions) {
+			return;
+		}
+
+		$tokens = $phpcsFile->getTokens();
+
+		$conditionsCount = count($tokens[$equalPointer]['conditions']);
+		if ($conditionsCount === 0) {
+			return;
+		}
+
+		$ifPointer = array_keys($tokens[$equalPointer]['conditions'])[$conditionsCount - 1];
+		if ($tokens[$ifPointer]['code'] !== T_IF) {
+			return;
+		}
+
+		$pointerAfterIfCondition = TokenHelper::findNextEffective($phpcsFile, $tokens[$ifPointer]['scope_closer'] + 1);
+		if ($pointerAfterIfCondition !== null && in_array($tokens[$pointerAfterIfCondition]['code'], [T_ELSEIF, T_ELSE], true)) {
+			return;
+		}
+
+		$ifVariableStartPointer = TokenHelper::findNextEffective($phpcsFile, $tokens[$ifPointer]['parenthesis_opener'] + 1);
+		$ifVariableEndPointer = IdentificatorHelper::findEndPointer($phpcsFile, $ifVariableStartPointer);
+		if ($ifVariableEndPointer === null) {
+			return;
+		}
+
+		$nextIfPointer = TokenHelper::findNextEffective($phpcsFile, $ifVariableEndPointer + 1);
+		if ($tokens[$nextIfPointer]['code'] !== T_IS_IDENTICAL) {
+			return;
+		}
+
+		$nextIfPointer = TokenHelper::findNextEffective($phpcsFile, $nextIfPointer + 1);
+		if ($tokens[$nextIfPointer]['code'] !== T_NULL) {
+			return;
+		}
+
+		if (TokenHelper::findNextEffective($phpcsFile, $nextIfPointer + 1) !== $tokens[$ifPointer]['parenthesis_closer']) {
+			return;
+		}
+
+		$beforeEqualVariableStartPointer = TokenHelper::findNextEffective($phpcsFile, $tokens[$ifPointer]['scope_opener'] + 1);
+		$beforeEqualVariableEndPointer = IdentificatorHelper::findEndPointer($phpcsFile, $beforeEqualVariableStartPointer);
+		if ($beforeEqualVariableEndPointer === null) {
+			return;
+		}
+
+		if (TokenHelper::findNextEffective($phpcsFile, $beforeEqualVariableEndPointer + 1) !== $equalPointer) {
+			return;
+		}
+
+		$variableName = IdentificatorHelper::getContent($phpcsFile, $ifVariableStartPointer, $ifVariableEndPointer);
+
+		if ($variableName !== IdentificatorHelper::getContent(
+			$phpcsFile,
+			$beforeEqualVariableStartPointer,
+			$beforeEqualVariableEndPointer,
+		)) {
+			return;
+		}
+
+		$semicolonPointer = TokenHelper::findNext($phpcsFile, T_SEMICOLON, $equalPointer + 1);
+		if (TokenHelper::findNextEffective($phpcsFile, $semicolonPointer + 1) !== $tokens[$ifPointer]['scope_closer']) {
+			return;
+		}
+
+		$fix = $phpcsFile->addFixableError(
+			'Use "??=" operator instead of if condition and "=".',
+			$ifPointer,
+			self::CODE_REQUIRED_NULL_COALESCE_EQUAL_OPERATOR,
+		);
+
+		if (!$fix) {
+			return;
+		}
+
+		$codeStartPointer = TokenHelper::findNextEffective($phpcsFile, $equalPointer + 1);
+
+		$afterNullCoalesceEqualCode = IndentationHelper::removeIndentation(
+			$phpcsFile,
+			range($codeStartPointer, $semicolonPointer),
+			IndentationHelper::getIndentation($phpcsFile, $ifPointer),
+		);
+
+		$phpcsFile->fixer->beginChangeset();
+		FixerHelper::change(
+			$phpcsFile,
+			$ifPointer,
+			$tokens[$ifPointer]['scope_closer'],
+			sprintf('%s ??= %s', $variableName, trim($afterNullCoalesceEqualCode)),
+		);
+		$phpcsFile->fixer->endChangeset();
+	}
+
 }
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireNullCoalesceOperatorSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireNullCoalesceOperatorSniff.php
index 333ac6ab0..dff8ad2d7 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireNullCoalesceOperatorSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireNullCoalesceOperatorSniff.php
@@ -92,7 +92,7 @@ public function checkIsset(File $phpcsFile, int $issetPointer): void
 		$fix = $phpcsFile->addFixableError(
 			'Use null coalesce operator instead of ternary operator.',
 			$inlineThenPointer,
-			self::CODE_NULL_COALESCE_OPERATOR_NOT_USED
+			self::CODE_NULL_COALESCE_OPERATOR_NOT_USED,
 		);
 		if (!$fix) {
 			return;
@@ -142,7 +142,7 @@ public function checkIdenticalOperator(File $phpcsFile, int $identicalOperator):
 
 		$pointerBeforeCondition = TokenHelper::findPreviousEffective(
 			$phpcsFile,
-			($isYodaCondition ? $pointerBeforeIdenticalOperator : $variableStartPointer) - 1
+			($isYodaCondition ? $pointerBeforeIdenticalOperator : $variableStartPointer) - 1,
 		);
 
 		if (in_array($tokens[$pointerBeforeCondition]['code'], Tokens::$booleanOperators, true)) {
@@ -152,7 +152,7 @@ public function checkIdenticalOperator(File $phpcsFile, int $identicalOperator):
 		/** @var int $inlineThenPointer */
 		$inlineThenPointer = TokenHelper::findNextEffective(
 			$phpcsFile,
-			($isYodaCondition ? $variableEndPointer : $pointerAfterIdenticalOperator) + 1
+			($isYodaCondition ? $variableEndPointer : $pointerAfterIdenticalOperator) + 1,
 		);
 		if ($tokens[$inlineThenPointer]['code'] !== T_INLINE_THEN) {
 			return;
@@ -168,12 +168,12 @@ public function checkIdenticalOperator(File $phpcsFile, int $identicalOperator):
 		/** @var int $compareToStartPointer */
 		$compareToStartPointer = TokenHelper::findNextEffective(
 			$phpcsFile,
-			($tokens[$identicalOperator]['code'] === T_IS_IDENTICAL ? $inlineElsePointer : $inlineThenPointer) + 1
+			($tokens[$identicalOperator]['code'] === T_IS_IDENTICAL ? $inlineElsePointer : $inlineThenPointer) + 1,
 		);
 		/** @var int $compareToEndPointer */
 		$compareToEndPointer = TokenHelper::findPreviousEffective(
 			$phpcsFile,
-			($tokens[$identicalOperator]['code'] === T_IS_IDENTICAL ? $pointerAfterInlineElseEnd : $inlineElsePointer) - 1
+			($tokens[$identicalOperator]['code'] === T_IS_IDENTICAL ? $pointerAfterInlineElseEnd : $inlineElsePointer) - 1,
 		);
 
 		$compareToContent = IdentificatorHelper::getContent($phpcsFile, $compareToStartPointer, $compareToEndPointer);
@@ -185,7 +185,7 @@ public function checkIdenticalOperator(File $phpcsFile, int $identicalOperator):
 		$fix = $phpcsFile->addFixableError(
 			'Use null coalesce operator instead of ternary operator.',
 			$inlineThenPointer,
-			self::CODE_NULL_COALESCE_OPERATOR_NOT_USED
+			self::CODE_NULL_COALESCE_OPERATOR_NOT_USED,
 		);
 
 		if (!$fix) {
@@ -198,7 +198,7 @@ public function checkIdenticalOperator(File $phpcsFile, int $identicalOperator):
 
 		$phpcsFile->fixer->beginChangeset();
 
-		$phpcsFile->fixer->replaceToken($conditionStart, sprintf('%s ??', $variableContent));
+		FixerHelper::replace($phpcsFile, $conditionStart, sprintf('%s ??', $variableContent));
 
 		if ($tokens[$identicalOperator]['code'] === T_IS_IDENTICAL) {
 			FixerHelper::removeBetweenIncluding($phpcsFile, $conditionStart + 1, $inlineThenPointer);
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireNullSafeObjectOperatorSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireNullSafeObjectOperatorSniff.php
index 4dd1f9e94..bebfa7755 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireNullSafeObjectOperatorSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireNullSafeObjectOperatorSniff.php
@@ -41,8 +41,7 @@ class RequireNullSafeObjectOperatorSniff implements Sniff
 
 	private const OPERATOR_REGEXP = '~(::|->|\?->)~';
 
-	/** @var bool|null */
-	public $enable = null;
+	public ?bool $enable = null;
 
 	/**
 	 * @return array
@@ -78,7 +77,7 @@ public function process(File $phpcsFile, $identicalPointer): int
 		[$identificatorStartPointer, $identificatorEndPointer, $conditionStartPointer] = $this->getConditionData(
 			$phpcsFile,
 			$pointerBeforeIdentical,
-			$pointerAfterIdentical
+			$pointerAfterIdentical,
 		);
 
 		if ($identificatorStartPointer === null || $identificatorEndPointer === null) {
@@ -90,7 +89,7 @@ public function process(File $phpcsFile, $identicalPointer): int
 
 		$pointerAfterCondition = TokenHelper::findNextEffective(
 			$phpcsFile,
-			($isYoda ? $identificatorEndPointer : $pointerAfterIdentical) + 1
+			($isYoda ? $identificatorEndPointer : $pointerAfterIdentical) + 1,
 		);
 
 		$allowedBooleanCondition = $tokens[$identicalPointer]['code'] === T_IS_NOT_IDENTICAL ? T_BOOLEAN_AND : T_BOOLEAN_OR;
@@ -129,7 +128,7 @@ private function checkTernaryOperator(
 				$phpcsFile,
 				[T_IS_IDENTICAL, T_IS_NOT_IDENTICAL],
 				$searchStartPointer,
-				$booleanOperatorPointer
+				$booleanOperatorPointer,
 			);
 
 			if ($identicalPointer === null) {
@@ -151,26 +150,26 @@ private function checkTernaryOperator(
 			$previousIdenticalPointer = TokenHelper::findPreviousLocal(
 				$phpcsFile,
 				[T_IS_IDENTICAL, T_IS_NOT_IDENTICAL],
-				$pointerBeforeCondition
+				$pointerBeforeCondition,
 			);
 
 			if ($previousIdenticalPointer !== null) {
 				[$pointerBeforePreviousIdentical, $pointerAfterPreviousIdentical] = $this->getIdenticalData(
 					$phpcsFile,
-					$previousIdenticalPointer
+					$previousIdenticalPointer,
 				);
 
 				[$previousIdentificatorStartPointer, $previousIdentificatorEndPointer] = $this->getConditionData(
 					$phpcsFile,
 					$pointerBeforePreviousIdentical,
-					$pointerAfterPreviousIdentical
+					$pointerAfterPreviousIdentical,
 				);
 
 				if ($previousIdentificatorStartPointer !== null && $previousIdentificatorEndPointer !== null) {
 					$previousIdentificator = IdentificatorHelper::getContent(
 						$phpcsFile,
 						$previousIdentificatorStartPointer,
-						$previousIdentificatorEndPointer
+						$previousIdentificatorEndPointer,
 					);
 
 					if (!self::areIdentificatorsCompatible($previousIdentificator, $identificator)) {
@@ -207,7 +206,7 @@ private function checkTernaryOperator(
 				$phpcsFile,
 				$identificator,
 				$nextIdentificatorStartPointer,
-				$nextIdentificatorEndPointer
+				$nextIdentificatorEndPointer,
 			);
 
 			$firstPointerInElse = TokenHelper::findNextEffective($phpcsFile, $inlineElsePointer + 1);
@@ -249,7 +248,7 @@ private function checkTernaryOperator(
 				$phpcsFile,
 				$identificator,
 				$nextIdentificatorStartPointer,
-				$nextIdentificatorEndPointer
+				$nextIdentificatorEndPointer,
 			);
 
 			$defaultContent = trim(TokenHelper::getContent($phpcsFile, $inlineThenPointer + 1, $inlineElsePointer - 1));
@@ -321,7 +320,7 @@ private function checkNextCondition(
 			$phpcsFile,
 			$identificator,
 			$nextIdentificatorStartPointer,
-			$nextIdentificatorEndPointer
+			$nextIdentificatorEndPointer,
 		);
 
 		$fix = $phpcsFile->addFixableError('Operator ?-> is required.', $identicalPointer, self::CODE_REQUIRED_NULL_SAFE_OBJECT_OPERATOR);
@@ -338,7 +337,7 @@ private function checkNextCondition(
 			$phpcsFile,
 			$conditionStartPointer,
 			$nextIdentificatorEndPointer,
-			sprintf('%s?%s', $identificator, $identificatorDifference)
+			sprintf('%s?%s', $identificator, $identificatorDifference),
 		);
 
 		$phpcsFile->fixer->endChangeset();
@@ -373,7 +372,7 @@ private function findIdentificatorStart(File $phpcsFile, int $identificatorEndPo
 		if ($tokens[$identificatorEndPointer]['code'] === T_CLOSE_PARENTHESIS) {
 			$pointerBeforeParenthesisOpener = TokenHelper::findPreviousEffective(
 				$phpcsFile,
-				$tokens[$identificatorEndPointer]['parenthesis_opener'] - 1
+				$tokens[$identificatorEndPointer]['parenthesis_opener'] - 1,
 			);
 			$identificatorStartPointer = IdentificatorHelper::findStartPointer($phpcsFile, $pointerBeforeParenthesisOpener);
 		} else {
@@ -386,7 +385,7 @@ private function findIdentificatorStart(File $phpcsFile, int $identificatorEndPo
 			if (in_array(
 				$tokens[$pointerBeforeIdentificatorStart]['code'],
 				[T_DOUBLE_COLON, T_OBJECT_OPERATOR, T_NULLSAFE_OBJECT_OPERATOR],
-				true
+				true,
 			)) {
 				$pointerBeforeOperator = TokenHelper::findPreviousEffective($phpcsFile, $pointerBeforeIdentificatorStart - 1);
 				return $this->findIdentificatorStart($phpcsFile, $pointerBeforeOperator);
@@ -415,7 +414,7 @@ private function findIdentificatorEnd(File $phpcsFile, int $identificatorStartPo
 			if (in_array(
 				$tokens[$pointerAfterIdentificatorEnd]['code'],
 				[T_DOUBLE_COLON, T_OBJECT_OPERATOR, T_NULLSAFE_OBJECT_OPERATOR],
-				true
+				true,
 			)) {
 				$pointerAfterOperator = TokenHelper::findNextEffective($phpcsFile, $pointerAfterIdentificatorEnd + 1);
 				return $this->findIdentificatorEnd($phpcsFile, $pointerAfterOperator);
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireShortTernaryOperatorSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireShortTernaryOperatorSniff.php
index 6cfe2f9e8..be9658d48 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireShortTernaryOperatorSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireShortTernaryOperatorSniff.php
@@ -73,7 +73,7 @@ public function process(File $phpcsFile, $inlineThenPointer): void
 		$phpcsFile->fixer->beginChangeset();
 
 		if ($tokens[$conditionStartPointer]['code'] === T_BOOLEAN_NOT) {
-			$phpcsFile->fixer->replaceToken($conditionStartPointer, '');
+			FixerHelper::replace($phpcsFile, $conditionStartPointer, '');
 
 			FixerHelper::change($phpcsFile, $inlineThenPointer, $inlineElseEndPointer, sprintf('?: %s', $thenContent));
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireSingleLineConditionSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireSingleLineConditionSniff.php
index d55864da6..a92708fe2 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireSingleLineConditionSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireSingleLineConditionSniff.php
@@ -15,11 +15,9 @@ class RequireSingleLineConditionSniff extends AbstractLineCondition
 
 	public const CODE_REQUIRED_SINGLE_LINE_CONDITION = 'RequiredSingleLineCondition';
 
-	/** @var int */
-	public $maxLineLength = 120;
+	public int $maxLineLength = 120;
 
-	/** @var bool */
-	public $alwaysForSimpleConditions = true;
+	public bool $alwaysForSimpleConditions = true;
 
 	/**
 	 * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
@@ -44,9 +42,9 @@ public function process(File $phpcsFile, $controlStructurePointer): void
 
 		if (TokenHelper::findNext(
 			$phpcsFile,
-			TokenHelper::$inlineCommentTokenCodes,
+			TokenHelper::INLINE_COMMENT_TOKEN_CODES,
 			$parenthesisOpenerPointer + 1,
-			$parenthesisCloserPointer
+			$parenthesisCloserPointer,
 		) !== null) {
 			return;
 		}
@@ -60,7 +58,7 @@ public function process(File $phpcsFile, $controlStructurePointer): void
 			$phpcsFile,
 			Tokens::$booleanOperators,
 			$parenthesisOpenerPointer + 1,
-			$parenthesisCloserPointer
+			$parenthesisCloserPointer,
 		) === null;
 
 		if (!$this->shouldReportError($lineLength, $isSimpleCondition)) {
@@ -70,10 +68,10 @@ public function process(File $phpcsFile, $controlStructurePointer): void
 		$fix = $phpcsFile->addFixableError(
 			sprintf(
 				'Condition of "%s" should be placed on a single line.',
-				$this->getControlStructureName($phpcsFile, $controlStructurePointer)
+				$this->getControlStructureName($phpcsFile, $controlStructurePointer),
 			),
 			$controlStructurePointer,
-			self::CODE_REQUIRED_SINGLE_LINE_CONDITION
+			self::CODE_REQUIRED_SINGLE_LINE_CONDITION,
 		);
 
 		if (!$fix) {
@@ -82,7 +80,7 @@ public function process(File $phpcsFile, $controlStructurePointer): void
 
 		$phpcsFile->fixer->beginChangeset();
 
-		$phpcsFile->fixer->addContent($parenthesisOpenerPointer, $condition);
+		FixerHelper::add($phpcsFile, $parenthesisOpenerPointer, $condition);
 
 		FixerHelper::removeBetween($phpcsFile, $parenthesisOpenerPointer, $parenthesisCloserPointer);
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireTernaryOperatorSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireTernaryOperatorSniff.php
index f1dc541bb..ac72140ef 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireTernaryOperatorSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireTernaryOperatorSniff.php
@@ -27,8 +27,7 @@ class RequireTernaryOperatorSniff implements Sniff
 
 	public const CODE_TERNARY_OPERATOR_NOT_USED = 'TernaryOperatorNotUsed';
 
-	/** @var bool */
-	public $ignoreMultiLine = false;
+	public bool $ignoreMultiLine = false;
 
 	/**
 	 * @return array
@@ -115,12 +114,12 @@ private function checkIfWithReturns(File $phpcsFile, int $ifPointer, int $elsePo
 		$semicolonAfterReturnInElse = TokenHelper::findNext($phpcsFile, T_SEMICOLON, $pointerAfterReturnInElse + 1);
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->replaceToken($ifPointer, 'return');
+		FixerHelper::replace($phpcsFile, $ifPointer, 'return');
 		if ($ifPointer + 1 === $tokens[$ifPointer]['parenthesis_opener']) {
-			$phpcsFile->fixer->addContent($ifPointer, ' ');
+			FixerHelper::add($phpcsFile, $ifPointer, ' ');
 		}
-		$phpcsFile->fixer->replaceToken($tokens[$ifPointer]['parenthesis_opener'], '');
-		$phpcsFile->fixer->replaceToken($tokens[$ifPointer]['parenthesis_closer'], ' ? ');
+		FixerHelper::replace($phpcsFile, $tokens[$ifPointer]['parenthesis_opener'], '');
+		FixerHelper::replace($phpcsFile, $tokens[$ifPointer]['parenthesis_closer'], ' ? ');
 
 		FixerHelper::removeBetween($phpcsFile, $tokens[$ifPointer]['parenthesis_closer'], $pointerAfterReturnInIf);
 
@@ -231,7 +230,7 @@ private function isCompatibleScope(File $phpcsFile, int $scopeOpenerPointer, int
 				T_WHITESPACE,
 				$phpcsFile->eolChar,
 				$firstContentPointer + 1,
-				$semicolonPointer
+				$semicolonPointer,
 			) !== null) {
 				return false;
 			}
@@ -248,7 +247,7 @@ private function containsComment(File $phpcsFile, int $scopeOwnerPointer): bool
 			$phpcsFile,
 			Tokens::$commentTokens,
 			$tokens[$scopeOwnerPointer]['scope_opener'] + 1,
-			$tokens[$scopeOwnerPointer]['scope_closer']
+			$tokens[$scopeOwnerPointer]['scope_closer'],
 		) !== null;
 	}
 
@@ -259,7 +258,7 @@ private function containsLogicalOperators(File $phpcsFile, int $scopeOwnerPointe
 			$phpcsFile,
 			[T_LOGICAL_AND, T_LOGICAL_OR, T_LOGICAL_XOR],
 			$tokens[$scopeOwnerPointer]['parenthesis_opener'] + 1,
-			$tokens[$scopeOwnerPointer]['parenthesis_closer']
+			$tokens[$scopeOwnerPointer]['parenthesis_closer'],
 		) !== null;
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireYodaComparisonSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireYodaComparisonSniff.php
index cc0a31992..b610df63e 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireYodaComparisonSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/RequireYodaComparisonSniff.php
@@ -23,8 +23,7 @@ class RequireYodaComparisonSniff implements Sniff
 
 	public const CODE_REQUIRED_YODA_COMPARISON = 'RequiredYodaComparison';
 
-	/** @var bool */
-	public $alwaysVariableOnRight = false;
+	public bool $alwaysVariableOnRight = false;
 
 	/**
 	 * @return array
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/UselessIfConditionWithReturnSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/UselessIfConditionWithReturnSniff.php
index 37a10b163..38bc8f250 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/UselessIfConditionWithReturnSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/UselessIfConditionWithReturnSniff.php
@@ -24,8 +24,7 @@ class UselessIfConditionWithReturnSniff implements Sniff
 
 	public const CODE_USELESS_IF_CONDITION = 'UselessIfCondition';
 
-	/** @var bool */
-	public $assumeAllConditionExpressionsAreAlreadyBoolean = false;
+	public bool $assumeAllConditionExpressionsAreAlreadyBoolean = false;
 
 	/**
 	 * @return array
@@ -55,19 +54,17 @@ public function process(File $phpcsFile, $ifPointer): void
 			return;
 		}
 
-		$newCondition = static function () use ($phpcsFile, $tokens, $ifBooleanPointer, $ifPointer): string {
-			return strtolower($tokens[$ifBooleanPointer]['content']) === 'true'
-				? TokenHelper::getContent(
-					$phpcsFile,
-					$tokens[$ifPointer]['parenthesis_opener'] + 1,
-					$tokens[$ifPointer]['parenthesis_closer'] - 1
-				)
-				: ConditionHelper::getNegativeCondition(
-					$phpcsFile,
-					$tokens[$ifPointer]['parenthesis_opener'] + 1,
-					$tokens[$ifPointer]['parenthesis_closer'] - 1
-				);
-		};
+		$newCondition = static fn (): string => strtolower($tokens[$ifBooleanPointer]['content']) === 'true'
+			? TokenHelper::getContent(
+				$phpcsFile,
+				$tokens[$ifPointer]['parenthesis_opener'] + 1,
+				$tokens[$ifPointer]['parenthesis_closer'] - 1,
+			)
+			: ConditionHelper::getNegativeCondition(
+				$phpcsFile,
+				$tokens[$ifPointer]['parenthesis_opener'] + 1,
+				$tokens[$ifPointer]['parenthesis_closer'] - 1,
+			);
 
 		$elsePointer = TokenHelper::findNextEffective($phpcsFile, $tokens[$ifPointer]['scope_closer'] + 1);
 
@@ -157,7 +154,7 @@ private function isFixable(File $phpcsFile, int $ifPointer, int $endPointer): bo
 		return ConditionHelper::conditionReturnsBoolean(
 			$phpcsFile,
 			$tokens[$ifPointer]['parenthesis_opener'] + 1,
-			$tokens[$ifPointer]['parenthesis_closer'] - 1
+			$tokens[$ifPointer]['parenthesis_closer'] - 1,
 		);
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/UselessTernaryOperatorSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/UselessTernaryOperatorSniff.php
index 55f51134a..004faa2ff 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/UselessTernaryOperatorSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/ControlStructures/UselessTernaryOperatorSniff.php
@@ -19,8 +19,7 @@ class UselessTernaryOperatorSniff implements Sniff
 
 	public const CODE_USELESS_TERNARY_OPERATOR = 'UselessTernaryOperator';
 
-	/** @var bool */
-	public $assumeAllConditionExpressionsAreAlreadyBoolean = false;
+	public bool $assumeAllConditionExpressionsAreAlreadyBoolean = false;
 
 	/**
 	 * @return array
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Exceptions/DisallowNonCapturingCatchSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Exceptions/DisallowNonCapturingCatchSniff.php
index fcf40c9de..a519bf112 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Exceptions/DisallowNonCapturingCatchSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Exceptions/DisallowNonCapturingCatchSniff.php
@@ -35,7 +35,7 @@ public function process(File $phpcsFile, $catchPointer): void
 			$phpcsFile,
 			T_VARIABLE,
 			$tokens[$catchPointer]['parenthesis_opener'],
-			$tokens[$catchPointer]['parenthesis_closer']
+			$tokens[$catchPointer]['parenthesis_closer'],
 		);
 
 		if ($variablePointer === null) {
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Exceptions/ReferenceThrowableOnlySniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Exceptions/ReferenceThrowableOnlySniff.php
index 3769e0ae5..987e3e4a6 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Exceptions/ReferenceThrowableOnlySniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Exceptions/ReferenceThrowableOnlySniff.php
@@ -13,7 +13,6 @@
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use Throwable;
 use function array_key_exists;
-use function array_merge;
 use function in_array;
 use function sprintf;
 use const T_BITWISE_OR;
@@ -59,7 +58,7 @@ public function process(File $phpcsFile, $openTagPointer): void
 			$resolvedName = NamespaceHelper::resolveClassName(
 				$phpcsFile,
 				$referencedName->getNameAsReferencedInFile(),
-				$referencedName->getStartPointer()
+				$referencedName->getStartPointer(),
 			);
 			if ($resolvedName !== '\\Exception') {
 				continue;
@@ -72,8 +71,8 @@ public function process(File $phpcsFile, $openTagPointer): void
 			if ($tokens[$previousPointer]['code'] === T_BITWISE_OR) {
 				$previousPointer = TokenHelper::findPreviousExcluding(
 					$phpcsFile,
-					array_merge(TokenHelper::$ineffectiveTokenCodes, TokenHelper::getNameTokenCodes(), [T_BITWISE_OR]),
-					$previousPointer - 1
+					[...TokenHelper::INEFFECTIVE_TOKEN_CODES, ...TokenHelper::NAME_TOKEN_CODES, T_BITWISE_OR],
+					$previousPointer - 1,
 				);
 			}
 			if ($tokens[$previousPointer]['code'] === T_OPEN_PARENTHESIS) {
@@ -90,7 +89,7 @@ public function process(File $phpcsFile, $openTagPointer): void
 					&& SuppressHelper::isSniffSuppressed(
 						$phpcsFile,
 						$openParenthesisOpenerPointer,
-						sprintf('%s.%s', self::NAME, self::CODE_REFERENCED_GENERAL_EXCEPTION)
+						sprintf('%s.%s', self::NAME, self::CODE_REFERENCED_GENERAL_EXCEPTION),
 					)
 				) {
 					continue;
@@ -100,7 +99,7 @@ public function process(File $phpcsFile, $openTagPointer): void
 			$fix = $phpcsFile->addFixableError(
 				$message,
 				$referencedName->getStartPointer(),
-				self::CODE_REFERENCED_GENERAL_EXCEPTION
+				self::CODE_REFERENCED_GENERAL_EXCEPTION,
 			);
 			if (!$fix) {
 				continue;
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Exceptions/RequireNonCapturingCatchSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Exceptions/RequireNonCapturingCatchSniff.php
index e042ccc8c..15bc1a247 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Exceptions/RequireNonCapturingCatchSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Exceptions/RequireNonCapturingCatchSniff.php
@@ -11,12 +11,12 @@
 use SlevomatCodingStandard\Helpers\SniffSettingsHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use SlevomatCodingStandard\Helpers\VariableHelper;
-use function array_keys;
 use function array_reverse;
 use function count;
 use function in_array;
 use const T_CATCH;
 use const T_DOUBLE_QUOTED_STRING;
+use const T_FINALLY;
 use const T_HEREDOC;
 use const T_VARIABLE;
 use const T_WHITESPACE;
@@ -26,8 +26,7 @@ class RequireNonCapturingCatchSniff implements Sniff
 
 	public const CODE_NON_CAPTURING_CATCH_REQUIRED = 'NonCapturingCatchRequired';
 
-	/** @var bool|null */
-	public $enable = null;
+	public ?bool $enable = null;
 
 	/**
 	 * @return array
@@ -57,7 +56,7 @@ public function process(File $phpcsFile, $catchPointer): void
 			$phpcsFile,
 			T_VARIABLE,
 			$tokens[$catchPointer]['parenthesis_opener'],
-			$tokens[$catchPointer]['parenthesis_closer']
+			$tokens[$catchPointer]['parenthesis_closer'],
 		);
 		if ($variablePointer === null) {
 			return;
@@ -69,18 +68,33 @@ public function process(File $phpcsFile, $catchPointer): void
 			$phpcsFile,
 			$tokens[$catchPointer]['scope_opener'],
 			$tokens[$catchPointer]['scope_closer'],
-			$variableName
+			$variableName,
 		)) {
 			return;
 		}
 
 		$tryEndPointer = CatchHelper::getTryEndPointer($phpcsFile, $catchPointer);
 
-		if ($tokens[$tryEndPointer]['conditions'] !== []) {
-			$lastConditionPointer = array_reverse(array_keys($tokens[$tryEndPointer]['conditions']))[0];
-			$nextScopeEnd = $tokens[$lastConditionPointer]['scope_closer'];
-		} else {
-			$nextScopeEnd = count($tokens) - 1;
+		$possibleFinallyPointer = $tokens[$tryEndPointer]['scope_condition'];
+		if (
+			$tokens[$possibleFinallyPointer]['code'] === T_FINALLY
+			&& $this->isVariableUsedInCodePart(
+				$phpcsFile,
+				$tokens[$possibleFinallyPointer]['scope_opener'],
+				$tokens[$possibleFinallyPointer]['scope_closer'],
+				$variableName,
+			)
+		) {
+			return;
+		}
+
+		$nextScopeEnd = count($tokens) - 1;
+
+		foreach (array_reverse($tokens[$tryEndPointer]['conditions'], true) as $conditionPointer => $conditionCode) {
+			if (in_array($conditionCode, TokenHelper::FUNCTION_TOKEN_CODES, true)) {
+				$nextScopeEnd = $tokens[$conditionPointer]['scope_closer'];
+				break;
+			}
 		}
 
 		if ($this->isVariableUsedInCodePart($phpcsFile, $tryEndPointer, $nextScopeEnd, $variableName)) {
@@ -99,7 +113,7 @@ public function process(File $phpcsFile, $catchPointer): void
 			T_WHITESPACE,
 			$phpcsFile->eolChar,
 			$variablePointer + 1,
-			$tokens[$catchPointer]['parenthesis_closer']
+			$tokens[$catchPointer]['parenthesis_closer'],
 		);
 		if ($fixEndPointer === null) {
 			$fixEndPointer = $tokens[$catchPointer]['parenthesis_closer'];
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Files/FileLengthSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Files/FileLengthSniff.php
index a3e0108ec..111adb325 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Files/FileLengthSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Files/FileLengthSniff.php
@@ -17,14 +17,11 @@ class FileLengthSniff implements Sniff
 
 	public const CODE_FILE_TOO_LONG = 'FileTooLong';
 
-	/** @var int */
-	public $maxLinesLength = 250;
+	public int $maxLinesLength = 250;
 
-	/** @var bool */
-	public $includeComments = false;
+	public bool $includeComments = false;
 
-	/** @var bool */
-	public $includeWhitespace = false;
+	public bool $includeWhitespace = false;
 
 	/**
 	 * @return array
@@ -45,9 +42,7 @@ public function process(File $phpcsFile, $pointer): void
 			FunctionHelper::LINE_INCLUDE_COMMENT => $this->includeComments,
 			FunctionHelper::LINE_INCLUDE_WHITESPACE => $this->includeWhitespace,
 		]));
-		$flags = array_reduce($flags, static function ($carry, $flag): int {
-			return $carry | $flag;
-		}, 0);
+		$flags = array_reduce($flags, static fn ($carry, $flag): int => $carry | $flag, 0);
 
 		$length = FunctionHelper::getLineCount($phpcsFile, $pointer, $flags);
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Files/FilepathNamespaceExtractor.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Files/FilepathNamespaceExtractor.php
index 768bb9a1a..dade3f10a 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Files/FilepathNamespaceExtractor.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Files/FilepathNamespaceExtractor.php
@@ -23,13 +23,13 @@ class FilepathNamespaceExtractor
 {
 
 	/** @var array */
-	private $rootNamespaces;
+	private array $rootNamespaces;
 
 	/** @var array dir(string) => true(bool) */
-	private $skipDirs;
+	private array $skipDirs;
 
 	/** @var list */
-	private $extensions;
+	private array $extensions;
 
 	/**
 	 * @param array $rootNamespaces directory(string) => namespace
@@ -40,9 +40,7 @@ public function __construct(array $rootNamespaces, array $skipDirs, array $exten
 	{
 		$this->rootNamespaces = $rootNamespaces;
 		$this->skipDirs = array_fill_keys($skipDirs, true);
-		$this->extensions = array_map(static function (string $extension): string {
-			return strtolower($extension);
-		}, $extensions);
+		$this->extensions = array_map(static fn (string $extension): string => strtolower($extension), $extensions);
 	}
 
 	public function getTypeNameFromProjectPath(string $path): ?string
@@ -78,9 +76,7 @@ public function getTypeNameFromProjectPath(string $path): ?string
 
 		array_unshift($pathParts, $rootNamespace);
 
-		$typeName = implode('\\', array_filter($pathParts, function (string $pathPart): bool {
-			return !isset($this->skipDirs[$pathPart]);
-		}));
+		$typeName = implode('\\', array_filter($pathParts, fn (string $pathPart): bool => !isset($this->skipDirs[$pathPart])));
 
 		return substr($typeName, 0, -strlen('.' . $extension));
 	}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Files/FunctionLengthSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Files/FunctionLengthSniff.php
deleted file mode 100644
index 04735d04b..000000000
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Files/FunctionLengthSniff.php
+++ /dev/null
@@ -1,12 +0,0 @@
-
@@ -122,9 +116,11 @@ private function checkLineLength(File $phpcsFile, int $pointer): void
 
 		if ($this->ignoreImports) {
 			$usePointer = UseStatementHelper::getUseStatementPointer($phpcsFile, $pointer - 1);
-			if (is_int($usePointer)
+			if (
+				is_int($usePointer)
 				&& $tokens[$usePointer]['line'] === $tokens[$pointer]['line']
-				&& !UseStatementHelper::isTraitUse($phpcsFile, $usePointer)) {
+				&& UseStatementHelper::isImportUse($phpcsFile, $usePointer)
+			) {
 				return;
 			}
 		}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Files/TypeNameMatchesFileNameSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Files/TypeNameMatchesFileNameSniff.php
index 25b369f1c..a4bf6ac95 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Files/TypeNameMatchesFileNameSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Files/TypeNameMatchesFileNameSniff.php
@@ -28,38 +28,37 @@ class TypeNameMatchesFileNameSniff implements Sniff
 	public const CODE_NO_MATCH_BETWEEN_TYPE_NAME_AND_FILE_NAME = 'NoMatchBetweenTypeNameAndFileName';
 
 	/** @var array */
-	public $rootNamespaces = [];
+	public array $rootNamespaces = [];
 
 	/** @var list */
-	public $skipDirs = [];
+	public array $skipDirs = [];
 
 	/** @var list */
-	public $ignoredNamespaces = [];
+	public array $ignoredNamespaces = [];
 
 	/** @var list */
-	public $extensions = ['php'];
+	public array $extensions = ['php'];
 
 	/** @var array|null */
-	private $normalizedRootNamespaces;
+	private ?array $normalizedRootNamespaces = null;
 
 	/** @var list|null */
-	private $normalizedSkipDirs;
+	private ?array $normalizedSkipDirs = null;
 
 	/** @var list|null */
-	private $normalizedIgnoredNamespaces;
+	private ?array $normalizedIgnoredNamespaces = null;
 
 	/** @var list|null */
-	private $normalizedExtensions;
+	private ?array $normalizedExtensions = null;
 
-	/** @var FilepathNamespaceExtractor */
-	private $namespaceExtractor;
+	private ?FilepathNamespaceExtractor $namespaceExtractor = null;
 
 	/**
 	 * @return array
 	 */
 	public function register(): array
 	{
-		return TokenHelper::$typeKeywordTokenCodes;
+		return TokenHelper::CLASS_TYPE_TOKEN_CODES;
 	}
 
 	/**
@@ -99,10 +98,10 @@ public function process(File $phpcsFile, $typePointer): void
 				'%s name %s does not match filepath %s.',
 				ucfirst($tokens[$typePointer]['content']),
 				$typeName,
-				$phpcsFile->getFilename()
+				$phpcsFile->getFilename(),
 			),
 			$namePointer,
-			self::CODE_NO_MATCH_BETWEEN_TYPE_NAME_AND_FILE_NAME
+			self::CODE_NO_MATCH_BETWEEN_TYPE_NAME_AND_FILE_NAME,
 		);
 	}
 
@@ -178,7 +177,7 @@ private function getNamespaceExtractor(): FilepathNamespaceExtractor
 			$this->namespaceExtractor = new FilepathNamespaceExtractor(
 				$this->getRootNamespaces(),
 				$this->getSkipDirs(),
-				$this->getExtensions()
+				$this->getExtensions(),
 			);
 		}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/AbstractLineCall.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/AbstractLineCall.php
index 72c869974..4d81e92a0 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/AbstractLineCall.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/AbstractLineCall.php
@@ -4,9 +4,7 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
-use SlevomatCodingStandard\Helpers\IndentationHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
-use function array_merge;
 use function rtrim;
 use function trim;
 use const T_CLOSE_PARENTHESIS;
@@ -26,7 +24,7 @@ abstract class AbstractLineCall implements Sniff
 	 */
 	public function register(): array
 	{
-		return array_merge(TokenHelper::getOnlyNameTokenCodes(), [T_SELF, T_STATIC, T_PARENT]);
+		return [...TokenHelper::ONLY_NAME_TOKEN_CODES, T_SELF, T_STATIC, T_PARENT];
 	}
 
 	protected function isCall(File $phpcsFile, int $stringPointer): bool
@@ -48,7 +46,7 @@ protected function getLineStart(File $phpcsFile, int $pointer): string
 	{
 		$firstPointerOnLine = TokenHelper::findFirstTokenOnLine($phpcsFile, $pointer);
 
-		return IndentationHelper::convertTabsToSpaces($phpcsFile, TokenHelper::getContent($phpcsFile, $firstPointerOnLine, $pointer));
+		return TokenHelper::getContent($phpcsFile, $firstPointerOnLine, $pointer);
 	}
 
 	protected function getCall(File $phpcsFile, int $parenthesisOpenerPointer, int $parenthesisCloserPointer): string
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/ArrowFunctionDeclarationSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/ArrowFunctionDeclarationSniff.php
index e593423ee..c9fd1ea18 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/ArrowFunctionDeclarationSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/ArrowFunctionDeclarationSniff.php
@@ -22,17 +22,13 @@ class ArrowFunctionDeclarationSniff implements Sniff
 	public const CODE_INCORRECT_SPACES_BEFORE_ARROW = 'IncorrectSpacesBeforeArrow';
 	public const CODE_INCORRECT_SPACES_AFTER_ARROW = 'IncorrectSpacesAfterArrow';
 
-	/** @var int */
-	public $spacesCountAfterKeyword = 1;
+	public int $spacesCountAfterKeyword = 1;
 
-	/** @var int */
-	public $spacesCountBeforeArrow = 1;
+	public int $spacesCountBeforeArrow = 1;
 
-	/** @var int */
-	public $spacesCountAfterArrow = 1;
+	public int $spacesCountAfterArrow = 1;
 
-	/** @var bool */
-	public $allowMultiLine = false;
+	public bool $allowMultiLine = false;
 
 	/**
 	 * @return array
@@ -87,7 +83,7 @@ private function checkSpacesAfterKeyword(File $phpcsFile, int $arrowFunctionPoin
 		$fix = $phpcsFile->addFixableError(
 			$this->formatErrorMessage('after "fn" keyword', $this->spacesCountAfterKeyword),
 			$arrowFunctionPointer,
-			self::CODE_INCORRECT_SPACES_AFTER_KEYWORD
+			self::CODE_INCORRECT_SPACES_AFTER_KEYWORD,
 		);
 		if (!$fix) {
 			return;
@@ -121,7 +117,7 @@ private function checkSpacesBeforeArrow(File $phpcsFile, int $arrowPointer): voi
 		$fix = $phpcsFile->addFixableError(
 			$this->formatErrorMessage('before =>', $this->spacesCountBeforeArrow),
 			$arrowPointer,
-			self::CODE_INCORRECT_SPACES_BEFORE_ARROW
+			self::CODE_INCORRECT_SPACES_BEFORE_ARROW,
 		);
 		if (!$fix) {
 			return;
@@ -149,7 +145,7 @@ private function checkSpacesAfterArrow(File $phpcsFile, int $arrowPointer): void
 		$fix = $phpcsFile->addFixableError(
 			$this->formatErrorMessage('after =>', $this->spacesCountAfterArrow),
 			$arrowPointer,
-			self::CODE_INCORRECT_SPACES_AFTER_ARROW
+			self::CODE_INCORRECT_SPACES_AFTER_ARROW,
 		);
 		if (!$fix) {
 			return;
@@ -170,7 +166,7 @@ private function fixSpaces(File $phpcsFile, int $pointerBefore, int $pointerAfte
 		$phpcsFile->fixer->beginChangeset();
 
 		if ($requiredSpaces > 0) {
-			$phpcsFile->fixer->addContent($pointerBefore, str_repeat(' ', $requiredSpaces));
+			FixerHelper::add($phpcsFile, $pointerBefore, str_repeat(' ', $requiredSpaces));
 		}
 
 		FixerHelper::removeBetween($phpcsFile, $pointerBefore, $pointerAfter);
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/DisallowEmptyFunctionSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/DisallowEmptyFunctionSniff.php
index 704d30f44..a2333401a 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/DisallowEmptyFunctionSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/DisallowEmptyFunctionSniff.php
@@ -40,7 +40,7 @@ public function process(File $phpcsFile, $functionPointer): void
 				$phpcsFile,
 				Tokens::$scopeModifiers,
 				$tokens[$functionPointer]['parenthesis_opener'] + 1,
-				$tokens[$functionPointer]['parenthesis_closer']
+				$tokens[$functionPointer]['parenthesis_closer'],
 			);
 
 			if ($propertyPromotion !== null) {
@@ -52,7 +52,7 @@ public function process(File $phpcsFile, $functionPointer): void
 			$phpcsFile,
 			T_WHITESPACE,
 			$tokens[$functionPointer]['scope_opener'] + 1,
-			$tokens[$functionPointer]['scope_closer']
+			$tokens[$functionPointer]['scope_closer'],
 		);
 
 		if ($firstContent !== null) {
@@ -62,7 +62,7 @@ public function process(File $phpcsFile, $functionPointer): void
 		$phpcsFile->addError(
 			'Empty function body must have at least a comment to explain why is empty.',
 			$functionPointer,
-			self::CODE_EMPTY_FUNCTION
+			self::CODE_EMPTY_FUNCTION,
 		);
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/DisallowNamedArgumentsSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/DisallowNamedArgumentsSniff.php
index 500f0f40b..4d9c4a531 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/DisallowNamedArgumentsSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/DisallowNamedArgumentsSniff.php
@@ -33,7 +33,7 @@ public function process(File $phpcsFile, $argumentNamePointer): void
 		$phpcsFile->addError(
 			sprintf('Named arguments are disallowed, usage of named argument "%s" found.', $tokens[$argumentNamePointer]['content']),
 			$argumentNamePointer,
-			self::CODE_DISALLOWED_NAMED_ARGUMENT
+			self::CODE_DISALLOWED_NAMED_ARGUMENT,
 		);
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/DisallowTrailingCommaInCallSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/DisallowTrailingCommaInCallSniff.php
index 2914a8415..eaf3e5f7d 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/DisallowTrailingCommaInCallSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/DisallowTrailingCommaInCallSniff.php
@@ -6,8 +6,6 @@
 use PHP_CodeSniffer\Sniffs\Sniff;
 use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
-use function array_key_exists;
-use function array_merge;
 use function in_array;
 use const T_CLOSE_PARENTHESIS;
 use const T_COMMA;
@@ -16,6 +14,7 @@
 use const T_PARENT;
 use const T_SELF;
 use const T_STATIC;
+use const T_STRING;
 use const T_UNSET;
 use const T_VARIABLE;
 
@@ -24,8 +23,7 @@ class DisallowTrailingCommaInCallSniff implements Sniff
 
 	public const CODE_DISALLOWED_TRAILING_COMMA = 'DisallowedTrailingComma';
 
-	/** @var bool */
-	public $onlySingleLine = false;
+	public bool $onlySingleLine = false;
 
 	/**
 	 * @return array
@@ -45,22 +43,20 @@ public function process(File $phpcsFile, $parenthesisOpenerPointer): void
 	{
 		$tokens = $phpcsFile->getTokens();
 
-		if (array_key_exists('parenthesis_owner', $tokens[$parenthesisOpenerPointer])) {
-			return;
-		}
-
 		$pointerBeforeParenthesisOpener = TokenHelper::findPreviousEffective($phpcsFile, $parenthesisOpenerPointer - 1);
 		if (!in_array(
 			$tokens[$pointerBeforeParenthesisOpener]['code'],
-			array_merge(
-				TokenHelper::getOnlyNameTokenCodes(),
-				[T_VARIABLE, T_ISSET, T_UNSET, T_CLOSE_PARENTHESIS, T_SELF, T_STATIC, T_PARENT]
-			),
-			true
+			[...TokenHelper::ONLY_NAME_TOKEN_CODES, T_STRING, T_VARIABLE, T_ISSET, T_UNSET, T_CLOSE_PARENTHESIS, T_SELF, T_STATIC, T_PARENT],
+			true,
 		)) {
 			return;
 		}
 
+		$functionPointer = TokenHelper::findPreviousEffective($phpcsFile, $pointerBeforeParenthesisOpener - 1);
+		if (in_array($tokens[$functionPointer]['code'], TokenHelper::FUNCTION_TOKEN_CODES, true)) {
+			return;
+		}
+
 		$parenthesisCloserPointer = $tokens[$parenthesisOpenerPointer]['parenthesis_closer'];
 		$pointerBeforeParenthesisCloser = TokenHelper::findPreviousEffective($phpcsFile, $parenthesisCloserPointer - 1);
 
@@ -75,7 +71,7 @@ public function process(File $phpcsFile, $parenthesisOpenerPointer): void
 		$fix = $phpcsFile->addFixableError(
 			'Trailing comma after the last parameter in function call is disallowed.',
 			$pointerBeforeParenthesisCloser,
-			self::CODE_DISALLOWED_TRAILING_COMMA
+			self::CODE_DISALLOWED_TRAILING_COMMA,
 		);
 
 		if (!$fix) {
@@ -83,7 +79,7 @@ public function process(File $phpcsFile, $parenthesisOpenerPointer): void
 		}
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->replaceToken($pointerBeforeParenthesisCloser, '');
+		FixerHelper::replace($phpcsFile, $pointerBeforeParenthesisCloser, '');
 
 		if ($tokens[$pointerBeforeParenthesisCloser]['line'] === $tokens[$parenthesisCloserPointer]['line']) {
 			FixerHelper::removeBetween($phpcsFile, $pointerBeforeParenthesisCloser, $parenthesisCloserPointer);
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/DisallowTrailingCommaInClosureUseSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/DisallowTrailingCommaInClosureUseSniff.php
index ad8e2bc2a..8f7f06f42 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/DisallowTrailingCommaInClosureUseSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/DisallowTrailingCommaInClosureUseSniff.php
@@ -16,8 +16,7 @@ class DisallowTrailingCommaInClosureUseSniff implements Sniff
 
 	public const CODE_DISALLOWED_TRAILING_COMMA = 'DisallowedTrailingComma';
 
-	/** @var bool */
-	public $onlySingleLine = false;
+	public bool $onlySingleLine = false;
 
 	/**
 	 * @return array
@@ -52,7 +51,7 @@ public function process(File $phpcsFile, $functionPointer): void
 			$phpcsFile,
 			T_WHITESPACE,
 			$tokens[$useParenthesisOpenerPointer]['parenthesis_closer'] - 1,
-			$useParenthesisOpenerPointer
+			$useParenthesisOpenerPointer,
 		);
 
 		if ($tokens[$pointerBeforeUseParenthesisCloser]['code'] !== T_COMMA) {
@@ -66,7 +65,7 @@ public function process(File $phpcsFile, $functionPointer): void
 		$fix = $phpcsFile->addFixableError(
 			'Trailing comma after the last inherited variable in "use" of closure declaration is disallowed.',
 			$pointerBeforeUseParenthesisCloser,
-			self::CODE_DISALLOWED_TRAILING_COMMA
+			self::CODE_DISALLOWED_TRAILING_COMMA,
 		);
 
 		if (!$fix) {
@@ -74,7 +73,7 @@ public function process(File $phpcsFile, $functionPointer): void
 		}
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->replaceToken($pointerBeforeUseParenthesisCloser, '');
+		FixerHelper::replace($phpcsFile, $pointerBeforeUseParenthesisCloser, '');
 
 		if ($tokens[$pointerBeforeUseParenthesisCloser]['line'] === $tokens[$useParenthesisCloserPointer]['line']) {
 			FixerHelper::removeBetween($phpcsFile, $pointerBeforeUseParenthesisCloser, $useParenthesisCloserPointer);
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/DisallowTrailingCommaInDeclarationSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/DisallowTrailingCommaInDeclarationSniff.php
index 4e3c747bb..615b6e9de 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/DisallowTrailingCommaInDeclarationSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/DisallowTrailingCommaInDeclarationSniff.php
@@ -14,15 +14,14 @@ class DisallowTrailingCommaInDeclarationSniff implements Sniff
 
 	public const CODE_DISALLOWED_TRAILING_COMMA = 'DisallowedTrailingComma';
 
-	/** @var bool */
-	public $onlySingleLine = false;
+	public bool $onlySingleLine = false;
 
 	/**
 	 * @return array
 	 */
 	public function register(): array
 	{
-		return TokenHelper::$functionTokenCodes;
+		return TokenHelper::FUNCTION_TOKEN_CODES;
 	}
 
 	/**
@@ -40,7 +39,7 @@ public function process(File $phpcsFile, $functionPointer): void
 			$phpcsFile,
 			T_WHITESPACE,
 			$parenthesisCloserPointer - 1,
-			$parenthesisOpenerPointer
+			$parenthesisOpenerPointer,
 		);
 
 		if ($tokens[$pointerBeforeParenthesisCloser]['code'] !== T_COMMA) {
@@ -54,7 +53,7 @@ public function process(File $phpcsFile, $functionPointer): void
 		$fix = $phpcsFile->addFixableError(
 			'Trailing comma after the last parameter in function declaration is disallowed.',
 			$pointerBeforeParenthesisCloser,
-			self::CODE_DISALLOWED_TRAILING_COMMA
+			self::CODE_DISALLOWED_TRAILING_COMMA,
 		);
 
 		if (!$fix) {
@@ -62,7 +61,7 @@ public function process(File $phpcsFile, $functionPointer): void
 		}
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->replaceToken($pointerBeforeParenthesisCloser, '');
+		FixerHelper::replace($phpcsFile, $pointerBeforeParenthesisCloser, '');
 
 		if ($tokens[$pointerBeforeParenthesisCloser]['line'] === $tokens[$parenthesisCloserPointer]['line']) {
 			FixerHelper::removeBetween($phpcsFile, $pointerBeforeParenthesisCloser, $parenthesisCloserPointer);
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/FunctionLengthSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/FunctionLengthSniff.php
index 0c15e81b5..e74675333 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/FunctionLengthSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/FunctionLengthSniff.php
@@ -17,14 +17,11 @@ class FunctionLengthSniff implements Sniff
 
 	public const CODE_FUNCTION_LENGTH = 'FunctionLength';
 
-	/** @var int */
-	public $maxLinesLength = 20;
+	public int $maxLinesLength = 20;
 
-	/** @var bool */
-	public $includeComments = false;
+	public bool $includeComments = false;
 
-	/** @var bool */
-	public $includeWhitespace = false;
+	public bool $includeWhitespace = false;
 
 	/**
 	 * @return array
@@ -46,9 +43,7 @@ public function process(File $file, $functionPointer): void
 			FunctionHelper::LINE_INCLUDE_COMMENT => $this->includeComments,
 			FunctionHelper::LINE_INCLUDE_WHITESPACE => $this->includeWhitespace,
 		]));
-		$flags = array_reduce($flags, static function ($carry, $flag): int {
-			return $carry | $flag;
-		}, 0);
+		$flags = array_reduce($flags, static fn ($carry, $flag): int => $carry | $flag, 0);
 
 		$length = FunctionHelper::getFunctionLengthInLines($file, $functionPointer, $flags);
 
@@ -59,7 +54,7 @@ public function process(File $file, $functionPointer): void
 		$errorMessage = sprintf(
 			'Your function is too long. Currently using %d lines. Can be up to %d lines.',
 			$length,
-			$this->maxLinesLength
+			$this->maxLinesLength,
 		);
 
 		$file->addError($errorMessage, $functionPointer, self::CODE_FUNCTION_LENGTH);
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/NamedArgumentSpacingSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/NamedArgumentSpacingSniff.php
index b44272216..e72a2af2a 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/NamedArgumentSpacingSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/NamedArgumentSpacingSniff.php
@@ -4,6 +4,7 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use function sprintf;
 use const T_COLON;
@@ -43,10 +44,10 @@ public function process(File $phpcsFile, $pointer): void
 			$fix = $phpcsFile->addFixableError(
 				sprintf('There must be no whitespace between named argument "%s" and colon.', $parameterName),
 				$colonPointer,
-				self::CODE_WHITESPACE_BEFORE_COLON
+				self::CODE_WHITESPACE_BEFORE_COLON,
 			);
 			if ($fix) {
-				$phpcsFile->fixer->replaceToken($colonPointer - 1, '');
+				FixerHelper::replace($phpcsFile, $colonPointer - 1, '');
 			}
 		}
 
@@ -62,7 +63,7 @@ public function process(File $phpcsFile, $pointer): void
 		$fix = $phpcsFile->addFixableError(
 			sprintf('There must be exactly one space after colon in named argument "%s".', $parameterName),
 			$colonPointer,
-			self::CODE_NO_WHITESPACE_AFTER_COLON
+			self::CODE_NO_WHITESPACE_AFTER_COLON,
 		);
 
 		if (!$fix) {
@@ -70,9 +71,9 @@ public function process(File $phpcsFile, $pointer): void
 		}
 
 		if ($tokens[$whitespacePointer]['code'] === T_WHITESPACE) {
-			$phpcsFile->fixer->replaceToken($whitespacePointer, ' ');
+			FixerHelper::replace($phpcsFile, $whitespacePointer, ' ');
 		} else {
-			$phpcsFile->fixer->addContent($colonPointer, ' ');
+			FixerHelper::add($phpcsFile, $colonPointer, ' ');
 		}
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/RequireArrowFunctionSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/RequireArrowFunctionSniff.php
index 06e07873e..5fa4dc4a5 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/RequireArrowFunctionSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/RequireArrowFunctionSniff.php
@@ -23,11 +23,9 @@ class RequireArrowFunctionSniff implements Sniff
 
 	public const CODE_REQUIRED_ARROW_FUNCTION = 'RequiredArrowFunction';
 
-	/** @var bool */
-	public $allowNested = true;
+	public bool $allowNested = true;
 
-	/** @var bool|null */
-	public $enable = null;
+	public ?bool $enable = null;
 
 	/**
 	 * @return array
@@ -65,7 +63,7 @@ public function process(File $phpcsFile, $closurePointer): void
 				$phpcsFile,
 				T_BITWISE_AND,
 				$useOpenParenthesisPointer + 1,
-				$tokens[$useOpenParenthesisPointer]['parenthesis_closer']
+				$tokens[$useOpenParenthesisPointer]['parenthesis_closer'],
 			) !== null) {
 				return;
 			}
@@ -76,7 +74,7 @@ public function process(File $phpcsFile, $closurePointer): void
 				$phpcsFile,
 				[T_CLOSURE, T_FN],
 				$tokens[$closurePointer]['scope_opener'] + 1,
-				$tokens[$closurePointer]['scope_closer']
+				$tokens[$closurePointer]['scope_closer'],
 			);
 			if ($closureOrArrowFunctionPointer !== null) {
 				return;
@@ -94,12 +92,12 @@ public function process(File $phpcsFile, $closurePointer): void
 			$phpcsFile,
 			T_USE,
 			$tokens[$closurePointer]['parenthesis_closer'] + 1,
-			$tokens[$closurePointer]['scope_opener']
+			$tokens[$closurePointer]['scope_opener'],
 		);
 		$nonWhitespacePointerBeforeScopeOpener = TokenHelper::findPreviousExcluding(
 			$phpcsFile,
 			T_WHITESPACE,
-			$tokens[$closurePointer]['scope_opener'] - 1
+			$tokens[$closurePointer]['scope_opener'] - 1,
 		);
 
 		$nonWhitespacePointerAfterUseParenthesisCloser = null;
@@ -108,24 +106,24 @@ public function process(File $phpcsFile, $closurePointer): void
 			$nonWhitespacePointerAfterUseParenthesisCloser = TokenHelper::findNextExcluding(
 				$phpcsFile,
 				T_WHITESPACE,
-				$useParenthesiCloserPointer + 1
+				$useParenthesiCloserPointer + 1,
 			);
 		}
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->replaceToken($closurePointer, 'fn');
+		FixerHelper::replace($phpcsFile, $closurePointer, 'fn');
 
 		if ($nonWhitespacePointerAfterUseParenthesisCloser !== null) {
 			FixerHelper::removeBetween(
 				$phpcsFile,
 				$tokens[$closurePointer]['parenthesis_closer'],
-				$nonWhitespacePointerAfterUseParenthesisCloser
+				$nonWhitespacePointerAfterUseParenthesisCloser,
 			);
 		}
 
 		FixerHelper::removeBetween($phpcsFile, $nonWhitespacePointerBeforeScopeOpener, $pointerAfterReturn);
 
-		$phpcsFile->fixer->addContent($nonWhitespacePointerBeforeScopeOpener, ' => ');
+		FixerHelper::add($phpcsFile, $nonWhitespacePointerBeforeScopeOpener, ' => ');
 
 		FixerHelper::removeBetweenIncluding($phpcsFile, $semicolonAfterReturn, $tokens[$closurePointer]['scope_closer']);
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/RequireMultiLineCallSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/RequireMultiLineCallSniff.php
index 693eb175e..c33c85fee 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/RequireMultiLineCallSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/RequireMultiLineCallSniff.php
@@ -28,8 +28,7 @@ class RequireMultiLineCallSniff extends AbstractLineCall
 
 	public const CODE_REQUIRED_MULTI_LINE_CALL = 'RequiredMultiLineCall';
 
-	/** @var int */
-	public $minLineLength = 121;
+	public int $minLineLength = 121;
 
 	/**
 	 * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
@@ -61,7 +60,7 @@ public function process(File $phpcsFile, $stringPointer): void
 			$phpcsFile,
 			[T_COMMA, T_OPEN_PARENTHESIS, T_CLOSE_PARENTHESIS, T_OPEN_SHORT_ARRAY, T_CLOSE_SHORT_ARRAY],
 			$parenthesisOpenerPointer + 1,
-			$parenthesisCloserPointer
+			$parenthesisCloserPointer,
 		);
 		foreach ($pointers as $pointer) {
 			if (in_array($tokens[$pointer]['code'], [T_OPEN_PARENTHESIS, T_OPEN_SHORT_ARRAY], true)) {
@@ -108,20 +107,20 @@ public function process(File $phpcsFile, $stringPointer): void
 			$lineEnd = $this->getLineEnd($phpcsFile, $parenthesisCloserPointer);
 			$lineLength = strlen($lineStart . $call . $lineEnd);
 		} else {
-			$lineEnd = $this->getLineEnd($phpcsFile, $parenthesisOpenerPointer);
+			$lineEnd = $this->getLineEnd($phpcsFile, $parenthesisOpenerPointer + 1);
 			$lineLength = strlen($lineStart . $lineEnd);
 		}
 
 		$firstNonWhitespaceOnLine = TokenHelper::findFirstNonWhitespaceOnLine($phpcsFile, $stringPointer);
 		$indentation = IndentationHelper::getIndentation($phpcsFile, $firstNonWhitespaceOnLine);
-		$oneIndentation = IndentationHelper::getOneIndentationLevel($indentation);
+		$oneIndentation = IndentationHelper::getOneIndentationLevel($phpcsFile);
 
 		if (!$this->shouldReportError(
 			$lineLength,
 			$lineStart,
 			$lineEnd,
 			count($parametersPointers),
-			strlen(IndentationHelper::convertTabsToSpaces($phpcsFile, $oneIndentation))
+			strlen($oneIndentation),
 		)) {
 			return;
 		}
@@ -144,23 +143,23 @@ public function process(File $phpcsFile, $stringPointer): void
 			return;
 		}
 
-		$parametersIndentation = IndentationHelper::addIndentation($indentation);
+		$parametersIndentation = IndentationHelper::addIndentation($phpcsFile, $indentation);
 
 		$phpcsFile->fixer->beginChangeset();
 
 		for ($i = $parenthesisOpenerPointer + 1; $i < $parenthesisCloserPointer; $i++) {
 			if (in_array($i, $parametersPointers, true)) {
 				FixerHelper::removeWhitespaceBefore($phpcsFile, $i);
-				$phpcsFile->fixer->addContentBefore($i, $phpcsFile->eolChar . $parametersIndentation);
+				FixerHelper::addBefore($phpcsFile, $i, $phpcsFile->eolChar . $parametersIndentation);
 			} elseif ($tokens[$i]['content'] === $phpcsFile->eolChar) {
-				$phpcsFile->fixer->addContent($i, $oneIndentation);
+				FixerHelper::add($phpcsFile, $i, $oneIndentation);
 			} else {
 				// Create conflict so inner calls are fixed in next loop
-				$phpcsFile->fixer->replaceToken($i, $tokens[$i]['content']);
+				FixerHelper::replace($phpcsFile, $i, $tokens[$i]['content']);
 			}
 		}
 
-		$phpcsFile->fixer->addContentBefore($parenthesisCloserPointer, $phpcsFile->eolChar . $indentation);
+		FixerHelper::addBefore($phpcsFile, $parenthesisCloserPointer, $phpcsFile->eolChar . $indentation);
 
 		$phpcsFile->fixer->endChangeset();
 	}
@@ -168,11 +167,15 @@ public function process(File $phpcsFile, $stringPointer): void
 	private function shouldBeSkipped(File $phpcsFile, int $stringPointer, int $parenthesisCloserPointer): bool
 	{
 		$tokens = $phpcsFile->getTokens();
-		$nameTokenCodes = TokenHelper::getOnlyNameTokenCodes();
 
 		$searchStartPointer = TokenHelper::findFirstNonWhitespaceOnLine($phpcsFile, $stringPointer);
 		while (true) {
-			$stringPointerBefore = TokenHelper::findNext($phpcsFile, $nameTokenCodes, $searchStartPointer, $stringPointer);
+			$stringPointerBefore = TokenHelper::findNext(
+				$phpcsFile,
+				TokenHelper::ONLY_NAME_TOKEN_CODES,
+				$searchStartPointer,
+				$stringPointer,
+			);
 
 			if ($stringPointerBefore === null) {
 				break;
@@ -192,7 +195,12 @@ private function shouldBeSkipped(File $phpcsFile, int $stringPointer, int $paren
 		$lastPointerOnLine = TokenHelper::findLastTokenOnLine($phpcsFile, $parenthesisCloserPointer);
 		$searchStartPointer = $parenthesisCloserPointer + 1;
 		while (true) {
-			$stringPointerAfter = TokenHelper::findNext($phpcsFile, $nameTokenCodes, $searchStartPointer, $lastPointerOnLine + 1);
+			$stringPointerAfter = TokenHelper::findNext(
+				$phpcsFile,
+				TokenHelper::ONLY_NAME_TOKEN_CODES,
+				$searchStartPointer,
+				$lastPointerOnLine + 1,
+			);
 
 			if ($stringPointerAfter === null) {
 				break;
@@ -205,7 +213,7 @@ private function shouldBeSkipped(File $phpcsFile, int $stringPointer, int $paren
 				&& $tokens[$tokens[$pointerAfterStringPointerAfter]['parenthesis_closer']]['line'] === $tokens[$stringPointer]['line']
 				&& $tokens[$pointerAfterStringPointerAfter]['parenthesis_closer'] !== TokenHelper::findNextEffective(
 					$phpcsFile,
-					$pointerAfterStringPointerAfter + 1
+					$pointerAfterStringPointerAfter + 1,
 				)
 			) {
 				return true;
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/RequireSingleLineCallSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/RequireSingleLineCallSniff.php
index 6e1bd4cb1..2c21ca9b3 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/RequireSingleLineCallSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/RequireSingleLineCallSniff.php
@@ -32,11 +32,9 @@ class RequireSingleLineCallSniff extends AbstractLineCall
 
 	public const CODE_REQUIRED_SINGLE_LINE_CALL = 'RequiredSingleLineCall';
 
-	/** @var int */
-	public $maxLineLength = 120;
+	public int $maxLineLength = 120;
 
-	/** @var bool */
-	public $ignoreWithComplexParameter = true;
+	public bool $ignoreWithComplexParameter = true;
 
 	/**
 	 * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
@@ -65,9 +63,9 @@ public function process(File $phpcsFile, $stringPointer): void
 
 		if (TokenHelper::findNext(
 			$phpcsFile,
-			array_merge(TokenHelper::$inlineCommentTokenCodes, Tokens::$heredocTokens),
+			array_merge(TokenHelper::INLINE_COMMENT_TOKEN_CODES, Tokens::$heredocTokens),
 			$parenthesisOpenerPointer + 1,
-			$parenthesisCloserPointer
+			$parenthesisCloserPointer,
 		) !== null) {
 			return;
 		}
@@ -88,7 +86,7 @@ public function process(File $phpcsFile, $stringPointer): void
 					$phpcsFile,
 					[T_CLOSURE, T_FN, T_OPEN_SHORT_ARRAY],
 					$parenthesisOpenerPointer + 1,
-					$parenthesisCloserPointer
+					$parenthesisCloserPointer,
 				) !== null
 			) {
 				return;
@@ -96,13 +94,12 @@ public function process(File $phpcsFile, $stringPointer): void
 
 			// Contains inner call
 			$callSearchStartPointer = $parenthesisOpenerPointer + 1;
-			$nameTokenCodes = TokenHelper::getOnlyNameTokenCodes();
 			while (true) {
 				$innerStringPointer = TokenHelper::findNext(
 					$phpcsFile,
-					$nameTokenCodes,
+					TokenHelper::ONLY_NAME_TOKEN_CODES,
 					$callSearchStartPointer,
-					$parenthesisCloserPointer
+					$parenthesisCloserPointer,
 				);
 				if ($innerStringPointer === null) {
 					break;
@@ -150,7 +147,7 @@ public function process(File $phpcsFile, $stringPointer): void
 
 		$phpcsFile->fixer->beginChangeset();
 
-		$phpcsFile->fixer->addContent($parenthesisOpenerPointer, $call);
+		FixerHelper::add($phpcsFile, $parenthesisOpenerPointer, $call);
 
 		FixerHelper::removeBetween($phpcsFile, $parenthesisOpenerPointer, $parenthesisCloserPointer);
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/RequireTrailingCommaInCallSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/RequireTrailingCommaInCallSniff.php
index 5dff75e98..9420a0ce1 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/RequireTrailingCommaInCallSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/RequireTrailingCommaInCallSniff.php
@@ -4,19 +4,18 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\SniffSettingsHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
-use function array_key_exists;
-use function array_merge;
 use function in_array;
 use const T_CLOSE_PARENTHESIS;
 use const T_COMMA;
-use const T_FN;
 use const T_ISSET;
 use const T_OPEN_PARENTHESIS;
 use const T_PARENT;
 use const T_SELF;
 use const T_STATIC;
+use const T_STRING;
 use const T_UNSET;
 use const T_VARIABLE;
 
@@ -25,8 +24,7 @@ class RequireTrailingCommaInCallSniff implements Sniff
 
 	public const CODE_MISSING_TRAILING_COMMA = 'MissingTrailingComma';
 
-	/** @var bool|null */
-	public $enable = null;
+	public ?bool $enable = null;
 
 	/**
 	 * @return array
@@ -52,22 +50,21 @@ public function process(File $phpcsFile, $parenthesisOpenerPointer): void
 
 		$tokens = $phpcsFile->getTokens();
 
-		if (array_key_exists('parenthesis_owner', $tokens[$parenthesisOpenerPointer])) {
-			return;
-		}
-
 		$pointerBeforeParenthesisOpener = TokenHelper::findPreviousEffective($phpcsFile, $parenthesisOpenerPointer - 1);
+
 		if (!in_array(
 			$tokens[$pointerBeforeParenthesisOpener]['code'],
-			array_merge(
-				TokenHelper::getOnlyNameTokenCodes(),
-				[T_VARIABLE, T_ISSET, T_UNSET, T_CLOSE_PARENTHESIS, T_SELF, T_STATIC, T_PARENT]
-			),
-			true
+			[...TokenHelper::ONLY_NAME_TOKEN_CODES, T_STRING, T_VARIABLE, T_ISSET, T_UNSET, T_CLOSE_PARENTHESIS, T_SELF, T_STATIC, T_PARENT],
+			true,
 		)) {
 			return;
 		}
 
+		$functionPointer = TokenHelper::findPreviousEffective($phpcsFile, $pointerBeforeParenthesisOpener - 1);
+		if (in_array($tokens[$functionPointer]['code'], TokenHelper::FUNCTION_TOKEN_CODES, true)) {
+			return;
+		}
+
 		$parenthesisCloserPointer = $tokens[$parenthesisOpenerPointer]['parenthesis_closer'];
 
 		if ($tokens[$parenthesisOpenerPointer]['line'] === $tokens[$parenthesisCloserPointer]['line']) {
@@ -83,13 +80,6 @@ public function process(File $phpcsFile, $parenthesisOpenerPointer): void
 			return;
 		}
 
-		if (
-			array_key_exists('scope_condition', $tokens[$pointerBeforeParenthesisCloser])
-			&& $tokens[$tokens[$pointerBeforeParenthesisCloser]['scope_condition']]['code'] === T_FN
-		) {
-			return;
-		}
-
 		if ($tokens[$pointerBeforeParenthesisCloser]['code'] === T_COMMA) {
 			return;
 		}
@@ -97,7 +87,7 @@ public function process(File $phpcsFile, $parenthesisOpenerPointer): void
 		$fix = $phpcsFile->addFixableError(
 			'Multi-line function calls must have a trailing comma after the last parameter.',
 			$pointerBeforeParenthesisCloser,
-			self::CODE_MISSING_TRAILING_COMMA
+			self::CODE_MISSING_TRAILING_COMMA,
 		);
 
 		if (!$fix) {
@@ -105,7 +95,7 @@ public function process(File $phpcsFile, $parenthesisOpenerPointer): void
 		}
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->addContent($pointerBeforeParenthesisCloser, ',');
+		FixerHelper::add($phpcsFile, $pointerBeforeParenthesisCloser, ',');
 		$phpcsFile->fixer->endChangeset();
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/RequireTrailingCommaInClosureUseSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/RequireTrailingCommaInClosureUseSniff.php
index e50a8e3b4..5ac5eb57f 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/RequireTrailingCommaInClosureUseSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/RequireTrailingCommaInClosureUseSniff.php
@@ -4,6 +4,7 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\SniffSettingsHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use const T_CLOSURE;
@@ -16,8 +17,7 @@ class RequireTrailingCommaInClosureUseSniff implements Sniff
 
 	public const CODE_MISSING_TRAILING_COMMA = 'MissingTrailingComma';
 
-	/** @var bool|null */
-	public $enable = null;
+	public ?bool $enable = null;
 
 	/**
 	 * @return array
@@ -60,7 +60,7 @@ public function process(File $phpcsFile, $functionPointer): void
 			$phpcsFile,
 			T_WHITESPACE,
 			$useParenthesisCloserPointer - 1,
-			$useParenthesisOpenerPointer
+			$useParenthesisOpenerPointer,
 		);
 
 		if ($tokens[$pointerBeforeUseParenthesisCloser]['code'] === T_COMMA) {
@@ -70,7 +70,7 @@ public function process(File $phpcsFile, $functionPointer): void
 		$fix = $phpcsFile->addFixableError(
 			'Multi-line "use" of closure declaration must have a trailing comma after the last inherited variable.',
 			$pointerBeforeUseParenthesisCloser,
-			self::CODE_MISSING_TRAILING_COMMA
+			self::CODE_MISSING_TRAILING_COMMA,
 		);
 
 		if (!$fix) {
@@ -78,7 +78,7 @@ public function process(File $phpcsFile, $functionPointer): void
 		}
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->addContent($pointerBeforeUseParenthesisCloser, ',');
+		FixerHelper::add($phpcsFile, $pointerBeforeUseParenthesisCloser, ',');
 		$phpcsFile->fixer->endChangeset();
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/RequireTrailingCommaInDeclarationSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/RequireTrailingCommaInDeclarationSniff.php
index aab66c58e..ce1a47fe7 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/RequireTrailingCommaInDeclarationSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/RequireTrailingCommaInDeclarationSniff.php
@@ -4,6 +4,7 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\SniffSettingsHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use const T_COMMA;
@@ -13,15 +14,14 @@ class RequireTrailingCommaInDeclarationSniff implements Sniff
 
 	public const CODE_MISSING_TRAILING_COMMA = 'MissingTrailingComma';
 
-	/** @var bool|null */
-	public $enable = null;
+	public ?bool $enable = null;
 
 	/**
 	 * @return array
 	 */
 	public function register(): array
 	{
-		return TokenHelper::$functionTokenCodes;
+		return TokenHelper::FUNCTION_TOKEN_CODES;
 	}
 
 	/**
@@ -48,7 +48,7 @@ public function process(File $phpcsFile, $functionPointer): void
 		$pointerBeforeParenthesisCloser = TokenHelper::findPreviousEffective(
 			$phpcsFile,
 			$parenthesisCloserPointer - 1,
-			$parenthesisOpenerPointer
+			$parenthesisOpenerPointer,
 		);
 
 		if ($pointerBeforeParenthesisCloser === $parenthesisOpenerPointer) {
@@ -62,7 +62,7 @@ public function process(File $phpcsFile, $functionPointer): void
 		$fix = $phpcsFile->addFixableError(
 			'Multi-line function declaration must have a trailing comma after the last parameter.',
 			$pointerBeforeParenthesisCloser,
-			self::CODE_MISSING_TRAILING_COMMA
+			self::CODE_MISSING_TRAILING_COMMA,
 		);
 
 		if (!$fix) {
@@ -70,7 +70,7 @@ public function process(File $phpcsFile, $functionPointer): void
 		}
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->addContent($pointerBeforeParenthesisCloser, ',');
+		FixerHelper::add($phpcsFile, $pointerBeforeParenthesisCloser, ',');
 		$phpcsFile->fixer->endChangeset();
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/StaticClosureSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/StaticClosureSniff.php
index 5e2053cc9..35ffd7e11 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/StaticClosureSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/StaticClosureSniff.php
@@ -4,6 +4,7 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use SlevomatCodingStandard\Helpers\VariableHelper;
 use const T_CLOSURE;
@@ -62,7 +63,7 @@ public function process(File $phpcsFile, $closurePointer): void
 			T_VARIABLE,
 			'$this',
 			$closureScopeOpenerPointer + 1,
-			$closureScopeCloserPointer
+			$closureScopeCloserPointer,
 		);
 		if ($thisPointer !== null) {
 			return;
@@ -72,7 +73,7 @@ public function process(File $phpcsFile, $closurePointer): void
 			$phpcsFile,
 			T_DOUBLE_QUOTED_STRING,
 			$closureScopeOpenerPointer + 1,
-			$closureScopeCloserPointer
+			$closureScopeCloserPointer,
 		);
 		foreach ($stringPointers as $stringPointer) {
 			if (VariableHelper::isUsedInScopeInString($phpcsFile, '$this', $stringPointer)) {
@@ -88,7 +89,7 @@ public function process(File $phpcsFile, $closurePointer): void
 		$fix = $phpcsFile->addFixableError(
 			'Closure not using "$this" should be declared static.',
 			$closurePointer,
-			self::CODE_CLOSURE_NOT_STATIC
+			self::CODE_CLOSURE_NOT_STATIC,
 		);
 
 		if (!$fix) {
@@ -96,7 +97,7 @@ public function process(File $phpcsFile, $closurePointer): void
 		}
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->addContentBefore($closurePointer, 'static ');
+		FixerHelper::addBefore($phpcsFile, $closurePointer, 'static ');
 		$phpcsFile->fixer->endChangeset();
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/StrictCallSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/StrictCallSniff.php
index a012fb4a8..6e4aaceb3 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/StrictCallSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/StrictCallSniff.php
@@ -37,7 +37,7 @@ class StrictCallSniff implements Sniff
 	 */
 	public function register(): array
 	{
-		return TokenHelper::getOnlyNameTokenCodes();
+		return TokenHelper::ONLY_NAME_TOKEN_CODES;
 	}
 
 	/**
@@ -102,7 +102,7 @@ public function process(File $phpcsFile, $stringPointer): void
 			$strictParameterValue = TokenHelper::getContent(
 				$phpcsFile,
 				$commaPointers[self::FUNCTIONS[$functionName] - 2] + 1,
-				($hasTrailingComma ? $lastCommaPointer : $parenthesisCloserPointer) - 1
+				($hasTrailingComma ? $lastCommaPointer : $parenthesisCloserPointer) - 1,
 			);
 
 			if (strtolower(trim($strictParameterValue)) !== 'false') {
@@ -112,14 +112,14 @@ public function process(File $phpcsFile, $stringPointer): void
 			$phpcsFile->addError(
 				sprintf('Strict parameter should be set to true in %s() call.', $functionName),
 				$stringPointer,
-				self::CODE_NON_STRICT_COMPARISON
+				self::CODE_NON_STRICT_COMPARISON,
 			);
 
 		} elseif ($parametersCount === self::FUNCTIONS[$functionName] - 1) {
 			$phpcsFile->addError(
 				sprintf('Strict parameter missing in %s() call.', $functionName),
 				$stringPointer,
-				self::CODE_STRICT_PARAMETER_MISSING
+				self::CODE_STRICT_PARAMETER_MISSING,
 			);
 		}
 	}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/UnusedInheritedVariablePassedToClosureSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/UnusedInheritedVariablePassedToClosureSniff.php
index 3fe2e7e20..a6f76c0f9 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/UnusedInheritedVariablePassedToClosureSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/UnusedInheritedVariablePassedToClosureSniff.php
@@ -55,7 +55,7 @@ public function process(File $phpcsFile, $usePointer): void
 				$phpcsFile,
 				T_VARIABLE,
 				$currentPointer,
-				$tokens[$parenthesisOpenerPointer]['parenthesis_closer']
+				$tokens[$parenthesisOpenerPointer]['parenthesis_closer'],
 			);
 			if ($variablePointer === null) {
 				break;
@@ -67,7 +67,7 @@ public function process(File $phpcsFile, $usePointer): void
 				$parenthesisOpenerPointer,
 				$tokens[$parenthesisOpenerPointer]['parenthesis_closer'],
 				$variablePointer,
-				$closurePointer
+				$closurePointer,
 			);
 
 			$currentPointer = $variablePointer + 1;
@@ -92,7 +92,7 @@ private function checkVariableUsage(
 		$fix = $phpcsFile->addFixableError(
 			sprintf('Unused inherited variable %s passed to closure.', $tokens[$variablePointer]['content']),
 			$variablePointer,
-			self::CODE_UNUSED_INHERITED_VARIABLE
+			self::CODE_UNUSED_INHERITED_VARIABLE,
 		);
 
 		if (!$fix) {
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/UnusedParameterSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/UnusedParameterSniff.php
index 857f7b30b..903f32b8f 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/UnusedParameterSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/UnusedParameterSniff.php
@@ -28,7 +28,7 @@ class UnusedParameterSniff implements Sniff
 	 */
 	public function register(): array
 	{
-		return TokenHelper::$functionTokenCodes;
+		return TokenHelper::FUNCTION_TOKEN_CODES;
 	}
 
 	/**
@@ -52,7 +52,7 @@ public function process(File $phpcsFile, $functionPointer): void
 				$phpcsFile,
 				T_VARIABLE,
 				$currentPointer,
-				$tokens[$functionPointer]['parenthesis_closer']
+				$tokens[$functionPointer]['parenthesis_closer'],
 			);
 			if ($parameterPointer === null) {
 				break;
@@ -62,7 +62,7 @@ public function process(File $phpcsFile, $functionPointer): void
 				$phpcsFile,
 				array_merge([T_COMMA], Tokens::$scopeModifiers),
 				$parameterPointer - 1,
-				$tokens[$functionPointer]['parenthesis_opener']
+				$tokens[$functionPointer]['parenthesis_opener'],
 			);
 
 			if ($previousPointer !== null && in_array($tokens[$previousPointer]['code'], Tokens::$scopeModifiers, true)) {
@@ -79,7 +79,7 @@ public function process(File $phpcsFile, $functionPointer): void
 				$phpcsFile->addError(
 					sprintf('Unused parameter %s.', $tokens[$parameterPointer]['content']),
 					$parameterPointer,
-					self::CODE_UNUSED_PARAMETER
+					self::CODE_UNUSED_PARAMETER,
 				);
 			} else {
 				$suppressUseless = false;
@@ -95,7 +95,7 @@ public function process(File $phpcsFile, $functionPointer): void
 		$phpcsFile->addError(
 			sprintf('Useless %s %s', SuppressHelper::ANNOTATION, self::NAME),
 			$functionPointer,
-			self::CODE_USELESS_SUPPRESS
+			self::CODE_USELESS_SUPPRESS,
 		);
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/UselessParameterDefaultValueSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/UselessParameterDefaultValueSniff.php
index 2a9d613dd..e747c53ad 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/UselessParameterDefaultValueSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Functions/UselessParameterDefaultValueSniff.php
@@ -4,6 +4,7 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use function array_key_exists;
 use function count;
@@ -21,7 +22,7 @@ class UselessParameterDefaultValueSniff implements Sniff
 	 */
 	public function register(): array
 	{
-		return TokenHelper::$functionTokenCodes;
+		return TokenHelper::FUNCTION_TOKEN_CODES;
 	}
 
 	/**
@@ -63,7 +64,7 @@ public function process(File $phpcsFile, $functionPointer): void
 				$fix = $phpcsFile->addFixableError(
 					sprintf('Useless default value of parameter %s.', $parameter['name']),
 					$parameter['token'],
-					self::CODE_USELESS_PARAMETER_DEFAULT_VALUE
+					self::CODE_USELESS_PARAMETER_DEFAULT_VALUE,
 				);
 
 				if (!$fix) {
@@ -76,7 +77,7 @@ public function process(File $phpcsFile, $functionPointer): void
 
 				$phpcsFile->fixer->beginChangeset();
 				for ($k = $parameterPointer + 1; $k < $commaPointer; $k++) {
-					$phpcsFile->fixer->replaceToken($k, '');
+					FixerHelper::replace($phpcsFile, $k, '');
 				}
 				$phpcsFile->fixer->endChangeset();
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/AbstractFullyQualifiedGlobalReference.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/AbstractFullyQualifiedGlobalReference.php
index 5e91e0e63..4c7f1d3e1 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/AbstractFullyQualifiedGlobalReference.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/AbstractFullyQualifiedGlobalReference.php
@@ -4,6 +4,7 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\NamespaceHelper;
 use SlevomatCodingStandard\Helpers\ReferencedName;
 use SlevomatCodingStandard\Helpers\ReferencedNameHelper;
@@ -28,16 +29,16 @@ abstract class AbstractFullyQualifiedGlobalReference implements Sniff
 	public const CODE_NON_FULLY_QUALIFIED = 'NonFullyQualified';
 
 	/** @var list */
-	public $exclude = [];
+	public array $exclude = [];
 
 	/** @var list */
-	public $include = [];
+	public array $include = [];
 
 	/** @var list|null */
-	private $normalizedExclude;
+	private ?array $normalizedExclude = null;
 
 	/** @var list|null */
-	private $normalizedInclude;
+	private ?array $normalizedInclude = null;
 
 	abstract protected function getNotFullyQualifiedMessage(): string;
 
@@ -118,14 +119,14 @@ public function process(File $phpcsFile, $openTagPointer): void
 			$fix = $phpcsFile->addFixableError(
 				sprintf($this->getNotFullyQualifiedMessage(), $tokens[$namePointer]['content']),
 				$namePointer,
-				self::CODE_NON_FULLY_QUALIFIED
+				self::CODE_NON_FULLY_QUALIFIED,
 			);
 			if (!$fix) {
 				continue;
 			}
 
 			$phpcsFile->fixer->beginChangeset();
-			$phpcsFile->fixer->addContentBefore($namePointer, NamespaceHelper::NAMESPACE_SEPARATOR);
+			FixerHelper::addBefore($phpcsFile, $namePointer, NamespaceHelper::NAMESPACE_SEPARATOR);
 			$phpcsFile->fixer->endChangeset();
 		}
 	}
@@ -161,9 +162,7 @@ private function normalizeNames(array $names): array
 		$names = SniffSettingsHelper::normalizeArray($names);
 
 		if (!$this->isCaseSensitive()) {
-			$names = array_map(static function (string $name): string {
-				return strtolower($name);
-			}, $names);
+			$names = array_map(static fn (string $name): string => strtolower($name), $names);
 		}
 
 		return $names;
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/AlphabeticallySortedUsesSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/AlphabeticallySortedUsesSniff.php
index 6e5b3a0d4..13466cb3d 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/AlphabeticallySortedUsesSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/AlphabeticallySortedUsesSniff.php
@@ -35,11 +35,9 @@ class AlphabeticallySortedUsesSniff implements Sniff
 
 	public const CODE_INCORRECT_ORDER = 'IncorrectlyOrderedUses';
 
-	/** @var bool */
-	public $psr12Compatible = true;
+	public bool $psr12Compatible = true;
 
-	/** @var bool */
-	public $caseSensitive = false;
+	public bool $caseSensitive = false;
 
 	/**
 	 * @return array
@@ -92,7 +90,7 @@ public function process(File $phpcsFile, $openTagPointer): void
 						$errorParameters = [
 							sprintf(
 								'Use statements should be sorted alphabetically. The first wrong one is %s.',
-								$useStatement->getFullyQualifiedTypeName()
+								$useStatement->getFullyQualifiedTypeName(),
 							),
 							$useStatement->getPointer(),
 							self::CODE_INCORRECT_ORDER,
@@ -145,14 +143,14 @@ private function fixAlphabeticalOrder(File $phpcsFile, array $useStatements): vo
 				continue;
 			}
 
-			$commentStartPointer = in_array($tokens[$pointerBeforeUseStatement]['code'], TokenHelper::$inlineCommentTokenCodes, true)
+			$commentStartPointer = in_array($tokens[$pointerBeforeUseStatement]['code'], TokenHelper::INLINE_COMMENT_TOKEN_CODES, true)
 				? CommentHelper::getMultilineCommentStartPointer($phpcsFile, $pointerBeforeUseStatement)
 				: $tokens[$pointerBeforeUseStatement]['comment_opener'];
 
 			$commentsBefore[$useStatement->getPointer()] = TokenHelper::getContent(
 				$phpcsFile,
 				$commentStartPointer,
-				$pointerBeforeUseStatement
+				$pointerBeforeUseStatement,
 			);
 
 			if ($firstPointer === $useStatement->getPointer()) {
@@ -160,15 +158,14 @@ private function fixAlphabeticalOrder(File $phpcsFile, array $useStatements): vo
 			}
 		}
 
-		uasort($useStatements, function (UseStatement $a, UseStatement $b): int {
-			return $this->compareUseStatements($a, $b);
-		});
+		uasort($useStatements, fn (UseStatement $a, UseStatement $b): int => $this->compareUseStatements($a, $b));
 
 		$phpcsFile->fixer->beginChangeset();
 
 		FixerHelper::removeBetweenIncluding($phpcsFile, $firstPointer, $lastSemicolonPointer);
 
-		$phpcsFile->fixer->addContent(
+		FixerHelper::add(
+			$phpcsFile,
 			$firstPointer,
 			implode($phpcsFile->eolChar, array_map(static function (UseStatement $useStatement) use ($phpcsFile, $commentsBefore): string {
 				$unqualifiedName = NamespaceHelper::getUnqualifiedNameFromFullyQualifiedName($useStatement->getFullyQualifiedTypeName());
@@ -193,9 +190,9 @@ private function fixAlphabeticalOrder(File $phpcsFile, array $useStatements): vo
 					$commentBefore,
 					$useTypeFormatted,
 					$useStatement->getFullyQualifiedTypeName(),
-					$useStatement->getNameAsReferencedInFile()
+					$useStatement->getNameAsReferencedInFile(),
 				);
-			}, $useStatements))
+			}, $useStatements)),
 		);
 		$phpcsFile->fixer->endChangeset();
 	}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/DisallowGroupUseSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/DisallowGroupUseSniff.php
index 35aecfa4d..a2a7e1e87 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/DisallowGroupUseSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/DisallowGroupUseSniff.php
@@ -30,7 +30,7 @@ public function process(File $phpcsFile, $usePointer): void
 		$phpcsFile->addError(
 			'Group use declaration is disallowed, use single use for every import.',
 			$usePointer,
-			self::CODE_DISALLOWED_GROUP_USE
+			self::CODE_DISALLOWED_GROUP_USE,
 		);
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/FullyQualifiedClassNameInAnnotationSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/FullyQualifiedClassNameInAnnotationSniff.php
index 17f25b0a1..d120815c9 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/FullyQualifiedClassNameInAnnotationSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/FullyQualifiedClassNameInAnnotationSniff.php
@@ -26,7 +26,7 @@ class FullyQualifiedClassNameInAnnotationSniff implements Sniff
 	public const CODE_NON_FULLY_QUALIFIED_CLASS_NAME = 'NonFullyQualifiedClassName';
 
 	/** @var list */
-	public $ignoredAnnotationNames = [];
+	public array $ignoredAnnotationNames = [];
 
 	/**
 	 * @return array
@@ -48,7 +48,6 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 		$this->ignoredAnnotationNames = SniffSettingsHelper::normalizeArray($this->ignoredAnnotationNames);
 
 		foreach ($annotations as $annotation) {
-			/** @var list $identifierTypeNodes */
 			$identifierTypeNodes = AnnotationHelper::getAnnotationNodesByType($annotation->getNode(), IdentifierTypeNode::class);
 
 			$annotationName = $annotation->getName();
@@ -78,7 +77,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 				$fix = $phpcsFile->addFixableError(sprintf(
 					'Class name %s in %s should be referenced via a fully qualified name.',
 					$fullyQualifiedTypeHint,
-					$annotationName
+					$annotationName,
 				), $annotation->getStartPointer(), self::CODE_NON_FULLY_QUALIFIED_CLASS_NAME);
 
 				if (!$fix) {
@@ -91,7 +90,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 					$parsedDocComment,
 					$annotation,
 					$typeHintNode,
-					new IdentifierTypeNode($fullyQualifiedTypeHint)
+					new IdentifierTypeNode($fullyQualifiedTypeHint),
 				);
 
 				$phpcsFile->fixer->beginChangeset();
@@ -100,13 +99,12 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 					$phpcsFile,
 					$parsedDocComment->getOpenPointer(),
 					$parsedDocComment->getClosePointer(),
-					$fixedDocComment
+					$fixedDocComment,
 				);
 
 				$phpcsFile->fixer->endChangeset();
 			}
 
-			/** @var list $constantFetchNodes */
 			$constantFetchNodes = AnnotationHelper::getAnnotationNodesByType($annotation->getNode(), ConstFetchNode::class);
 
 			foreach ($constantFetchNodes as $constantFetchNode) {
@@ -132,7 +130,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 					'%s name %s in %s should be referenced via a fully qualified name.',
 					$isClassConstant ? 'Class' : 'Constant',
 					$fullyQualifiedTypeHint,
-					$annotationName
+					$annotationName,
 				), $annotation->getStartPointer(), self::CODE_NON_FULLY_QUALIFIED_CLASS_NAME);
 
 				if (!$fix) {
@@ -152,7 +150,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 					$parsedDocComment,
 					$annotation,
 					$constantFetchNode,
-					$fixedConstantFetchNode
+					$fixedConstantFetchNode,
 				);
 
 				$phpcsFile->fixer->beginChangeset();
@@ -161,7 +159,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 					$phpcsFile,
 					$parsedDocComment->getOpenPointer(),
 					$parsedDocComment->getClosePointer(),
-					$fixedDocComment
+					$fixedDocComment,
 				);
 
 				$phpcsFile->fixer->endChangeset();
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/FullyQualifiedExceptionsSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/FullyQualifiedExceptionsSniff.php
index 8d410cbd8..a959b5833 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/FullyQualifiedExceptionsSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/FullyQualifiedExceptionsSniff.php
@@ -24,16 +24,16 @@ class FullyQualifiedExceptionsSniff implements Sniff
 	public const CODE_NON_FULLY_QUALIFIED_EXCEPTION = 'NonFullyQualifiedException';
 
 	/** @var list */
-	public $specialExceptionNames = [];
+	public array $specialExceptionNames = [];
 
 	/** @var list */
-	public $ignoredNames = [];
+	public array $ignoredNames = [];
 
 	/** @var list|null */
-	private $normalizedSpecialExceptionNames;
+	private ?array $normalizedSpecialExceptionNames = null;
 
 	/** @var list|null */
-	private $normalizedIgnoredNames;
+	private ?array $normalizedIgnoredNames = null;
 
 	/**
 	 * @return array
@@ -75,7 +75,7 @@ public function process(File $phpcsFile, $openTagPointer): void
 						!StringHelper::endsWith($useStatement->getFullyQualifiedTypeName(), 'Exception')
 						&& $useStatement->getFullyQualifiedTypeName() !== Throwable::class
 						&& (!StringHelper::endsWith($useStatement->getFullyQualifiedTypeName(), 'Error') || NamespaceHelper::hasNamespace(
-							$useStatement->getFullyQualifiedTypeName()
+							$useStatement->getFullyQualifiedTypeName(),
 						))
 						&& !in_array($useStatement->getFullyQualifiedTypeName(), $this->getSpecialExceptionNames(), true)
 					)
@@ -119,7 +119,7 @@ public function process(File $phpcsFile, $openTagPointer): void
 
 			$fix = $phpcsFile->addFixableError(sprintf(
 				'Exception %s should be referenced via a fully qualified name.',
-				$name
+				$name,
 			), $pointer, self::CODE_NON_FULLY_QUALIFIED_EXCEPTION);
 			if (!$fix) {
 				continue;
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/FullyQualifiedGlobalFunctionsSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/FullyQualifiedGlobalFunctionsSniff.php
index 30741a3b9..1d9bd5bdc 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/FullyQualifiedGlobalFunctionsSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/FullyQualifiedGlobalFunctionsSniff.php
@@ -4,14 +4,13 @@
 
 use SlevomatCodingStandard\Helpers\FunctionHelper;
 use SlevomatCodingStandard\Helpers\ReferencedName;
-use function array_merge;
+use function array_push;
 
 class FullyQualifiedGlobalFunctionsSniff
 	extends AbstractFullyQualifiedGlobalReference
 {
 
-	/** @var bool */
-	public $includeSpecialFunctions = false;
+	public bool $includeSpecialFunctions = false;
 
 	/**
 	 * @return list
@@ -21,7 +20,7 @@ protected function getNormalizedInclude(): array
 		$include = parent::getNormalizedInclude();
 
 		if ($this->includeSpecialFunctions) {
-			$include = array_merge($include, FunctionHelper::SPECIAL_FUNCTIONS);
+			array_push($include, ...FunctionHelper::SPECIAL_FUNCTIONS);
 		}
 
 		return $include;
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/MultipleUsesPerLineSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/MultipleUsesPerLineSniff.php
index 5549cae38..38ed1031d 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/MultipleUsesPerLineSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/MultipleUsesPerLineSniff.php
@@ -31,10 +31,7 @@ public function register(): array
 	 */
 	public function process(File $phpcsFile, $usePointer): void
 	{
-		if (
-			UseStatementHelper::isAnonymousFunctionUse($phpcsFile, $usePointer)
-			|| UseStatementHelper::isTraitUse($phpcsFile, $usePointer)
-		) {
+		if (!UseStatementHelper::isImportUse($phpcsFile, $usePointer)) {
 			return;
 		}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/NamespaceDeclarationSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/NamespaceDeclarationSniff.php
index 028a63e2f..b94286198 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/NamespaceDeclarationSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/NamespaceDeclarationSniff.php
@@ -59,7 +59,7 @@ private function checkWhitespaceAfterNamespace(File $phpcsFile, int $namespacePo
 			$phpcsFile->addError(
 				'Expected one space after namespace statement.',
 				$namespacePointer,
-				self::CODE_INVALID_WHITESPACE_AFTER_NAMESPACE
+				self::CODE_INVALID_WHITESPACE_AFTER_NAMESPACE,
 			);
 			return;
 		}
@@ -68,9 +68,7 @@ private function checkWhitespaceAfterNamespace(File $phpcsFile, int $namespacePo
 			return;
 		}
 
-		$errorMessage = $tokens[$whitespacePointer]['content'][0] === "\t"
-			? 'Expected one space after namespace statement, found tab.'
-			: sprintf('Expected one space after namespace statement, found %d.', strlen($tokens[$whitespacePointer]['content']));
+		$errorMessage = sprintf('Expected one space after namespace statement, found %d.', strlen($tokens[$whitespacePointer]['content']));
 
 		$fix = $phpcsFile->addFixableError($errorMessage, $namespacePointer, self::CODE_INVALID_WHITESPACE_AFTER_NAMESPACE);
 
@@ -79,7 +77,7 @@ private function checkWhitespaceAfterNamespace(File $phpcsFile, int $namespacePo
 		}
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->replaceToken($whitespacePointer, ' ');
+		FixerHelper::replace($phpcsFile, $whitespacePointer, ' ');
 		$phpcsFile->fixer->endChangeset();
 	}
 
@@ -92,8 +90,8 @@ private function checkDisallowedContentBetweenNamespaceNameAndSemicolon(File $ph
 		$namespaceNameStartPointer = TokenHelper::findNextEffective($phpcsFile, $namespacePointer + 1);
 		$namespaceNameEndPointer = TokenHelper::findNextExcluding(
 			$phpcsFile,
-			TokenHelper::getNameTokenCodes(),
-			$namespaceNameStartPointer + 1
+			TokenHelper::NAME_TOKEN_CODES,
+			$namespaceNameStartPointer + 1,
 		) - 1;
 
 		/** @var int $namespaceSemicolonPointer */
@@ -106,7 +104,7 @@ private function checkDisallowedContentBetweenNamespaceNameAndSemicolon(File $ph
 		$fix = $phpcsFile->addFixableError(
 			'Disallowed content between namespace name and semicolon.',
 			$namespacePointer,
-			self::CODE_DISALLOWED_CONTENT_BETWEEN_NAMESPACE_NAME_AND_SEMICOLON
+			self::CODE_DISALLOWED_CONTENT_BETWEEN_NAMESPACE_NAME_AND_SEMICOLON,
 		);
 
 		if (!$fix) {
@@ -131,7 +129,7 @@ private function checkDisallowedBracketedSyntax(File $phpcsFile, int $namespaceP
 		$fix = $phpcsFile->addFixableError(
 			'Bracketed syntax for namespaces is disallowed.',
 			$namespacePointer,
-			self::CODE_DISALLOWED_BRACKETED_SYNTAX
+			self::CODE_DISALLOWED_BRACKETED_SYNTAX,
 		);
 
 		if (!$fix) {
@@ -139,8 +137,8 @@ private function checkDisallowedBracketedSyntax(File $phpcsFile, int $namespaceP
 		}
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->replaceToken($tokens[$namespacePointer]['scope_opener'], ';');
-		$phpcsFile->fixer->replaceToken($tokens[$namespacePointer]['scope_closer'], '');
+		FixerHelper::replace($phpcsFile, $tokens[$namespacePointer]['scope_opener'], ';');
+		FixerHelper::replace($phpcsFile, $tokens[$namespacePointer]['scope_closer'], '');
 		$phpcsFile->fixer->endChangeset();
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/NamespaceSpacingSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/NamespaceSpacingSniff.php
index 14229a039..e43a8e59c 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/NamespaceSpacingSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/NamespaceSpacingSniff.php
@@ -24,11 +24,9 @@ class NamespaceSpacingSniff implements Sniff
 	public const CODE_INCORRECT_LINES_COUNT_BEFORE_NAMESPACE = 'IncorrectLinesCountBeforeNamespace';
 	public const CODE_INCORRECT_LINES_COUNT_AFTER_NAMESPACE = 'IncorrectLinesCountAfterNamespace';
 
-	/** @var int */
-	public $linesCountBeforeNamespace = 1;
+	public int $linesCountBeforeNamespace = 1;
 
-	/** @var int */
-	public $linesCountAfterNamespace = 1;
+	public int $linesCountAfterNamespace = 1;
 
 	/**
 	 * @return array
@@ -85,10 +83,10 @@ private function checkLinesBeforeNamespace(File $phpcsFile, int $namespacePointe
 				'Expected %d line%s before namespace statement, found %d.',
 				$this->linesCountBeforeNamespace,
 				$this->linesCountBeforeNamespace === 1 ? '' : 's',
-				$actualLinesCountBeforeNamespace
+				$actualLinesCountBeforeNamespace,
 			),
 			$namespacePointer,
-			self::CODE_INCORRECT_LINES_COUNT_BEFORE_NAMESPACE
+			self::CODE_INCORRECT_LINES_COUNT_BEFORE_NAMESPACE,
 		);
 
 		if (!$fix) {
@@ -98,11 +96,12 @@ private function checkLinesBeforeNamespace(File $phpcsFile, int $namespacePointe
 		$phpcsFile->fixer->beginChangeset();
 
 		if ($tokens[$pointerBeforeNamespace]['code'] === T_OPEN_TAG) {
-			$phpcsFile->fixer->replaceToken($pointerBeforeNamespace, 'fixer->replaceToken(
+			FixerHelper::replace(
+				$phpcsFile,
 				$pointerBeforeNamespace,
-				rtrim($tokens[$pointerBeforeNamespace]['content'], $phpcsFile->eolChar)
+				rtrim($tokens[$pointerBeforeNamespace]['content'], $phpcsFile->eolChar),
 			);
 		}
 
@@ -141,10 +140,10 @@ private function checkLinesAfterNamespace(File $phpcsFile, int $namespacePointer
 				'Expected %d line%s after namespace statement, found %d.',
 				$this->linesCountAfterNamespace,
 				$this->linesCountAfterNamespace === 1 ? '' : 's',
-				$actualLinesCountAfterNamespace
+				$actualLinesCountAfterNamespace,
 			),
 			$namespacePointer,
-			self::CODE_INCORRECT_LINES_COUNT_AFTER_NAMESPACE
+			self::CODE_INCORRECT_LINES_COUNT_AFTER_NAMESPACE,
 		);
 
 		if (!$fix) {
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/ReferenceUsedNamesOnlySniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/ReferenceUsedNamesOnlySniff.php
index 224afd5e5..91d7a3895 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/ReferenceUsedNamesOnlySniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/ReferenceUsedNamesOnlySniff.php
@@ -65,60 +65,51 @@ class ReferenceUsedNamesOnlySniff implements Sniff
 	private const SOURCE_ANNOTATION_CONSTANT_FETCH = 3;
 	private const SOURCE_ATTRIBUTE = 4;
 
-	/** @var bool */
-	public $searchAnnotations = false;
+	public bool $searchAnnotations = false;
 
-	/** @var bool */
-	public $allowFullyQualifiedExceptions = false;
+	public bool $allowFullyQualifiedExceptions = false;
 
-	/** @var bool */
-	public $allowFullyQualifiedGlobalClasses = false;
+	public bool $allowFullyQualifiedGlobalClasses = false;
 
-	/** @var bool */
-	public $allowFullyQualifiedGlobalFunctions = false;
+	public bool $allowFullyQualifiedGlobalFunctions = false;
 
-	/** @var bool */
-	public $allowFallbackGlobalFunctions = true;
+	public bool $allowFallbackGlobalFunctions = true;
 
-	/** @var bool */
-	public $allowFullyQualifiedGlobalConstants = false;
+	public bool $allowFullyQualifiedGlobalConstants = false;
 
-	/** @var bool */
-	public $allowFallbackGlobalConstants = true;
+	public bool $allowFallbackGlobalConstants = true;
+
+	public bool $allowWhenNoNamespace = true;
 
 	/** @var list */
-	public $specialExceptionNames = [];
+	public array $specialExceptionNames = [];
 
 	/** @var list */
-	public $ignoredNames = [];
+	public array $ignoredNames = [];
 
-	/** @var bool */
-	public $allowPartialUses = true;
+	public bool $allowPartialUses = true;
 
 	/**
 	 * If empty, all namespaces are required to be used
 	 *
 	 * @var list
 	 */
-	public $namespacesRequiredToUse = [];
+	public array $namespacesRequiredToUse = [];
 
-	/** @var bool */
-	public $allowFullyQualifiedNameForCollidingClasses = false;
+	public bool $allowFullyQualifiedNameForCollidingClasses = false;
 
-	/** @var bool */
-	public $allowFullyQualifiedNameForCollidingFunctions = false;
+	public bool $allowFullyQualifiedNameForCollidingFunctions = false;
 
-	/** @var bool */
-	public $allowFullyQualifiedNameForCollidingConstants = false;
+	public bool $allowFullyQualifiedNameForCollidingConstants = false;
 
 	/** @var list|null */
-	private $normalizedSpecialExceptionNames;
+	private ?array $normalizedSpecialExceptionNames = null;
 
 	/** @var list|null */
-	private $normalizedIgnoredNames;
+	private ?array $normalizedIgnoredNames = null;
 
 	/** @var list|null */
-	private $normalizedNamespacesRequiredToUse;
+	private ?array $normalizedNamespacesRequiredToUse = null;
 
 	/**
 	 * @return array
@@ -140,6 +131,12 @@ public function process(File $phpcsFile, $openTagPointer): void
 			return;
 		}
 
+		$namespacePointers = NamespaceHelper::getAllNamespacesPointers($phpcsFile);
+
+		if ($namespacePointers === [] && !$this->allowWhenNoNamespace) {
+			return;
+		}
+
 		$tokens = $phpcsFile->getTokens();
 
 		$references = $this->getReferences($phpcsFile, $openTagPointer);
@@ -149,30 +146,32 @@ public function process(File $phpcsFile, $openTagPointer): void
 			$definedClassesIndex[strtolower($definedClassName)] = NamespaceHelper::resolveClassName(
 				$phpcsFile,
 				$definedClassName,
-				$definedClassPointer
+				$definedClassPointer,
 			);
 		}
-		$definedFunctionsIndex = array_flip(array_map(static function (string $functionName): string {
-			return strtolower($functionName);
-		}, FunctionHelper::getAllFunctionNames($phpcsFile)));
+		$definedFunctionsIndex = array_flip(
+			array_map(
+				static fn (string $functionName): string => strtolower($functionName),
+				FunctionHelper::getAllFunctionNames($phpcsFile),
+			),
+		);
 		$definedConstantsIndex = array_flip(ConstantHelper::getAllNames($phpcsFile));
 
 		$classReferencesIndex = [];
-		$classReferences = array_filter($references, static function (stdClass $reference): bool {
-			return $reference->source === self::SOURCE_CODE && $reference->isClass;
-		});
+		$classReferences = array_filter(
+			$references,
+			static fn (stdClass $reference): bool => $reference->source === self::SOURCE_CODE && $reference->isClass,
+		);
 
 		foreach ($classReferences as $classReference) {
 			$classReferencesIndex[strtolower($classReference->name)] = NamespaceHelper::resolveName(
 				$phpcsFile,
 				$classReference->name,
 				$classReference->type,
-				$classReference->startPointer
+				$classReference->startPointer,
 			);
 		}
 
-		$namespacePointers = NamespaceHelper::getAllNamespacesPointers($phpcsFile);
-
 		$referenceErrors = [];
 
 		foreach ($references as $reference) {
@@ -210,7 +209,7 @@ public function process(File $phpcsFile, $openTagPointer): void
 			$isGlobalFunctionFallback = false;
 			if ($reference->isFunction && $isGlobalFallback) {
 				$isGlobalFunctionFallback = !array_key_exists(strtolower($reference->name), $definedFunctionsIndex) && function_exists(
-					$reference->name
+					$reference->name,
 				);
 			}
 			$isGlobalConstantFallback = false;
@@ -224,7 +223,7 @@ public function process(File $phpcsFile, $openTagPointer): void
 					if (
 						array_key_exists($lowerCasedUnqualifiedClassName, $definedClassesIndex)
 						&& $canonicalName !== NamespaceHelper::normalizeToCanonicalName(
-							$definedClassesIndex[$lowerCasedUnqualifiedClassName]
+							$definedClassesIndex[$lowerCasedUnqualifiedClassName],
 						)
 					) {
 						continue;
@@ -240,7 +239,7 @@ public function process(File $phpcsFile, $openTagPointer): void
 					if (
 						array_key_exists($collidingUseStatementUniqueId, $useStatements)
 						&& $canonicalName !== NamespaceHelper::normalizeToCanonicalName(
-							$useStatements[$collidingUseStatementUniqueId]->getFullyQualifiedTypeName()
+							$useStatements[$collidingUseStatementUniqueId]->getFullyQualifiedTypeName(),
 						)
 					) {
 						continue;
@@ -254,7 +253,7 @@ public function process(File $phpcsFile, $openTagPointer): void
 					if (
 						array_key_exists($collidingUseStatementUniqueId, $useStatements)
 						&& $canonicalName !== NamespaceHelper::normalizeToCanonicalName(
-							$useStatements[$collidingUseStatementUniqueId]->getFullyQualifiedTypeName()
+							$useStatements[$collidingUseStatementUniqueId]->getFullyQualifiedTypeName(),
 						)
 					) {
 						continue;
@@ -267,7 +266,7 @@ public function process(File $phpcsFile, $openTagPointer): void
 					if (
 						array_key_exists($collidingUseStatementUniqueId, $useStatements)
 						&& $canonicalName !== NamespaceHelper::normalizeToCanonicalName(
-							$useStatements[$collidingUseStatementUniqueId]->getFullyQualifiedTypeName()
+							$useStatements[$collidingUseStatementUniqueId]->getFullyQualifiedTypeName(),
 						)
 					) {
 						continue;
@@ -297,12 +296,12 @@ public function process(File $phpcsFile, $openTagPointer): void
 				) {
 					$label = sprintf(
 						$reference->isConstant ? 'Constant %s' : ($reference->isFunction ? 'Function %s()' : 'Class %s'),
-						$name
+						$name,
 					);
 
 					$fix = $phpcsFile->addFixableError(sprintf(
 						'%s should not be referenced via a fully qualified name, but via an unqualified name without the leading \\, because the file does not have a namespace and the type cannot be put in a use statement.',
-						$label
+						$label,
 					), $startPointer, self::CODE_REFERENCE_VIA_FULLY_QUALIFIED_NAME_WITHOUT_NAMESPACE);
 					if ($fix) {
 						$phpcsFile->fixer->beginChangeset();
@@ -312,14 +311,14 @@ public function process(File $phpcsFile, $openTagPointer): void
 								$reference->parsedDocComment,
 								$reference->annotation,
 								$reference->nameNode,
-								new IdentifierTypeNode(substr($reference->name, 1))
+								new IdentifierTypeNode(substr($reference->name, 1)),
 							);
 
 							FixerHelper::change(
 								$phpcsFile,
 								$reference->parsedDocComment->getOpenPointer(),
 								$reference->parsedDocComment->getClosePointer(),
-								$fixedDocComment
+								$fixedDocComment,
 							);
 
 						} elseif ($reference->source === self::SOURCE_ANNOTATION_CONSTANT_FETCH) {
@@ -327,17 +326,21 @@ public function process(File $phpcsFile, $openTagPointer): void
 								$reference->parsedDocComment,
 								$reference->annotation,
 								$reference->constantFetchNode,
-								new ConstFetchNode(substr($reference->name, 1), $reference->constantFetchNode->name)
+								new ConstFetchNode(substr($reference->name, 1), $reference->constantFetchNode->name),
 							);
 
 							FixerHelper::change(
 								$phpcsFile,
 								$reference->parsedDocComment->getOpenPointer(),
 								$reference->parsedDocComment->getClosePointer(),
-								$fixedDocComment
+								$fixedDocComment,
 							);
 						} else {
-							$phpcsFile->fixer->replaceToken($startPointer, substr($tokens[$startPointer]['content'], 1));
+							FixerHelper::replace(
+								$phpcsFile,
+								$startPointer,
+								substr($tokens[$startPointer]['content'], 1),
+							);
 						}
 
 						$phpcsFile->fixer->endChangeset();
@@ -373,7 +376,7 @@ public function process(File $phpcsFile, $openTagPointer): void
 				if (NamespaceHelper::isQualifiedName($name)) {
 					$phpcsFile->addError(sprintf(
 						'Partial use statements are not allowed, but referencing %s found.',
-						$name
+						$name,
 					), $startPointer, self::CODE_PARTIAL_USE);
 				}
 			}
@@ -410,7 +413,7 @@ static function (bool $carry, string $use) use ($canonicalName): bool {
 					$canonicalLastName = strtolower(NamespaceHelper::getLastNamePart($canonicalName));
 					return $useLastName === $canonicalLastName ? false : $carry;
 				},
-				true
+				true,
 			);
 
 			if (
@@ -451,7 +454,7 @@ static function (bool $carry, string $use) use ($canonicalName): bool {
 				$reference->isConstant
 					? 'Constant %s'
 					: ($reference->isFunction ? 'Function %s()' : 'Class %s'),
-				$reference->name
+				$reference->name,
 			);
 			$errorCode = $isGlobalConstantFallback || $isGlobalFunctionFallback
 				? self::CODE_REFERENCE_VIA_FALLBACK_GLOBAL_NAME
@@ -491,9 +494,10 @@ static function (bool $carry, string $use) use ($canonicalName): bool {
 				$nameToReference = $useStatement->getNameAsReferencedInFile();
 				$addUse = false;
 				// Lock the use statement, so it is not modified by other sniffs
-				$phpcsFile->fixer->replaceToken(
+				FixerHelper::replace(
+					$phpcsFile,
 					$useStatement->getPointer(),
-					$phpcsFile->fixer->getTokenContent($useStatement->getPointer())
+					$phpcsFile->fixer->getTokenContent($useStatement->getPointer()),
 				);
 				break;
 			}
@@ -504,7 +508,11 @@ static function (bool $carry, string $use) use ($canonicalName): bool {
 				$useTypeFormatted = $useTypeName !== null ? sprintf('%s ', $useTypeName) : '';
 
 				$phpcsFile->fixer->addNewline($useStatementPlacePointer);
-				$phpcsFile->fixer->addContent($useStatementPlacePointer, sprintf('use %s%s;', $useTypeFormatted, $canonicalName));
+				FixerHelper::add(
+					$phpcsFile,
+					$useStatementPlacePointer,
+					sprintf('use %s%s;', $useTypeFormatted, $canonicalName),
+				);
 
 				$alreadyAddedUses[$reference->type][] = $canonicalName;
 			}
@@ -514,14 +522,14 @@ static function (bool $carry, string $use) use ($canonicalName): bool {
 					$reference->parsedDocComment,
 					$reference->annotation,
 					$reference->nameNode,
-					new IdentifierTypeNode($nameToReference)
+					new IdentifierTypeNode($nameToReference),
 				);
 
 				FixerHelper::change(
 					$phpcsFile,
 					$reference->parsedDocComment->getOpenPointer(),
 					$reference->parsedDocComment->getClosePointer(),
-					$fixedDocComment
+					$fixedDocComment,
 				);
 
 			} elseif ($reference->source === self::SOURCE_ANNOTATION_CONSTANT_FETCH) {
@@ -529,14 +537,14 @@ static function (bool $carry, string $use) use ($canonicalName): bool {
 					$reference->parsedDocComment,
 					$reference->annotation,
 					$reference->constantFetchNode,
-					new ConstFetchNode($nameToReference, $reference->constantFetchNode->name)
+					new ConstFetchNode($nameToReference, $reference->constantFetchNode->name),
 				);
 
 				FixerHelper::change(
 					$phpcsFile,
 					$reference->parsedDocComment->getOpenPointer(),
 					$reference->parsedDocComment->getClosePointer(),
-					$fixedDocComment
+					$fixedDocComment,
 				);
 
 			} elseif ($reference->source === self::SOURCE_ATTRIBUTE) {
@@ -544,7 +552,7 @@ static function (bool $carry, string $use) use ($canonicalName): bool {
 				$fixedAttributeContent = preg_replace(
 					'~(?<=\W)' . preg_quote($reference->name, '~') . '(?=\W)~',
 					$nameToReference,
-					$attributeContent
+					$attributeContent,
 				);
 				FixerHelper::change($phpcsFile, $startPointer, $reference->endPointer, $fixedAttributeContent);
 			} else {
@@ -613,6 +621,14 @@ private function getUseStatementPlacePointer(File $phpcsFile, int $openTagPointe
 		$tokens = $phpcsFile->getTokens();
 
 		$useStatementPlacePointer = $openTagPointer;
+		if (
+			substr($tokens[$openTagPointer]['content'], -1) !== $phpcsFile->eolChar
+			&& $tokens[$openTagPointer + 1]['content'] === $phpcsFile->eolChar
+		) {
+			// @codeCoverageIgnoreStart
+			$useStatementPlacePointer++;
+			// @codeCoverageIgnoreEnd
+		}
 
 		$nonWhitespacePointerAfterOpenTag = TokenHelper::findNextNonWhitespace($phpcsFile, $openTagPointer + 1);
 		if (in_array($tokens[$nonWhitespacePointerAfterOpenTag]['code'], Tokens::$commentTokens, true)) {
@@ -631,7 +647,7 @@ private function getUseStatementPlacePointer(File $phpcsFile, int $openTagPointe
 						T_WHITESPACE,
 						$phpcsFile->eolChar,
 						$newLineAfterComment + 1,
-						$pointerAfterCommentEnd
+						$pointerAfterCommentEnd,
 					) !== null) {
 						$useStatementPlacePointer = $commentEndPointer;
 					}
@@ -649,7 +665,7 @@ private function getUseStatementPlacePointer(File $phpcsFile, int $openTagPointe
 
 	private function isRequiredToBeUsed(string $name): bool
 	{
-		if ($this->namespacesRequiredToUse === null || $this->namespacesRequiredToUse === []) {
+		if ($this->namespacesRequiredToUse === []) {
 			return true;
 		}
 
@@ -717,7 +733,6 @@ private function getReferences(File $phpcsFile, int $openTagPointer): array
 				$annotations = AnnotationHelper::getAnnotations($phpcsFile, $docCommentOpenPointer);
 
 				foreach ($annotations as $annotation) {
-					/** @var list $identifierTypeNodes */
 					$identifierTypeNodes = AnnotationHelper::getAnnotationNodesByType($annotation->getNode(), IdentifierTypeNode::class);
 
 					foreach ($identifierTypeNodes as $typeHintNode) {
@@ -748,7 +763,6 @@ private function getReferences(File $phpcsFile, int $openTagPointer): array
 						$references[] = $reference;
 					}
 
-					/** @var list $constantFetchNodes */
 					$constantFetchNodes = AnnotationHelper::getAnnotationNodesByType($annotation->getNode(), ConstFetchNode::class);
 
 					foreach ($constantFetchNodes as $constantFetchNode) {
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UnusedUsesSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UnusedUsesSniff.php
index 9dfb68f40..fbc937569 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UnusedUsesSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UnusedUsesSniff.php
@@ -40,20 +40,19 @@ class UnusedUsesSniff implements Sniff
 
 	public const CODE_UNUSED_USE = 'UnusedUse';
 
-	/** @var bool */
-	public $searchAnnotations = false;
+	public bool $searchAnnotations = false;
 
 	/** @var list */
-	public $ignoredAnnotationNames = [];
+	public array $ignoredAnnotationNames = [];
 
 	/** @var list */
-	public $ignoredAnnotations = [];
+	public array $ignoredAnnotations = [];
 
 	/** @var list|null */
-	private $normalizedIgnoredAnnotationNames;
+	private ?array $normalizedIgnoredAnnotationNames = null;
 
 	/** @var list|null */
-	private $normalizedIgnoredAnnotations;
+	private ?array $normalizedIgnoredAnnotations = null;
 
 	/**
 	 * @return array
@@ -129,7 +128,7 @@ public function process(File $phpcsFile, $openTagPointer): void
 				$pointerBeforeUseStatements = $this->firstPointerBefore(
 					$docCommentOpenPointer - 1,
 					$pointersBeforeUseStatements,
-					$startPointer
+					$startPointer,
 				);
 
 				if (!array_key_exists($pointerBeforeUseStatements, $fileUnusedNames)) {
@@ -160,17 +159,14 @@ public function process(File $phpcsFile, $openTagPointer): void
 							$contentsToCheck[] = $annotation->getName();
 							$contentsToCheck[] = $annotation->getValue()->value;
 						} else {
-							/** @var list $identifierTypeNodes */
 							$identifierTypeNodes = AnnotationHelper::getAnnotationNodesByType(
 								$annotation->getNode(),
-								IdentifierTypeNode::class
+								IdentifierTypeNode::class,
 							);
-							/** @var list $doctrineAnnotations */
 							$doctrineAnnotations = AnnotationHelper::getAnnotationNodesByType(
 								$annotation->getNode(),
-								DoctrineAnnotation::class
+								DoctrineAnnotation::class,
 							);
-							/** @var list $constFetchNodes */
 							$constFetchNodes = AnnotationHelper::getAnnotationNodesByType($annotation->getNode(), ConstFetchNode::class);
 
 							$contentsToCheck = array_filter(array_merge(
@@ -193,16 +189,17 @@ public function process(File $phpcsFile, $openTagPointer): void
 
 									return $doctrineAnnotation->name;
 								}, $doctrineAnnotations),
-								array_map(static function (ConstFetchNode $constFetchNode): string {
-									return $constFetchNode->className;
-								}, $constFetchNodes)
-							));
+								array_map(
+									static fn (ConstFetchNode $constFetchNode): string => $constFetchNode->className,
+									$constFetchNodes,
+								),
+							), static fn (?string $content): bool => $content !== null);
 						}
 
 						foreach ($contentsToCheck as $contentToCheck) {
 							if (preg_match(
 								'~(?<=^|[^a-z\\\\])(' . preg_quote($nameAsReferencedInFile, '~') . ')(?=\\s|::|\\\\|\||\[|$)~im',
-								$contentToCheck
+								$contentToCheck,
 							) === 0) {
 								continue;
 							}
@@ -228,7 +225,7 @@ public function process(File $phpcsFile, $openTagPointer): void
 				}
 				$fix = $phpcsFile->addFixableError(sprintf(
 					'Type %s is not used in this file.',
-					$fullName
+					$fullName,
 				), $unusedUse->getPointer(), self::CODE_UNUSED_USE);
 				if (!$fix) {
 					continue;
@@ -258,7 +255,7 @@ private function getIgnoredAnnotationNames(): array
 					'@throws',
 					'@property',
 					'@method',
-				]
+				],
 			);
 		}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UseDoesNotStartWithBackslashSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UseDoesNotStartWithBackslashSniff.php
index 2aa181d5a..2022ec446 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UseDoesNotStartWithBackslashSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UseDoesNotStartWithBackslashSniff.php
@@ -4,6 +4,7 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\NamespaceHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use SlevomatCodingStandard\Helpers\UseStatementHelper;
@@ -32,10 +33,7 @@ public function register(): array
 	 */
 	public function process(File $phpcsFile, $usePointer): void
 	{
-		if (
-			UseStatementHelper::isAnonymousFunctionUse($phpcsFile, $usePointer)
-			|| UseStatementHelper::isTraitUse($phpcsFile, $usePointer)
-		) {
+		if (!UseStatementHelper::isImportUse($phpcsFile, $usePointer)) {
 			return;
 		}
 
@@ -45,7 +43,7 @@ public function process(File $phpcsFile, $usePointer): void
 		$nextTokenPointer = TokenHelper::findNextEffective($phpcsFile, $usePointer + 1);
 
 		if (
-			in_array($tokens[$nextTokenPointer]['code'], TokenHelper::getOnlyNameTokenCodes(), true)
+			in_array($tokens[$nextTokenPointer]['code'], TokenHelper::ONLY_NAME_TOKEN_CODES, true)
 			&& (
 				$tokens[$nextTokenPointer]['content'] === 'function'
 				|| $tokens[$nextTokenPointer]['content'] === 'const'
@@ -62,7 +60,7 @@ public function process(File $phpcsFile, $usePointer): void
 		$fix = $phpcsFile->addFixableError(
 			'Use statement cannot start with a backslash.',
 			$nextTokenPointer,
-			self::CODE_STARTS_WITH_BACKSLASH
+			self::CODE_STARTS_WITH_BACKSLASH,
 		);
 
 		if (!$fix) {
@@ -70,7 +68,11 @@ public function process(File $phpcsFile, $usePointer): void
 		}
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->replaceToken($nextTokenPointer, ltrim($tokens[$nextTokenPointer]['content'], '\\'));
+		FixerHelper::replace(
+			$phpcsFile,
+			$nextTokenPointer,
+			ltrim($tokens[$nextTokenPointer]['content'], '\\'),
+		);
 		$phpcsFile->fixer->endChangeset();
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UseFromSameNamespaceSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UseFromSameNamespaceSniff.php
index fcc0675dc..90519f869 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UseFromSameNamespaceSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UseFromSameNamespaceSniff.php
@@ -37,10 +37,7 @@ public function register(): array
 	 */
 	public function process(File $phpcsFile, $usePointer): void
 	{
-		if (
-			UseStatementHelper::isAnonymousFunctionUse($phpcsFile, $usePointer)
-			|| UseStatementHelper::isTraitUse($phpcsFile, $usePointer)
-		) {
+		if (!UseStatementHelper::isImportUse($phpcsFile, $usePointer)) {
 			return;
 		}
 
@@ -70,7 +67,7 @@ public function process(File $phpcsFile, $usePointer): void
 
 		$fix = $phpcsFile->addFixableError(sprintf(
 			'Use %s is from the same namespace – that is prohibited.',
-			$usedTypeName
+			$usedTypeName,
 		), $usePointer, self::CODE_USE_FROM_SAME_NAMESPACE);
 		if (!$fix) {
 			return;
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UseOnlyWhitelistedNamespacesSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UseOnlyWhitelistedNamespacesSniff.php
index f8f7508d6..97161c72e 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UseOnlyWhitelistedNamespacesSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UseOnlyWhitelistedNamespacesSniff.php
@@ -15,14 +15,13 @@ class UseOnlyWhitelistedNamespacesSniff implements Sniff
 
 	public const CODE_NON_FULLY_QUALIFIED = 'NonFullyQualified';
 
-	/** @var bool */
-	public $allowUseFromRootNamespace = false;
+	public bool $allowUseFromRootNamespace = false;
 
 	/** @var list */
-	public $namespacesRequiredToUse = [];
+	public array $namespacesRequiredToUse = [];
 
 	/** @var list|null */
-	private $normalizedNamespacesRequiredToUse;
+	private ?array $normalizedNamespacesRequiredToUse = null;
 
 	/**
 	 * @return array
@@ -40,10 +39,7 @@ public function register(): array
 	 */
 	public function process(File $phpcsFile, $usePointer): void
 	{
-		if (
-			UseStatementHelper::isAnonymousFunctionUse($phpcsFile, $usePointer)
-			|| UseStatementHelper::isTraitUse($phpcsFile, $usePointer)
-		) {
+		if (!UseStatementHelper::isImportUse($phpcsFile, $usePointer)) {
 			return;
 		}
 
@@ -62,7 +58,7 @@ public function process(File $phpcsFile, $usePointer): void
 
 		$phpcsFile->addError(sprintf(
 			'Type %s should not be used, but referenced via a fully qualified name.',
-			$className
+			$className,
 		), $usePointer, self::CODE_NON_FULLY_QUALIFIED);
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UseSpacingSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UseSpacingSniff.php
index ca0808a47..96069952e 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UseSpacingSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UseSpacingSniff.php
@@ -28,14 +28,11 @@ class UseSpacingSniff implements Sniff
 	public const CODE_INCORRECT_LINES_COUNT_BETWEEN_DIFFERENT_TYPES_OF_USE = 'IncorrectLinesCountBetweenDifferentTypeOfUse';
 	public const CODE_INCORRECT_LINES_COUNT_AFTER_LAST_USE = 'IncorrectLinesCountAfterLastUse';
 
-	/** @var int */
-	public $linesCountBeforeFirstUse = 1;
+	public int $linesCountBeforeFirstUse = 1;
 
-	/** @var int */
-	public $linesCountBetweenUseTypes = 0;
+	public int $linesCountBetweenUseTypes = 0;
 
-	/** @var int */
-	public $linesCountAfterLastUse = 1;
+	public int $linesCountAfterLastUse = 1;
 
 	/**
 	 * @return array
@@ -107,10 +104,10 @@ private function checkLinesBeforeFirstUse(File $phpcsFile, UseStatement $firstUs
 				'Expected %d line%s before first use statement, found %d.',
 				$this->linesCountBeforeFirstUse,
 				$this->linesCountBeforeFirstUse === 1 ? '' : 's',
-				$actualLinesCountBeforeFirstUse
+				$actualLinesCountBeforeFirstUse,
 			),
 			$firstUse->getPointer(),
-			self::CODE_INCORRECT_LINES_COUNT_BEFORE_FIRST_USE
+			self::CODE_INCORRECT_LINES_COUNT_BEFORE_FIRST_USE,
 		);
 
 		if (!$fix) {
@@ -120,7 +117,7 @@ private function checkLinesBeforeFirstUse(File $phpcsFile, UseStatement $firstUs
 		$phpcsFile->fixer->beginChangeset();
 
 		if ($tokens[$pointerBeforeFirstUse]['code'] === T_OPEN_TAG) {
-			$phpcsFile->fixer->replaceToken($pointerBeforeFirstUse, 'linesCountAfterLastUse,
 				$this->linesCountAfterLastUse === 1 ? '' : 's',
-				$actualLinesCountAfterLastUse
+				$actualLinesCountAfterLastUse,
 			),
 			$lastUse->getPointer(),
-			self::CODE_INCORRECT_LINES_COUNT_AFTER_LAST_USE
+			self::CODE_INCORRECT_LINES_COUNT_AFTER_LAST_USE,
 		);
 
 		if (!$fix) {
@@ -241,10 +238,10 @@ private function checkLinesBetweenSameTypesOfUse(File $phpcsFile, array $useStat
 			$fix = $phpcsFile->addFixableError(
 				sprintf(
 					'Expected 0 lines between same types of use statement, found %d.',
-					$actualLinesCountAfterPreviousUse
+					$actualLinesCountAfterPreviousUse,
 				),
 				$use->getPointer(),
-				self::CODE_INCORRECT_LINES_COUNT_BETWEEN_SAME_TYPES_OF_USE
+				self::CODE_INCORRECT_LINES_COUNT_BETWEEN_SAME_TYPES_OF_USE,
 			);
 
 			if (!$fix) {
@@ -313,10 +310,10 @@ private function checkLinesBetweenDifferentTypesOfUse(File $phpcsFile, array $us
 					'Expected %d line%s between different types of use statement, found %d.',
 					$this->linesCountBetweenUseTypes,
 					$this->linesCountBetweenUseTypes === 1 ? '' : 's',
-					$actualLinesCountAfterPreviousUse
+					$actualLinesCountAfterPreviousUse,
 				),
 				$use->getPointer(),
-				self::CODE_INCORRECT_LINES_COUNT_BETWEEN_DIFFERENT_TYPES_OF_USE
+				self::CODE_INCORRECT_LINES_COUNT_BETWEEN_DIFFERENT_TYPES_OF_USE,
 			);
 
 			if (!$fix) {
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UselessAliasSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UselessAliasSniff.php
index 140e3342e..b6866bd0e 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UselessAliasSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Namespaces/UselessAliasSniff.php
@@ -59,7 +59,7 @@ public function process(File $phpcsFile, $openTagPointer): void
 				$fix = $phpcsFile->addFixableError(
 					sprintf('Useless alias "%s" for use of "%s".', $useStatement->getAlias(), $useStatement->getFullyQualifiedTypeName()),
 					$useStatement->getPointer(),
-					self::CODE_USELESS_ALIAS
+					self::CODE_USELESS_ALIAS,
 				);
 
 				if (!$fix) {
@@ -67,7 +67,7 @@ public function process(File $phpcsFile, $openTagPointer): void
 				}
 
 				$asPointer = TokenHelper::findNext($phpcsFile, T_AS, $useStatement->getPointer() + 1);
-				$nameEndPointer = TokenHelper::findPrevious($phpcsFile, TokenHelper::getOnlyNameTokenCodes(), $asPointer - 1);
+				$nameEndPointer = TokenHelper::findPrevious($phpcsFile, TokenHelper::ONLY_NAME_TOKEN_CODES, $asPointer - 1);
 				$useSemicolonPointer = TokenHelper::findNext($phpcsFile, T_SEMICOLON, $asPointer + 1);
 
 				$phpcsFile->fixer->beginChangeset();
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Numbers/DisallowNumericLiteralSeparatorSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Numbers/DisallowNumericLiteralSeparatorSniff.php
index 76c0493bf..385eca554 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Numbers/DisallowNumericLiteralSeparatorSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Numbers/DisallowNumericLiteralSeparatorSniff.php
@@ -4,6 +4,7 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use function str_replace;
 use function strpos;
 use const T_DNUMBER;
@@ -40,7 +41,7 @@ public function process(File $phpcsFile, $numberPointer): void
 		$fix = $phpcsFile->addFixableError(
 			'Use of numeric literal separator is disallowed.',
 			$numberPointer,
-			self::CODE_DISALLOWED_NUMERIC_LITERAL_SEPARATOR
+			self::CODE_DISALLOWED_NUMERIC_LITERAL_SEPARATOR,
 		);
 
 		if (!$fix) {
@@ -48,7 +49,11 @@ public function process(File $phpcsFile, $numberPointer): void
 		}
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->replaceToken($numberPointer, str_replace('_', '', $tokens[$numberPointer]['content']));
+		FixerHelper::replace(
+			$phpcsFile,
+			$numberPointer,
+			str_replace('_', '', $tokens[$numberPointer]['content']),
+		);
 		$phpcsFile->fixer->endChangeset();
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Numbers/RequireNumericLiteralSeparatorSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Numbers/RequireNumericLiteralSeparatorSniff.php
index 92df96ea6..310908d96 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Numbers/RequireNumericLiteralSeparatorSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Numbers/RequireNumericLiteralSeparatorSniff.php
@@ -15,17 +15,13 @@ class RequireNumericLiteralSeparatorSniff implements Sniff
 
 	public const CODE_REQUIRED_NUMERIC_LITERAL_SEPARATOR = 'RequiredNumericLiteralSeparator';
 
-	/** @var bool|null */
-	public $enable = null;
+	public ?bool $enable = null;
 
-	/** @var int */
-	public $minDigitsBeforeDecimalPoint = 4;
+	public int $minDigitsBeforeDecimalPoint = 4;
 
-	/** @var int */
-	public $minDigitsAfterDecimalPoint = 4;
+	public int $minDigitsAfterDecimalPoint = 4;
 
-	/** @var bool */
-	public $ignoreOctalNumbers = true;
+	public bool $ignoreOctalNumbers = true;
 
 	/**
 	 * @return array
@@ -75,7 +71,7 @@ public function process(File $phpcsFile, $numberPointer): void
 		$phpcsFile->addError(
 			'Use of numeric literal separator is required.',
 			$numberPointer,
-			self::CODE_REQUIRED_NUMERIC_LITERAL_SEPARATOR
+			self::CODE_REQUIRED_NUMERIC_LITERAL_SEPARATOR,
 		);
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Operators/DisallowEqualOperatorsSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Operators/DisallowEqualOperatorsSniff.php
index 11acc895a..4604c3b0a 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Operators/DisallowEqualOperatorsSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Operators/DisallowEqualOperatorsSniff.php
@@ -4,6 +4,7 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use function sprintf;
 use const T_IS_EQUAL;
 use const T_IS_NOT_EQUAL;
@@ -37,21 +38,21 @@ public function process(File $phpcsFile, $operatorPointer): void
 			$fix = $phpcsFile->addFixableError(
 				'Operator == is disallowed, use === instead.',
 				$operatorPointer,
-				self::CODE_DISALLOWED_EQUAL_OPERATOR
+				self::CODE_DISALLOWED_EQUAL_OPERATOR,
 			);
 			if ($fix) {
 				$phpcsFile->fixer->beginChangeset();
-				$phpcsFile->fixer->replaceToken($operatorPointer, '===');
+				FixerHelper::replace($phpcsFile, $operatorPointer, '===');
 				$phpcsFile->fixer->endChangeset();
 			}
 		} else {
 			$fix = $phpcsFile->addFixableError(sprintf(
 				'Operator %s is disallowed, use !== instead.',
-				$tokens[$operatorPointer]['content']
+				$tokens[$operatorPointer]['content'],
 			), $operatorPointer, self::CODE_DISALLOWED_NOT_EQUAL_OPERATOR);
 			if ($fix) {
 				$phpcsFile->fixer->beginChangeset();
-				$phpcsFile->fixer->replaceToken($operatorPointer, '!==');
+				FixerHelper::replace($phpcsFile, $operatorPointer, '!==');
 				$phpcsFile->fixer->endChangeset();
 			}
 		}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Operators/NegationOperatorSpacingSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Operators/NegationOperatorSpacingSniff.php
index 3da9174b5..00ca0e879 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Operators/NegationOperatorSpacingSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Operators/NegationOperatorSpacingSniff.php
@@ -4,10 +4,10 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\IdentificatorHelper;
 use SlevomatCodingStandard\Helpers\SniffSettingsHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
-use function array_merge;
 use function in_array;
 use function sprintf;
 use function strlen;
@@ -36,8 +36,7 @@ class NegationOperatorSpacingSniff implements Sniff
 
 	public const CODE_INVALID_SPACE_AFTER_MINUS = 'InvalidSpaceAfterMinus';
 
-	/** @var int */
-	public $spacesCount = 0;
+	public int $spacesCount = 0;
 
 	/**
 	 * @return array
@@ -59,28 +58,26 @@ public function process(File $phpcsFile, $pointer): void
 
 		$previousEffective = TokenHelper::findPreviousEffective($phpcsFile, $pointer - 1);
 
-		$possibleOperandTypes = array_merge(
-			TokenHelper::getOnlyNameTokenCodes(),
-			[
-				T_CONSTANT_ENCAPSED_STRING,
-				T_CLASS_C,
-				T_CLOSE_PARENTHESIS,
-				T_CLOSE_SHORT_ARRAY,
-				T_CLOSE_SQUARE_BRACKET,
-				T_DIR,
-				T_DNUMBER,
-				T_ENCAPSED_AND_WHITESPACE,
-				T_FILE,
-				T_FUNC_C,
-				T_LINE,
-				T_LNUMBER,
-				T_METHOD_C,
-				T_NS_C,
-				T_NUM_STRING,
-				T_TRAIT_C,
-				T_VARIABLE,
-			]
-		);
+		$possibleOperandTypes = [
+			...TokenHelper::ONLY_NAME_TOKEN_CODES,
+			T_CONSTANT_ENCAPSED_STRING,
+			T_CLASS_C,
+			T_CLOSE_PARENTHESIS,
+			T_CLOSE_SHORT_ARRAY,
+			T_CLOSE_SQUARE_BRACKET,
+			T_DIR,
+			T_DNUMBER,
+			T_ENCAPSED_AND_WHITESPACE,
+			T_FILE,
+			T_FUNC_C,
+			T_LINE,
+			T_LNUMBER,
+			T_METHOD_C,
+			T_NS_C,
+			T_NUM_STRING,
+			T_TRAIT_C,
+			T_VARIABLE,
+		];
 
 		if (in_array($tokens[$previousEffective]['code'], $possibleOperandTypes, true)) {
 			return;
@@ -103,10 +100,10 @@ public function process(File $phpcsFile, $pointer): void
 				'Expected exactly %d space after "%s", %d found.',
 				$this->spacesCount,
 				$tokens[$pointer]['content'],
-				$numberOfSpaces
+				$numberOfSpaces,
 			),
 			$pointer,
-			self::CODE_INVALID_SPACE_AFTER_MINUS
+			self::CODE_INVALID_SPACE_AFTER_MINUS,
 		);
 
 		if (!$fix) {
@@ -114,12 +111,12 @@ public function process(File $phpcsFile, $pointer): void
 		}
 
 		if ($this->spacesCount > $numberOfSpaces) {
-			$phpcsFile->fixer->addContent($pointer, ' ');
+			FixerHelper::add($phpcsFile, $pointer, ' ');
 
 			return;
 		}
 
-		$phpcsFile->fixer->replaceToken($whitespacePointer, '');
+		FixerHelper::replace($phpcsFile, $whitespacePointer, '');
 	}
 
 }
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Operators/RequireCombinedAssignmentOperatorSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Operators/RequireCombinedAssignmentOperatorSniff.php
index 7a3406b34..475864dbf 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Operators/RequireCombinedAssignmentOperatorSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Operators/RequireCombinedAssignmentOperatorSniff.php
@@ -92,7 +92,7 @@ public function process(File $phpcsFile, $equalPointer): void
 			if (in_array(
 				$tokens[$pointerAfterOperator]['code'],
 				[T_CONSTANT_ENCAPSED_STRING, T_DOUBLE_QUOTED_STRING, T_START_HEREDOC, T_START_NOWDOC],
-				true
+				true,
 			)) {
 				return;
 			}
@@ -124,7 +124,7 @@ public function process(File $phpcsFile, $equalPointer): void
 		$errorMessage = sprintf(
 			'Use "%s" operator instead of "=" and "%s".',
 			$operators[$tokens[$operatorPointer]['code']],
-			$tokens[$operatorPointer]['content']
+			$tokens[$operatorPointer]['content'],
 		);
 
 		if (!$isFixable) {
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Operators/RequireOnlyStandaloneIncrementAndDecrementOperatorsSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Operators/RequireOnlyStandaloneIncrementAndDecrementOperatorsSniff.php
index 9b66a3c28..fb3958c34 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Operators/RequireOnlyStandaloneIncrementAndDecrementOperatorsSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Operators/RequireOnlyStandaloneIncrementAndDecrementOperatorsSniff.php
@@ -97,7 +97,7 @@ private function isStandalone(File $phpcsFile, int $instructionStartPointer, int
 		if (!in_array(
 			$tokens[$pointerBeforeInstructionStart]['code'],
 			[T_SEMICOLON, T_COLON, T_OPEN_CURLY_BRACKET, T_CLOSE_CURLY_BRACKET, T_OPEN_TAG],
-			true
+			true,
 		)) {
 			return false;
 		}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Operators/SpreadOperatorSpacingSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Operators/SpreadOperatorSpacingSniff.php
index 27548e711..e149e4232 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Operators/SpreadOperatorSpacingSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Operators/SpreadOperatorSpacingSniff.php
@@ -17,8 +17,7 @@ class SpreadOperatorSpacingSniff implements Sniff
 
 	public const CODE_INCORRECT_SPACES_AFTER_OPERATOR = 'IncorrectSpacesAfterOperator';
 
-	/** @var int */
-	public $spacesCountAfterOperator = 0;
+	public int $spacesCountAfterOperator = 0;
 
 	/**
 	 * @return array
@@ -51,7 +50,7 @@ public function process(File $phpcsFile, $spreadOperatorPointer): void
 			: sprintf(
 				'There must be exactly %d whitespace%s after spread operator.',
 				$this->spacesCountAfterOperator,
-				$this->spacesCountAfterOperator !== 1 ? 's' : ''
+				$this->spacesCountAfterOperator !== 1 ? 's' : '',
 			);
 
 		$fix = $phpcsFile->addFixableError($errorMessage, $spreadOperatorPointer, self::CODE_INCORRECT_SPACES_AFTER_OPERATOR);
@@ -62,7 +61,11 @@ public function process(File $phpcsFile, $spreadOperatorPointer): void
 
 		$phpcsFile->fixer->beginChangeset();
 
-		$phpcsFile->fixer->addContent($spreadOperatorPointer, str_repeat(' ', $this->spacesCountAfterOperator));
+		FixerHelper::add(
+			$phpcsFile,
+			$spreadOperatorPointer,
+			str_repeat(' ', $this->spacesCountAfterOperator),
+		);
 		FixerHelper::removeBetween($phpcsFile, $spreadOperatorPointer, $pointerAfterWhitespace);
 
 		$phpcsFile->fixer->endChangeset();
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/DisallowDirectMagicInvokeCallSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/DisallowDirectMagicInvokeCallSniff.php
index f6db2f3ab..28100a5b0 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/DisallowDirectMagicInvokeCallSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/DisallowDirectMagicInvokeCallSniff.php
@@ -51,7 +51,7 @@ public function process(File $phpcsFile, $stringPointer): void
 		$fix = $phpcsFile->addFixableError(
 			'Direct call of __invoke() is disallowed.',
 			$stringPointer,
-			self::CODE_DISALLOWED_DIRECT_MAGIC_INVOKE_CALL
+			self::CODE_DISALLOWED_DIRECT_MAGIC_INVOKE_CALL,
 		);
 		if (!$fix) {
 			return;
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/DisallowReferenceSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/DisallowReferenceSniff.php
index 31340396f..2f4eaef95 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/DisallowReferenceSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/DisallowReferenceSniff.php
@@ -44,7 +44,7 @@ public function process(File $phpcsFile, $referencePointer): void
 		$tokens = $phpcsFile->getTokens();
 
 		$previousPointer = TokenHelper::findPreviousEffective($phpcsFile, $referencePointer - 1);
-		if (in_array($tokens[$previousPointer]['code'], TokenHelper::$functionTokenCodes, true)) {
+		if (in_array($tokens[$previousPointer]['code'], TokenHelper::FUNCTION_TOKEN_CODES, true)) {
 			$phpcsFile->addError('Returning reference is disallowed.', $referencePointer, self::CODE_DISALLOWED_RETURNING_REFERENCE);
 			return;
 		}
@@ -56,11 +56,11 @@ public function process(File $phpcsFile, $referencePointer): void
 		) {
 			if (array_key_exists('parenthesis_owner', $tokens[$previousParenthesisOpenerPointer])) {
 				$parenthesisOwnerPointer = $tokens[$previousParenthesisOpenerPointer]['parenthesis_owner'];
-				if (in_array($tokens[$parenthesisOwnerPointer]['code'], TokenHelper::$functionTokenCodes, true)) {
+				if (in_array($tokens[$parenthesisOwnerPointer]['code'], TokenHelper::FUNCTION_TOKEN_CODES, true)) {
 					$phpcsFile->addError(
 						'Passing by reference is disallowed.',
 						$referencePointer,
-						self::CODE_DISALLOWED_PASSING_BY_REFERENCE
+						self::CODE_DISALLOWED_PASSING_BY_REFERENCE,
 					);
 					return;
 				}
@@ -74,7 +74,7 @@ public function process(File $phpcsFile, $referencePointer): void
 				$phpcsFile->addError(
 					'Inheriting variable by reference is disallowed.',
 					$referencePointer,
-					self::CODE_DISALLOWED_INHERITING_VARIABLE_BY_REFERENCE
+					self::CODE_DISALLOWED_INHERITING_VARIABLE_BY_REFERENCE,
 				);
 				return;
 			}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/ForbiddenClassesSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/ForbiddenClassesSniff.php
index 165840ed7..50f345d03 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/ForbiddenClassesSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/ForbiddenClassesSniff.php
@@ -10,7 +10,6 @@
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use SlevomatCodingStandard\Helpers\UseStatementHelper;
 use function array_key_exists;
-use function array_merge;
 use function array_pop;
 use function count;
 use function in_array;
@@ -38,19 +37,19 @@ class ForbiddenClassesSniff implements Sniff
 	public const CODE_FORBIDDEN_TRAIT = 'ForbiddenTrait';
 
 	/** @var array */
-	public $forbiddenClasses = [];
+	public array $forbiddenClasses = [];
 
 	/** @var array */
-	public $forbiddenExtends = [];
+	public array $forbiddenExtends = [];
 
 	/** @var array */
-	public $forbiddenInterfaces = [];
+	public array $forbiddenInterfaces = [];
 
 	/** @var array */
-	public $forbiddenTraits = [];
+	public array $forbiddenTraits = [];
 
 	/** @var list */
-	private static $keywordReferences = ['self', 'parent', 'static'];
+	private static array $keywordReferences = ['self', 'parent', 'static'];
 
 	/**
 	 * @return array
@@ -91,7 +90,7 @@ public function process(File $phpcsFile, $tokenPointer): void
 	{
 		$tokens = $phpcsFile->getTokens();
 		$token = $tokens[$tokenPointer];
-		$nameTokens = array_merge(TokenHelper::getNameTokenCodes(), TokenHelper::$ineffectiveTokenCodes);
+		$nameTokens = [...TokenHelper::NAME_TOKEN_CODES, ...TokenHelper::INEFFECTIVE_TOKEN_CODES];
 
 		if (
 			$token['code'] === T_IMPLEMENTS
@@ -103,7 +102,7 @@ public function process(File $phpcsFile, $tokenPointer): void
 			$endTokenPointer = TokenHelper::findNext(
 				$phpcsFile,
 				[T_SEMICOLON, T_OPEN_CURLY_BRACKET],
-				$tokenPointer
+				$tokenPointer,
 			);
 			$references = $this->getAllReferences($phpcsFile, $tokenPointer, $endTokenPointer);
 
@@ -116,7 +115,7 @@ public function process(File $phpcsFile, $tokenPointer): void
 					$tokenPointer,
 					$references,
 					$this->forbiddenTraits,
-					$tokens[$endTokenPointer]['code'] !== T_OPEN_CURLY_BRACKET
+					$tokens[$endTokenPointer]['code'] !== T_OPEN_CURLY_BRACKET,
 				);
 			}
 		} elseif (in_array($token['code'], [T_NEW, T_EXTENDS], true)) {
@@ -127,7 +126,7 @@ public function process(File $phpcsFile, $tokenPointer): void
 				$phpcsFile,
 				$tokenPointer,
 				$references,
-				$token['code'] === T_NEW ? $this->forbiddenClasses : $this->forbiddenExtends
+				$token['code'] === T_NEW ? $this->forbiddenClasses : $this->forbiddenExtends,
 			);
 		} elseif ($token['code'] === T_DOUBLE_COLON && !$this->isTraitsConflictResolutionToken($token)) {
 			$startTokenPointer = TokenHelper::findPreviousExcluding($phpcsFile, $nameTokens, $tokenPointer - 1);
@@ -170,7 +169,7 @@ private function checkReferences(
 				$phpcsFile->addError(
 					sprintf('Usage of %s %s is forbidden.', $reference['fullyQualifiedName'], $nameType),
 					$reference['startPointer'],
-					$code
+					$code,
 				);
 			} elseif (!$isFixable) {
 				$phpcsFile->addError(
@@ -178,10 +177,10 @@ private function checkReferences(
 						'Usage of %s %s is forbidden, use %s instead.',
 						$reference['fullyQualifiedName'],
 						$nameType,
-						$alternative
+						$alternative,
 					),
 					$reference['startPointer'],
-					$code
+					$code,
 				);
 			} else {
 				$fix = $phpcsFile->addFixableError(
@@ -189,10 +188,10 @@ private function checkReferences(
 						'Usage of %s %s is forbidden, use %s instead.',
 						$reference['fullyQualifiedName'],
 						$nameType,
-						$alternative
+						$alternative,
 					),
 					$reference['startPointer'],
-					$code
+					$code,
 				);
 				if (!$fix) {
 					continue;
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/OptimizedFunctionsWithoutUnpackingSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/OptimizedFunctionsWithoutUnpackingSniff.php
index cc304bbbe..f6232614d 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/OptimizedFunctionsWithoutUnpackingSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/OptimizedFunctionsWithoutUnpackingSniff.php
@@ -29,7 +29,7 @@ class OptimizedFunctionsWithoutUnpackingSniff implements Sniff
 	 */
 	public function register(): array
 	{
-		return TokenHelper::getOnlyNameTokenCodes();
+		return TokenHelper::ONLY_NAME_TOKEN_CODES;
 	}
 
 	/**
@@ -50,7 +50,7 @@ public function process(File $phpcsFile, $pointer): void
 			return;
 		}
 		/** @var int $tokenBeforeInvocationPointer */
-		$tokenBeforeInvocationPointer = TokenHelper::findPreviousExcluding($phpcsFile, TokenHelper::getNameTokenCodes(), $pointer);
+		$tokenBeforeInvocationPointer = TokenHelper::findPreviousExcluding($phpcsFile, TokenHelper::NAME_TOKEN_CODES, $pointer);
 		$invokedName = TokenHelper::getContent($phpcsFile, $tokenBeforeInvocationPointer + 1, $pointer);
 		$useName = sprintf('function %s', $invokedName);
 
@@ -92,7 +92,7 @@ public function process(File $phpcsFile, $pointer): void
 		$nextTokenAfterSeparatorPointer = TokenHelper::findNextEffective(
 			$phpcsFile,
 			$lastArgumentSeparatorPointer + 1,
-			$closeBracketPointer
+			$closeBracketPointer,
 		);
 
 		if ($tokens[$nextTokenAfterSeparatorPointer]['code'] !== T_ELLIPSIS) {
@@ -107,7 +107,7 @@ public function process(File $phpcsFile, $pointer): void
 		$phpcsFile->addError(
 			sprintf('Function %s is specialized by PHP and should not use argument unpacking.', $invokedName),
 			$nextTokenAfterSeparatorPointer,
-			self::CODE_UNPACKING_USED
+			self::CODE_UNPACKING_USED,
 		);
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/ReferenceSpacingSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/ReferenceSpacingSniff.php
index a3478c9b9..739bf38dc 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/ReferenceSpacingSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/ReferenceSpacingSniff.php
@@ -27,8 +27,7 @@ class ReferenceSpacingSniff implements Sniff
 
 	public const CODE_INCORRECT_SPACES_AFTER_REFERENCE = 'IncorrectSpacesAfterReference';
 
-	/** @var int */
-	public $spacesCountAfterReference = 0;
+	public int $spacesCountAfterReference = 0;
 
 	/**
 	 * @return array
@@ -67,7 +66,7 @@ public function process(File $phpcsFile, $referencePointer): void
 			: sprintf(
 				'There must be exactly %d whitespace%s after reference.',
 				$this->spacesCountAfterReference,
-				$this->spacesCountAfterReference !== 1 ? 's' : ''
+				$this->spacesCountAfterReference !== 1 ? 's' : '',
 			);
 
 		$fix = $phpcsFile->addFixableError($errorMessage, $referencePointer, self::CODE_INCORRECT_SPACES_AFTER_REFERENCE);
@@ -78,7 +77,7 @@ public function process(File $phpcsFile, $referencePointer): void
 
 		$phpcsFile->fixer->beginChangeset();
 
-		$phpcsFile->fixer->addContent($referencePointer, str_repeat(' ', $this->spacesCountAfterReference));
+		FixerHelper::add($phpcsFile, $referencePointer, str_repeat(' ', $this->spacesCountAfterReference));
 
 		FixerHelper::removeBetween($phpcsFile, $referencePointer, $pointerAfterWhitespace);
 
@@ -90,7 +89,7 @@ private function isReference(File $phpcsFile, int $referencePointer): bool
 		$tokens = $phpcsFile->getTokens();
 
 		$previousPointer = TokenHelper::findPreviousEffective($phpcsFile, $referencePointer - 1);
-		if (in_array($tokens[$previousPointer]['code'], TokenHelper::$functionTokenCodes, true)) {
+		if (in_array($tokens[$previousPointer]['code'], TokenHelper::FUNCTION_TOKEN_CODES, true)) {
 			return true;
 		}
 
@@ -101,7 +100,7 @@ private function isReference(File $phpcsFile, int $referencePointer): bool
 		) {
 			if (array_key_exists('parenthesis_owner', $tokens[$previousParenthesisOpenerPointer])) {
 				$parenthesisOwnerPointer = $tokens[$previousParenthesisOpenerPointer]['parenthesis_owner'];
-				if (in_array($tokens[$parenthesisOwnerPointer]['code'], TokenHelper::$functionTokenCodes, true)) {
+				if (in_array($tokens[$parenthesisOwnerPointer]['code'], TokenHelper::FUNCTION_TOKEN_CODES, true)) {
 					return true;
 				}
 			}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/RequireExplicitAssertionSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/RequireExplicitAssertionSniff.php
index 49466b11d..bbff40f48 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/RequireExplicitAssertionSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/RequireExplicitAssertionSniff.php
@@ -46,11 +46,9 @@ class RequireExplicitAssertionSniff implements Sniff
 
 	public const CODE_REQUIRED_EXPLICIT_ASSERTION = 'RequiredExplicitAssertion';
 
-	/** @var bool */
-	public $enableIntegerRanges = false;
+	public bool $enableIntegerRanges = false;
 
-	/** @var bool */
-	public $enableAdvancedStringTypes = false;
+	public bool $enableAdvancedStringTypes = false;
 
 	/**
 	 * @return array
@@ -149,7 +147,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 					T_VARIABLE,
 					$variableName,
 					$listParenthesisOpener + 1,
-					$tokens[$listParenthesisOpener]['parenthesis_closer']
+					$tokens[$listParenthesisOpener]['parenthesis_closer'],
 				);
 				if ($variablePointerInList === null) {
 					continue;
@@ -169,7 +167,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 					T_VARIABLE,
 					$variableName,
 					$codePointer + 1,
-					$tokens[$codePointer]['bracket_closer']
+					$tokens[$codePointer]['bracket_closer'],
 				);
 				if ($variablePointerInList === null) {
 					continue;
@@ -178,7 +176,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 				$pointerToAddAssertion = $this->getNextSemicolonInSameScope(
 					$phpcsFile,
 					$codePointer,
-					$tokens[$codePointer]['bracket_closer'] + 1
+					$tokens[$codePointer]['bracket_closer'] + 1,
 				);
 				$indentation = IndentationHelper::getIndentation($phpcsFile, $docCommentOpenPointer);
 
@@ -189,7 +187,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 						T_VARIABLE,
 						$variableName,
 						$tokens[$codePointer]['parenthesis_opener'] + 1,
-						$tokens[$codePointer]['parenthesis_closer']
+						$tokens[$codePointer]['parenthesis_closer'],
 					);
 					if ($variablePointerInWhile === null) {
 						continue;
@@ -204,14 +202,14 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 						$phpcsFile,
 						T_AS,
 						$tokens[$codePointer]['parenthesis_opener'] + 1,
-						$tokens[$codePointer]['parenthesis_closer']
+						$tokens[$codePointer]['parenthesis_closer'],
 					);
 					$variablePointerInForeach = TokenHelper::findNextContent(
 						$phpcsFile,
 						T_VARIABLE,
 						$variableName,
 						$asPointer + 1,
-						$tokens[$codePointer]['parenthesis_closer']
+						$tokens[$codePointer]['parenthesis_closer'],
 					);
 					if ($variablePointerInForeach === null) {
 						continue;
@@ -219,13 +217,13 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 				}
 
 				$pointerToAddAssertion = $tokens[$codePointer]['scope_opener'];
-				$indentation = IndentationHelper::addIndentation(IndentationHelper::getIndentation($phpcsFile, $codePointer));
+				$indentation = IndentationHelper::addIndentation($phpcsFile, IndentationHelper::getIndentation($phpcsFile, $codePointer));
 			}
 
 			$fix = $phpcsFile->addFixableError(
 				'Use assertion instead of inline documentation comment.',
 				$variableAnnotation->getStartPointer(),
-				self::CODE_REQUIRED_EXPLICIT_ASSERTION
+				self::CODE_REQUIRED_EXPLICIT_ASSERTION,
 			);
 			if (!$fix) {
 				continue;
@@ -251,13 +249,13 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 				$phpcsFile,
 				T_WHITESPACE,
 				$phpcsFile->eolChar,
-				$docCommentOpenPointer - 1
+				$docCommentOpenPointer - 1,
 			);
 			$pointerAfterDocComment = TokenHelper::findNextContent(
 				$phpcsFile,
 				T_WHITESPACE,
 				$phpcsFile->eolChar,
-				$docCommentClosePointer + 1
+				$docCommentClosePointer + 1,
 			);
 
 			if (!$docCommentUseful) {
@@ -268,9 +266,9 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 				$pointerToAddAssertion < $docCommentClosePointer
 				&& array_key_exists($pointerAfterDocComment + 1, $tokens)
 			) {
-				$phpcsFile->fixer->addContentBefore($pointerAfterDocComment + 1, $indentation . $assertion . $phpcsFile->eolChar);
+				FixerHelper::addBefore($phpcsFile, $pointerAfterDocComment + 1, $indentation . $assertion . $phpcsFile->eolChar);
 			} else {
-				$phpcsFile->fixer->addContent($pointerToAddAssertion, $phpcsFile->eolChar . $indentation . $assertion);
+				FixerHelper::add($phpcsFile, $pointerToAddAssertion, $phpcsFile->eolChar . $indentation . $assertion);
 			}
 
 			$phpcsFile->fixer->endChangeset();
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/RequireNowdocSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/RequireNowdocSniff.php
index 88e6f2365..a4e82dea1 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/RequireNowdocSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/RequireNowdocSniff.php
@@ -4,6 +4,7 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use function preg_match;
 use function preg_replace;
@@ -55,17 +56,17 @@ public function process(File $phpcsFile, $heredocStartPointer): void
 		$nowdocStart = preg_replace('~^<<<"?(\w+)"?~', '<<<\'$1\'', $tokens[$heredocStartPointer]['content']);
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->replaceToken($heredocStartPointer, $nowdocStart);
+		FixerHelper::replace($phpcsFile, $heredocStartPointer, $nowdocStart);
 
 		foreach ($heredocContentPointers as $heredocContentPointer) {
 			$heredocContent = $tokens[$heredocContentPointer]['content'];
 			$nowdocContent = preg_replace(
 				'~\\\\(\\\\[nrtvef]|\$|\\\\|\\\\[0-7]{1,3}|\\\\x[0-9A-Fa-f]{1,2}|\\\\u\{[0-9A-Fa-f]+\})~',
 				'$1',
-				$heredocContent
+				$heredocContent,
 			);
 
-			$phpcsFile->fixer->replaceToken($heredocContentPointer, $nowdocContent);
+			FixerHelper::replace($phpcsFile, $heredocContentPointer, $nowdocContent);
 		}
 
 		$phpcsFile->fixer->endChangeset();
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/ShortListSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/ShortListSniff.php
index 493261b5c..6a9362a32 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/ShortListSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/ShortListSniff.php
@@ -42,8 +42,8 @@ public function process(File $phpcsFile, $pointer): void
 
 		$phpcsFile->fixer->beginChangeset();
 		FixerHelper::removeBetweenIncluding($phpcsFile, $pointer, $startPointer - 1);
-		$phpcsFile->fixer->replaceToken($startPointer, '[');
-		$phpcsFile->fixer->replaceToken($endPointer, ']');
+		FixerHelper::replace($phpcsFile, $startPointer, '[');
+		FixerHelper::replace($phpcsFile, $endPointer, ']');
 		$phpcsFile->fixer->endChangeset();
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/TypeCastSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/TypeCastSniff.php
index a5b17bd12..cc39647c6 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/TypeCastSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/TypeCastSniff.php
@@ -73,7 +73,7 @@ public function process(File $phpcsFile, $pointer): void
 			$phpcsFile->addError(
 				sprintf('Cast "%s" is forbidden, use "unset(...)" or assign "null" instead.', $cast),
 				$pointer,
-				self::CODE_FORBIDDEN_CAST_USED
+				self::CODE_FORBIDDEN_CAST_USED,
 			);
 
 			return;
@@ -83,7 +83,7 @@ public function process(File $phpcsFile, $pointer): void
 			$fix = $phpcsFile->addFixableError(
 				sprintf('"Cast "%s" is forbidden and has no effect.', $cast),
 				$pointer,
-				self::CODE_FORBIDDEN_CAST_USED
+				self::CODE_FORBIDDEN_CAST_USED,
 			);
 
 			if (!$fix) {
@@ -104,7 +104,7 @@ public function process(File $phpcsFile, $pointer): void
 		$fix = $phpcsFile->addFixableError(
 			sprintf('Cast "%s" is forbidden, use "(%s)" instead.', $cast, self::INVALID_CASTS[$castNameLower]),
 			$pointer,
-			self::CODE_INVALID_CAST_USED
+			self::CODE_INVALID_CAST_USED,
 		);
 
 		if (!$fix) {
@@ -112,7 +112,7 @@ public function process(File $phpcsFile, $pointer): void
 		}
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->replaceToken($pointer, '(' . self::INVALID_CASTS[$castNameLower] . ')');
+		FixerHelper::replace($phpcsFile, $pointer, '(' . self::INVALID_CASTS[$castNameLower] . ')');
 		$phpcsFile->fixer->endChangeset();
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/UselessParenthesesSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/UselessParenthesesSniff.php
index 17c78a06b..903c3bfb8 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/UselessParenthesesSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/PHP/UselessParenthesesSniff.php
@@ -16,6 +16,7 @@
 use const T_ANON_CLASS;
 use const T_ARRAY_CAST;
 use const T_BITWISE_AND;
+use const T_BITWISE_NOT;
 use const T_BITWISE_OR;
 use const T_BITWISE_XOR;
 use const T_BOOL_CAST;
@@ -23,9 +24,11 @@
 use const T_CASE;
 use const T_CLONE;
 use const T_CLOSE_PARENTHESIS;
+use const T_CLOSE_SHORT_ARRAY;
 use const T_CLOSURE;
 use const T_COALESCE;
 use const T_COLON;
+use const T_COMMA;
 use const T_CONSTANT_ENCAPSED_STRING;
 use const T_DIVIDE;
 use const T_DNUMBER;
@@ -60,6 +63,7 @@
 use const T_REQUIRE_ONCE;
 use const T_SELF;
 use const T_SEMICOLON;
+use const T_SL;
 use const T_SR;
 use const T_STATIC;
 use const T_STRING_CAST;
@@ -97,8 +101,7 @@ class UselessParenthesesSniff implements Sniff
 		T_STRING_CONCAT => 5,
 	];
 
-	/** @var bool */
-	public $ignoreComplexTernaryConditions = false;
+	public bool $ignoreComplexTernaryConditions = false;
 
 	/**
 	 * @return array
@@ -128,40 +131,38 @@ public function process(File $phpcsFile, $parenthesisOpenerPointer): void
 
 		/** @var int $pointerBeforeParenthesisOpener */
 		$pointerBeforeParenthesisOpener = TokenHelper::findPreviousEffective($phpcsFile, $parenthesisOpenerPointer - 1);
-		if (in_array($tokens[$pointerBeforeParenthesisOpener]['code'], array_merge(
-			TokenHelper::getNameTokenCodes(),
-			[
-				T_VARIABLE,
-				T_ISSET,
-				T_UNSET,
-				T_EMPTY,
-				T_CLOSURE,
-				T_FN,
-				T_USE,
-				T_ANON_CLASS,
-				T_NEW,
-				T_SELF,
-				T_STATIC,
-				T_PARENT,
-				T_EXIT,
-				T_CLOSE_PARENTHESIS,
-				T_EVAL,
-				T_LIST,
-				T_INCLUDE,
-				T_INCLUDE_ONCE,
-				T_REQUIRE,
-				T_REQUIRE_ONCE,
-				T_INT_CAST,
-				T_DOUBLE_CAST,
-				T_STRING_CAST,
-				T_ARRAY_CAST,
-				T_OBJECT_CAST,
-				T_BOOL_CAST,
-				T_UNSET_CAST,
-				T_MATCH,
-			]
-		), true)
-		) {
+		if (in_array($tokens[$pointerBeforeParenthesisOpener]['code'], [
+			...TokenHelper::NAME_TOKEN_CODES,
+			T_VARIABLE,
+			T_ISSET,
+			T_UNSET,
+			T_EMPTY,
+			T_CLOSURE,
+			T_FN,
+			T_USE,
+			T_ANON_CLASS,
+			T_NEW,
+			T_SELF,
+			T_STATIC,
+			T_PARENT,
+			T_EXIT,
+			T_CLOSE_PARENTHESIS,
+			T_EVAL,
+			T_LIST,
+			T_INCLUDE,
+			T_INCLUDE_ONCE,
+			T_REQUIRE,
+			T_REQUIRE_ONCE,
+			T_INT_CAST,
+			T_DOUBLE_CAST,
+			T_STRING_CAST,
+			T_ARRAY_CAST,
+			T_OBJECT_CAST,
+			T_BOOL_CAST,
+			T_UNSET_CAST,
+			T_MATCH,
+			T_BITWISE_NOT,
+		], true,)) {
 			return;
 		}
 
@@ -169,8 +170,8 @@ public function process(File $phpcsFile, $parenthesisOpenerPointer): void
 		$pointerAfterParenthesisOpener = TokenHelper::findNextEffective($phpcsFile, $parenthesisOpenerPointer + 1);
 		if (in_array(
 			$tokens[$pointerAfterParenthesisOpener]['code'],
-			[T_NEW, T_CLONE, T_YIELD, T_YIELD_FROM, T_REQUIRE, T_REQUIRE_ONCE, T_INCLUDE, T_INCLUDE_ONCE, T_ARRAY_CAST],
-			true
+			[T_CLONE, T_YIELD, T_YIELD_FROM, T_REQUIRE, T_REQUIRE_ONCE, T_INCLUDE, T_INCLUDE_ONCE, T_ARRAY_CAST],
+			true,
 		)) {
 			return;
 		}
@@ -179,14 +180,14 @@ public function process(File $phpcsFile, $parenthesisOpenerPointer): void
 			$phpcsFile,
 			T_EQUAL,
 			$parenthesisOpenerPointer + 1,
-			$tokens[$parenthesisOpenerPointer]['parenthesis_closer']
+			$tokens[$parenthesisOpenerPointer]['parenthesis_closer'],
 		) !== null) {
 			return;
 		}
 
 		$pointerAfterParenthesisCloser = TokenHelper::findNextEffective(
 			$phpcsFile,
-			$tokens[$parenthesisOpenerPointer]['parenthesis_closer'] + 1
+			$tokens[$parenthesisOpenerPointer]['parenthesis_closer'] + 1,
 		);
 		if (
 			$pointerAfterParenthesisCloser !== null
@@ -204,6 +205,7 @@ public function process(File $phpcsFile, $parenthesisOpenerPointer): void
 		$this->checkParenthesesAroundVariableOrFunctionCall($phpcsFile, $parenthesisOpenerPointer);
 		$this->checkParenthesesAroundString($phpcsFile, $parenthesisOpenerPointer);
 		$this->checkParenthesesAroundOperators($phpcsFile, $parenthesisOpenerPointer);
+		$this->checkParenthesesAroundNew($phpcsFile, $parenthesisOpenerPointer);
 	}
 
 	private function checkParenthesesAroundConditionInTernaryOperator(File $phpcsFile, int $parenthesisOpenerPointer): void
@@ -221,7 +223,7 @@ private function checkParenthesesAroundConditionInTernaryOperator(File $phpcsFil
 			$phpcsFile,
 			[T_LOGICAL_AND, T_LOGICAL_OR, T_LOGICAL_XOR],
 			$parenthesisOpenerPointer + 1,
-			$parenthesisCloserPointer
+			$parenthesisCloserPointer,
 		) !== null) {
 			return;
 		}
@@ -244,7 +246,7 @@ private function checkParenthesesAroundConditionInTernaryOperator(File $phpcsFil
 				$phpcsFile,
 				Tokens::$booleanOperators,
 				$parenthesisOpenerPointer + 1,
-				$parenthesisCloserPointer
+				$parenthesisCloserPointer,
 			) !== null) {
 				return;
 			}
@@ -254,7 +256,7 @@ private function checkParenthesesAroundConditionInTernaryOperator(File $phpcsFil
 				T_WHITESPACE,
 				$phpcsFile->eolChar,
 				$parenthesisOpenerPointer + 1,
-				$parenthesisCloserPointer
+				$parenthesisCloserPointer,
 			) !== null) {
 				return;
 			}
@@ -294,7 +296,7 @@ private function checkParenthesesAroundCaseInSwitch(File $phpcsFile, int $parent
 
 		$pointerAfterParenthesisCloser = TokenHelper::findNextEffective(
 			$phpcsFile,
-			$tokens[$parenthesisOpenerPointer]['parenthesis_closer'] + 1
+			$tokens[$parenthesisOpenerPointer]['parenthesis_closer'] + 1,
 		);
 		if ($tokens[$pointerAfterParenthesisCloser]['code'] !== T_COLON) {
 			return;
@@ -321,11 +323,21 @@ private function checkParenthesesAroundVariableOrFunctionCall(File $phpcsFile, i
 	{
 		$tokens = $phpcsFile->getTokens();
 
+		$pointerAfterParenthesis = TokenHelper::findNextEffective($phpcsFile, $parenthesisOpenerPointer + 1);
+		if ($tokens[$pointerAfterParenthesis]['code'] === T_NEW) {
+			// Check in other method
+			return;
+		}
+
+		if ($tokens[$pointerAfterParenthesis]['code'] === T_OPEN_PARENTHESIS) {
+			return;
+		}
+
 		$operatorsPointers = TokenHelper::findNextAll(
 			$phpcsFile,
 			self::OPERATORS,
 			$parenthesisOpenerPointer + 1,
-			$tokens[$parenthesisOpenerPointer]['parenthesis_closer']
+			$tokens[$parenthesisOpenerPointer]['parenthesis_closer'],
 		);
 		if ($operatorsPointers !== []) {
 			return;
@@ -343,7 +355,7 @@ private function checkParenthesesAroundVariableOrFunctionCall(File $phpcsFile, i
 
 		$pointerAfterParenthesisCloser = TokenHelper::findNextEffective(
 			$phpcsFile,
-			$tokens[$parenthesisOpenerPointer]['parenthesis_closer'] + 1
+			$tokens[$parenthesisOpenerPointer]['parenthesis_closer'] + 1,
 		);
 		if (in_array($tokens[$pointerAfterParenthesisCloser]['code'], [T_INLINE_THEN, T_OPEN_PARENTHESIS, T_SR], true)) {
 			return;
@@ -365,14 +377,14 @@ private function checkParenthesesAroundVariableOrFunctionCall(File $phpcsFile, i
 
 		if (in_array(
 			$tokens[$notBooleanNotOperatorPointer]['code'],
-			array_merge([T_SELF, T_STATIC, T_PARENT, T_VARIABLE, T_DOLLAR], TokenHelper::getNameTokenCodes()),
-			true
+			[T_SELF, T_STATIC, T_PARENT, T_VARIABLE, T_DOLLAR, ...TokenHelper::NAME_TOKEN_CODES],
+			true,
 		)) {
 			$contentEndPointer = IdentificatorHelper::findEndPointer($phpcsFile, $notBooleanNotOperatorPointer);
 
 			if (
 				$contentEndPointer === null
-				&& in_array($tokens[$notBooleanNotOperatorPointer]['code'], TokenHelper::getNameTokenCodes(), true)
+				&& in_array($tokens[$notBooleanNotOperatorPointer]['code'], TokenHelper::NAME_TOKEN_CODES, true)
 			) {
 				$nextPointer = TokenHelper::findNextEffective($phpcsFile, $contentStartPointer + 1);
 				if ($tokens[$nextPointer]['code'] === T_OPEN_PARENTHESIS) {
@@ -451,10 +463,16 @@ private function checkParenthesesAroundOperators(File $phpcsFile, int $parenthes
 	{
 		$tokens = $phpcsFile->getTokens();
 
+		$newPointer = TokenHelper::findNextEffective($phpcsFile, $parenthesisOpenerPointer + 1);
+		if ($tokens[$newPointer]['code'] === T_NEW) {
+			// Check in other method
+			return;
+		}
+
 		$pointerBeforeParenthesisOpener = TokenHelper::findPreviousEffective($phpcsFile, $parenthesisOpenerPointer - 1);
 		$pointerAfterParenthesisCloser = TokenHelper::findNextEffective(
 			$phpcsFile,
-			$tokens[$parenthesisOpenerPointer]['parenthesis_closer'] + 1
+			$tokens[$parenthesisOpenerPointer]['parenthesis_closer'] + 1,
 		);
 
 		if ($tokens[$pointerBeforeParenthesisOpener]['code'] === T_MINUS) {
@@ -467,29 +485,35 @@ private function checkParenthesesAroundOperators(File $phpcsFile, int $parenthes
 		if (
 			in_array($tokens[$pointerBeforeParenthesisOpener]['code'], Tokens::$booleanOperators, true)
 			|| in_array($tokens[$pointerAfterParenthesisCloser]['code'], Tokens::$booleanOperators, true)
+			|| $tokens[$pointerBeforeParenthesisOpener]['code'] === T_BOOLEAN_NOT
 		) {
 			return;
 		}
 
+		$complicatedOperators = [T_INLINE_THEN, T_COALESCE, T_BITWISE_AND, T_BITWISE_OR, T_BITWISE_XOR, T_SL, T_SR];
+
 		$operatorsPointers = [];
 		$actualStartPointer = $parenthesisOpenerPointer + 1;
 		while (true) {
 			$pointer = TokenHelper::findNext(
 				$phpcsFile,
 				array_merge(
-					self::OPERATORS,
-					[T_OPEN_PARENTHESIS, T_INLINE_THEN, T_COALESCE, T_BITWISE_AND, T_BITWISE_OR, T_BITWISE_XOR],
-					Tokens::$comparisonTokens
+					[
+						...self::OPERATORS,
+						T_OPEN_PARENTHESIS,
+						...$complicatedOperators,
+					],
+					Tokens::$comparisonTokens,
 				),
 				$actualStartPointer,
-				$tokens[$parenthesisOpenerPointer]['parenthesis_closer']
+				$tokens[$parenthesisOpenerPointer]['parenthesis_closer'],
 			);
 
 			if ($pointer === null) {
 				break;
 			}
 
-			if (in_array($tokens[$pointer]['code'], [T_INLINE_THEN, T_COALESCE, T_BITWISE_AND, T_BITWISE_OR, T_BITWISE_XOR], true)) {
+			if (in_array($tokens[$pointer]['code'], $complicatedOperators, true)) {
 				return;
 			}
 
@@ -514,9 +538,10 @@ private function checkParenthesesAroundOperators(File $phpcsFile, int $parenthes
 			$tokens[$pointerBeforeParenthesisOpener]['code'] !== T_EQUAL
 			|| $tokens[$pointerAfterParenthesisCloser]['code'] !== T_SEMICOLON
 		) {
-			$operatorsGroups = array_map(static function (int $operatorPointer) use ($tokens): int {
-				return self::OPERATOR_GROUPS[$tokens[$operatorPointer]['code']];
-			}, $operatorsPointers);
+			$operatorsGroups = array_map(
+				static fn (int $operatorPointer): int => self::OPERATOR_GROUPS[$tokens[$operatorPointer]['code']],
+				$operatorsPointers,
+			);
 
 			if (count($operatorsGroups) > 1) {
 				return;
@@ -576,4 +601,38 @@ private function checkParenthesesAroundOperators(File $phpcsFile, int $parenthes
 		$phpcsFile->fixer->endChangeset();
 	}
 
+	private function checkParenthesesAroundNew(File $phpcsFile, int $parenthesisOpenerPointer): void
+	{
+		$tokens = $phpcsFile->getTokens();
+
+		$newPointer = TokenHelper::findNextEffective($phpcsFile, $parenthesisOpenerPointer + 1);
+		if ($tokens[$newPointer]['code'] !== T_NEW) {
+			return;
+		}
+
+		$pointerAfterParenthesisCloser = TokenHelper::findNextEffective(
+			$phpcsFile,
+			$tokens[$parenthesisOpenerPointer]['parenthesis_closer'] + 1,
+		);
+		if (!in_array($tokens[$pointerAfterParenthesisCloser]['code'], [T_COMMA, T_SEMICOLON, T_CLOSE_SHORT_ARRAY], true)) {
+			return;
+		}
+
+		$fix = $phpcsFile->addFixableError('Useless parentheses.', $parenthesisOpenerPointer, self::CODE_USELESS_PARENTHESES);
+
+		if (!$fix) {
+			return;
+		}
+
+		$contentStartPointer = TokenHelper::findNextEffective($phpcsFile, $parenthesisOpenerPointer + 1);
+		$contentEndPointer = TokenHelper::findPreviousEffective($phpcsFile, $tokens[$parenthesisOpenerPointer]['parenthesis_closer'] - 1);
+
+		$phpcsFile->fixer->beginChangeset();
+
+		FixerHelper::removeBetweenIncluding($phpcsFile, $parenthesisOpenerPointer, $contentStartPointer - 1);
+		FixerHelper::removeBetweenIncluding($phpcsFile, $contentEndPointer + 1, $tokens[$parenthesisOpenerPointer]['parenthesis_closer']);
+
+		$phpcsFile->fixer->endChangeset();
+	}
+
 }
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Strings/DisallowVariableParsingSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Strings/DisallowVariableParsingSniff.php
index 45a8c4048..ad44796eb 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Strings/DisallowVariableParsingSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Strings/DisallowVariableParsingSniff.php
@@ -24,14 +24,11 @@ class DisallowVariableParsingSniff implements Sniff
 
 	public const CODE_DISALLOWED_SIMPLE_SYNTAX = 'DisallowedSimpleSyntax';
 
-	/** @var bool */
-	public $disallowDollarCurlySyntax = true;
+	public bool $disallowDollarCurlySyntax = true;
 
-	/** @var bool */
-	public $disallowCurlyDollarSyntax = false;
+	public bool $disallowCurlyDollarSyntax = false;
 
-	/** @var bool */
-	public $disallowSimpleSyntax = false;
+	public bool $disallowSimpleSyntax = false;
 
 	/**
 	 * @return array
@@ -82,10 +79,10 @@ public function process(File $phpcsFile, $stringPointer): void
 						$phpcsFile->addError(
 							sprintf(
 								'Using variable syntax "${...}" inside string is disallowed as syntax "${...}" is deprecated as of PHP 8.2, found "%s".',
-								$usedVariable
+								$usedVariable,
 							),
 							$stringPointer,
-							self::CODE_DISALLOWED_DOLLAR_CURLY_SYNTAX
+							self::CODE_DISALLOWED_DOLLAR_CURLY_SYNTAX,
 						);
 
 						break;
@@ -107,10 +104,10 @@ public function process(File $phpcsFile, $stringPointer): void
 					$phpcsFile->addError(
 						sprintf(
 							'Using variable syntax "{$...}" inside string is disallowed, found "{%s}".',
-							$usedVariable
+							$usedVariable,
 						),
 						$stringPointer,
-						self::CODE_DISALLOWED_CURLY_DOLLAR_SYNTAX
+						self::CODE_DISALLOWED_CURLY_DOLLAR_SYNTAX,
 					);
 				} elseif ($this->disallowSimpleSyntax) {
 					$error = true;
@@ -132,10 +129,10 @@ public function process(File $phpcsFile, $stringPointer): void
 						$phpcsFile->addError(
 							sprintf(
 								'Using variable syntax "$..." inside string is disallowed, found "%s".',
-								$this->getTokenContent($stringToken)
+								$this->getTokenContent($stringToken),
 							),
 							$stringPointer,
-							self::CODE_DISALLOWED_SIMPLE_SYNTAX
+							self::CODE_DISALLOWED_SIMPLE_SYNTAX,
 						);
 					}
 				}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TestCase.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TestCase.php
index 74d440f94..abcb81e2e 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TestCase.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TestCase.php
@@ -29,6 +29,8 @@
 abstract class TestCase extends \PHPUnit\Framework\TestCase
 {
 
+	private const TAB_WIDTH = 4;
+
 	/**
 	 * @param array> $sniffProperties
 	 * @param list $codesToCheck
@@ -44,6 +46,13 @@ protected static function checkFile(string $filePath, array $sniffProperties = [
 		$codeSniffer->init();
 
 		if (count($sniffProperties) > 0) {
+			foreach ($sniffProperties as $name => $value) {
+				$sniffProperties[$name] = [
+					'value' => $value,
+					'scope' => 'sniff',
+				];
+			}
+
 			$codeSniffer->ruleset->ruleset[self::getSniffName()]['properties'] = $sniffProperties;
 		}
 
@@ -64,6 +73,7 @@ protected static function checkFile(string $filePath, array $sniffProperties = [
 		}
 
 		$codeSniffer->ruleset->populateTokenListeners();
+		$codeSniffer->config->tabWidth = self::TAB_WIDTH;
 
 		$file = new LocalFile($filePath, $codeSniffer->ruleset, $codeSniffer->config);
 		$file->process();
@@ -103,8 +113,8 @@ protected static function assertSniffError(File $phpcsFile, int $line, string $c
 				$line,
 				PHP_EOL,
 				self::getFormattedErrors($errors[$line]),
-				PHP_EOL
-			)
+				PHP_EOL,
+			),
 		);
 	}
 
@@ -128,8 +138,8 @@ protected static function assertSniffWarning(File $phpcsFile, int $line, string
 				$line,
 				PHP_EOL,
 				self::getFormattedErrors($errors[$line]),
-				PHP_EOL
-			)
+				PHP_EOL,
+			),
 		);
 	}
 
@@ -143,8 +153,8 @@ protected static function assertNoSniffError(File $phpcsFile, int $line): void
 				$line,
 				PHP_EOL . PHP_EOL,
 				isset($errors[$line]) ? self::getFormattedErrors($errors[$line]) : '',
-				PHP_EOL
-			)
+				PHP_EOL,
+			),
 		);
 	}
 
@@ -215,11 +225,16 @@ private static function hasError(array $errorsOnLine, string $sniffCode, ?string
 	 */
 	private static function getFormattedErrors(array $errors): string
 	{
-		return implode(PHP_EOL, array_map(static function (array $errors): string {
-			return implode(PHP_EOL, array_map(static function (array $error): string {
-				return sprintf("\t%s: %s", $error['source'], $error['message']);
-			}, $errors));
-		}, $errors));
+		return implode(
+			PHP_EOL,
+			array_map(
+				static fn (array $errors): string => implode(
+					PHP_EOL,
+					array_map(static fn (array $error): string => sprintf("\t%s: %s", $error['source'], $error['message']), $errors),
+				),
+				$errors,
+			),
+		);
 	}
 
 }
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/ClassConstantTypeHintSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/ClassConstantTypeHintSniff.php
new file mode 100644
index 000000000..3b78ab0fb
--- /dev/null
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/ClassConstantTypeHintSniff.php
@@ -0,0 +1,225 @@
+ */
+	private static array $tokenToTypeHintMapping = [
+		T_FALSE => 'false',
+		T_TRUE => 'true',
+		T_DNUMBER => 'float',
+		T_LNUMBER => 'int',
+		T_NULL => 'null',
+		T_OPEN_SHORT_ARRAY => 'array',
+		T_CONSTANT_ENCAPSED_STRING => 'string',
+		T_START_NOWDOC => 'string',
+		T_START_HEREDOC => 'string',
+	];
+
+	/**
+	 * @return array
+	 */
+	public function register(): array
+	{
+		return [
+			T_CONST,
+		];
+	}
+
+	/**
+	 * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
+	 * @param int $constantPointer
+	 */
+	public function process(File $phpcsFile, $constantPointer): void
+	{
+		if (ClassHelper::getClassPointer($phpcsFile, $constantPointer) === null) {
+			// Constant in namespace
+			return;
+		}
+
+		$this->checkNativeTypeHint($phpcsFile, $constantPointer);
+		$this->checkDocComment($phpcsFile, $constantPointer);
+	}
+
+	private function checkNativeTypeHint(File $phpcsFile, int $constantPointer): void
+	{
+		$this->enableNativeTypeHint = SniffSettingsHelper::isEnabledByPhpVersion($this->enableNativeTypeHint, 80300);
+
+		if (!$this->enableNativeTypeHint) {
+			return;
+		}
+
+		$namePointer = $this->getConstantNamePointer($phpcsFile, $constantPointer);
+		$typeHintPointer = TokenHelper::findPreviousEffective($phpcsFile, $namePointer - 1);
+
+		if ($typeHintPointer !== $constantPointer) {
+			// Has type hint
+			return;
+		}
+
+		$tokens = $phpcsFile->getTokens();
+
+		$namePointer = $this->getConstantNamePointer($phpcsFile, $constantPointer);
+		$equalPointer = TokenHelper::findNext($phpcsFile, T_EQUAL, $constantPointer + 1);
+
+		$valuePointer = TokenHelper::findNextEffective($phpcsFile, $equalPointer + 1);
+		if ($tokens[$valuePointer]['code'] === T_MINUS) {
+			$valuePointer = TokenHelper::findNextEffective($phpcsFile, $valuePointer + 1);
+		}
+
+		$constantName = $tokens[$namePointer]['content'];
+
+		$typeHint = null;
+		if (array_key_exists($tokens[$valuePointer]['code'], self::$tokenToTypeHintMapping)) {
+			$typeHint = self::$tokenToTypeHintMapping[$tokens[$valuePointer]['code']];
+		}
+
+		$errorParameters = [
+			sprintf('Constant %s does not have native type hint.', $constantName),
+			$constantPointer,
+			self::CODE_MISSING_NATIVE_TYPE_HINT,
+		];
+
+		if (
+			$typeHint === null
+			|| $this->fixableNativeTypeHint === self::NO
+			|| (
+				$this->fixableNativeTypeHint === self::PRIVATE
+				&& !$this->isConstantPrivate($phpcsFile, $constantPointer)
+			)
+		) {
+			$phpcsFile->addError(...$errorParameters);
+			return;
+		}
+
+		$fix = $phpcsFile->addFixableError(...$errorParameters);
+
+		if (!$fix) {
+			return;
+		}
+
+		$phpcsFile->fixer->beginChangeset();
+		FixerHelper::add($phpcsFile, $constantPointer, ' ' . $typeHint);
+		$phpcsFile->fixer->endChangeset();
+	}
+
+	private function checkDocComment(File $phpcsFile, int $constantPointer): void
+	{
+		$docCommentOpenPointer = DocCommentHelper::findDocCommentOpenPointer($phpcsFile, $constantPointer);
+		if ($docCommentOpenPointer === null) {
+			return;
+		}
+
+		$annotations = AnnotationHelper::getAnnotations($phpcsFile, $constantPointer, '@var');
+
+		if ($annotations === []) {
+			return;
+		}
+
+		$tokens = $phpcsFile->getTokens();
+
+		$namePointer = $this->getConstantNamePointer($phpcsFile, $constantPointer);
+		$constantName = $tokens[$namePointer]['content'];
+
+		$uselessDocComment = !DocCommentHelper::hasDocCommentDescription($phpcsFile, $constantPointer) && count($annotations) === 1;
+		if ($uselessDocComment) {
+			$fix = $phpcsFile->addFixableError(
+				sprintf('Useless documentation comment for constant %s.', $constantName),
+				$docCommentOpenPointer,
+				self::CODE_USELESS_DOC_COMMENT,
+			);
+
+			/** @var int $fixerStart */
+			$fixerStart = TokenHelper::findLastTokenOnPreviousLine($phpcsFile, $docCommentOpenPointer);
+			$fixerEnd = $tokens[$docCommentOpenPointer]['comment_closer'];
+		} else {
+			$annotation = $annotations[0];
+
+			$fix = $phpcsFile->addFixableError(
+				sprintf('Useless @var annotation for constant %s.', $constantName),
+				$annotation->getStartPointer(),
+				self::CODE_USELESS_VAR_ANNOTATION,
+			);
+
+			/** @var int $fixerStart */
+			$fixerStart = TokenHelper::findPreviousContent(
+				$phpcsFile,
+				T_DOC_COMMENT_WHITESPACE,
+				$phpcsFile->eolChar,
+				$annotation->getStartPointer() - 1,
+			);
+			$fixerEnd = $annotation->getEndPointer();
+		}
+
+		if (!$fix) {
+			return;
+		}
+
+		$phpcsFile->fixer->beginChangeset();
+		FixerHelper::removeBetweenIncluding($phpcsFile, $fixerStart, $fixerEnd);
+		$phpcsFile->fixer->endChangeset();
+	}
+
+	private function getConstantNamePointer(File $phpcsFile, int $constantPointer): int
+	{
+		$equalPointer = TokenHelper::findNext($phpcsFile, T_EQUAL, $constantPointer + 1);
+
+		return TokenHelper::findPreviousEffective($phpcsFile, $equalPointer - 1);
+	}
+
+	private function isConstantPrivate(File $phpcsFile, int $constantPointer): bool
+	{
+		$tokens = $phpcsFile->getTokens();
+		$previousPointer = TokenHelper::findPrevious(
+			$phpcsFile,
+			[T_PRIVATE, T_OPEN_CURLY_BRACKET, T_CLOSE_CURLY_BRACKET, T_SEMICOLON],
+			$constantPointer - 1,
+		);
+
+		return $previousPointer !== null && $tokens[$previousPointer]['code'] === T_PRIVATE;
+	}
+
+}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/DNFTypeHintFormatSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/DNFTypeHintFormatSniff.php
new file mode 100644
index 000000000..78341ea0c
--- /dev/null
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/DNFTypeHintFormatSniff.php
@@ -0,0 +1,334 @@
+
+	 */
+	public function register(): array
+	{
+		return [
+			T_VARIABLE,
+			...TokenHelper::FUNCTION_TOKEN_CODES,
+		];
+	}
+
+	/**
+	 * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
+	 * @param int $pointer
+	 */
+	public function process(File $phpcsFile, $pointer): void
+	{
+		$this->enable = SniffSettingsHelper::isEnabledByPhpVersion($this->enable, 80000);
+
+		if (!$this->enable) {
+			return;
+		}
+
+		$tokens = $phpcsFile->getTokens();
+
+		if ($tokens[$pointer]['code'] === T_VARIABLE) {
+			if (!PropertyHelper::isProperty($phpcsFile, $pointer)) {
+				return;
+			}
+
+			$propertyTypeHint = PropertyHelper::findTypeHint($phpcsFile, $pointer);
+			if ($propertyTypeHint !== null) {
+				$this->checkTypeHint($phpcsFile, $propertyTypeHint);
+			}
+
+			return;
+		}
+
+		$returnTypeHint = FunctionHelper::findReturnTypeHint($phpcsFile, $pointer);
+		if ($returnTypeHint !== null) {
+			$this->checkTypeHint($phpcsFile, $returnTypeHint);
+		}
+
+		foreach (FunctionHelper::getParametersTypeHints($phpcsFile, $pointer) as $parameterTypeHint) {
+			if ($parameterTypeHint !== null) {
+				$this->checkTypeHint($phpcsFile, $parameterTypeHint);
+			}
+		}
+	}
+
+	private function checkTypeHint(File $phpcsFile, TypeHint $typeHint): void
+	{
+		$tokens = $phpcsFile->getTokens();
+
+		$typeHintsCount = substr_count($typeHint->getTypeHint(), '|') + substr_count($typeHint->getTypeHint(), '&') + 1;
+
+		if ($typeHintsCount > 1) {
+			if ($this->withSpacesAroundOperators === self::NO) {
+				$error = false;
+				foreach (TokenHelper::findNextAll(
+					$phpcsFile,
+					T_WHITESPACE,
+					$typeHint->getStartPointer(),
+					$typeHint->getEndPointer(),
+				) as $whitespacePointer) {
+					if (in_array($tokens[$whitespacePointer - 1]['code'], [T_TYPE_UNION, T_TYPE_INTERSECTION], true)) {
+						$error = true;
+						break;
+					}
+					if (in_array($tokens[$whitespacePointer + 1]['code'], [T_TYPE_UNION, T_TYPE_INTERSECTION], true)) {
+						$error = true;
+						break;
+					}
+				}
+
+				if ($error) {
+					$originalTypeHint = TokenHelper::getContent($phpcsFile, $typeHint->getStartPointer(), $typeHint->getEndPointer());
+					$fix = $phpcsFile->addFixableError(
+						sprintf('Spaces around "|" or "&" in type hint "%s" are disallowed.', $originalTypeHint),
+						$typeHint->getStartPointer(),
+						self::CODE_DISALLOWED_WHITESPACE_AROUND_OPERATOR,
+					);
+					if ($fix) {
+						$fixedTypeHint = preg_replace('~\s*([|&])\s*~', '\1', $originalTypeHint);
+						$this->fixTypeHint($phpcsFile, $typeHint, $fixedTypeHint);
+					}
+				}
+			} elseif ($this->withSpacesAroundOperators === self::YES) {
+				$error = false;
+				foreach (TokenHelper::findNextAll(
+					$phpcsFile,
+					[T_TYPE_UNION, T_TYPE_INTERSECTION],
+					$typeHint->getStartPointer(),
+					$typeHint->getEndPointer(),
+				) as $operatorPointer) {
+					if ($tokens[$operatorPointer - 1]['content'] !== ' ') {
+						$error = true;
+						break;
+					}
+					if ($tokens[$operatorPointer + 1]['content'] !== ' ') {
+						$error = true;
+						break;
+					}
+				}
+
+				if ($error) {
+					$originalTypeHint = TokenHelper::getContent($phpcsFile, $typeHint->getStartPointer(), $typeHint->getEndPointer());
+					$fix = $phpcsFile->addFixableError(
+						sprintf('One space required around each "|" or "&" in type hint "%s".', $originalTypeHint),
+						$typeHint->getStartPointer(),
+						self::CODE_REQUIRED_WHITESPACE_AROUND_OPERATOR,
+					);
+					if ($fix) {
+						$fixedTypeHint = preg_replace('~\s*([|&])\s*~', ' \1 ', $originalTypeHint);
+						$this->fixTypeHint($phpcsFile, $typeHint, $fixedTypeHint);
+					}
+				}
+			}
+
+			if ($this->withSpacesInsideParentheses === self::NO) {
+				$error = false;
+				foreach (TokenHelper::findNextAll(
+					$phpcsFile,
+					T_WHITESPACE,
+					$typeHint->getStartPointer(),
+					$typeHint->getEndPointer(),
+				) as $whitespacePointer) {
+					if ($tokens[$whitespacePointer - 1]['code'] === T_TYPE_OPEN_PARENTHESIS) {
+						$error = true;
+						break;
+					}
+					if ($tokens[$whitespacePointer + 1]['code'] === T_TYPE_CLOSE_PARENTHESIS) {
+						$error = true;
+						break;
+					}
+				}
+
+				if ($error) {
+					$originalTypeHint = TokenHelper::getContent($phpcsFile, $typeHint->getStartPointer(), $typeHint->getEndPointer());
+					$fix = $phpcsFile->addFixableError(
+						sprintf('Spaces inside parentheses in type hint "%s" are disallowed.', $originalTypeHint),
+						$typeHint->getStartPointer(),
+						self::CODE_DISALLOWED_WHITESPACE_INSIDE_PARENTHESES,
+					);
+					if ($fix) {
+						$fixedTypeHint = preg_replace('~\s+\)~', ')', preg_replace('~\(\s+~', '(', $originalTypeHint));
+						$this->fixTypeHint($phpcsFile, $typeHint, $fixedTypeHint);
+					}
+				}
+			} elseif ($this->withSpacesInsideParentheses === self::YES) {
+				$error = false;
+				foreach (TokenHelper::findNextAll(
+					$phpcsFile,
+					[T_TYPE_OPEN_PARENTHESIS, T_TYPE_CLOSE_PARENTHESIS],
+					$typeHint->getStartPointer(),
+					$typeHint->getEndPointer() + 1,
+				) as $parenthesisPointer) {
+					if (
+						$tokens[$parenthesisPointer]['code'] === T_TYPE_OPEN_PARENTHESIS
+						&& $tokens[$parenthesisPointer + 1]['content'] !== ' '
+					) {
+						$error = true;
+						break;
+					}
+					if (
+						$tokens[$parenthesisPointer]['code'] === T_TYPE_CLOSE_PARENTHESIS
+						&& $tokens[$parenthesisPointer - 1]['content'] !== ' '
+					) {
+						$error = true;
+						break;
+					}
+				}
+
+				if ($error) {
+					$originalTypeHint = TokenHelper::getContent($phpcsFile, $typeHint->getStartPointer(), $typeHint->getEndPointer());
+					$fix = $phpcsFile->addFixableError(
+						sprintf('One space required around expression inside parentheses in type hint "%s".', $originalTypeHint),
+						$typeHint->getStartPointer(),
+						self::CODE_REQUIRED_WHITESPACE_INSIDE_PARENTHESES,
+					);
+					if ($fix) {
+						$fixedTypeHint = preg_replace('~\s*\)~', ' )', preg_replace('~\(\s*~', '( ', $originalTypeHint));
+						$this->fixTypeHint($phpcsFile, $typeHint, $fixedTypeHint);
+					}
+				}
+			}
+		}
+
+		if (substr_count($typeHint->getTypeHint(), '&') > 0) {
+			return;
+		}
+
+		if (!$typeHint->isNullable()) {
+			return;
+		}
+
+		$hasShortNullable = strpos($typeHint->getTypeHint(), '?') === 0;
+
+		if ($this->shortNullable === self::YES && $typeHintsCount === 2 && !$hasShortNullable) {
+			$fix = $phpcsFile->addFixableError(
+				sprintf('Short nullable type hint in "%s" is required.', $typeHint->getTypeHint()),
+				$typeHint->getStartPointer(),
+				self::CODE_REQUIRED_SHORT_NULLABLE,
+			);
+			if ($fix) {
+				$typeHintWithoutNull = self::getTypeHintContentWithoutNull($phpcsFile, $typeHint);
+				$this->fixTypeHint($phpcsFile, $typeHint, '?' . $typeHintWithoutNull);
+			}
+		} elseif ($this->shortNullable === self::NO && $hasShortNullable) {
+			$fix = $phpcsFile->addFixableError(
+				sprintf('Usage of short nullable type hint in "%s" is disallowed.', $typeHint->getTypeHint()),
+				$typeHint->getStartPointer(),
+				self::CODE_DISALLOWED_SHORT_NULLABLE,
+			);
+			if ($fix) {
+				$this->fixTypeHint($phpcsFile, $typeHint, substr($typeHint->getTypeHint(), 1) . '|null');
+			}
+		}
+
+		if ($hasShortNullable || ($this->shortNullable === self::YES && $typeHintsCount === 2)) {
+			return;
+		}
+
+		if ($this->nullPosition === self::FIRST && strtolower($tokens[$typeHint->getStartPointer()]['content']) !== 'null') {
+			$fix = $phpcsFile->addFixableError(
+				sprintf('Null type hint should be on first position in "%s".', $typeHint->getTypeHint()),
+				$typeHint->getStartPointer(),
+				self::CODE_NULL_TYPE_HINT_NOT_ON_FIRST_POSITION,
+			);
+			if ($fix) {
+				$this->fixTypeHint($phpcsFile, $typeHint, 'null|' . self::getTypeHintContentWithoutNull($phpcsFile, $typeHint));
+			}
+		} elseif ($this->nullPosition === self::LAST && strtolower($tokens[$typeHint->getEndPointer()]['content']) !== 'null') {
+			$fix = $phpcsFile->addFixableError(
+				sprintf('Null type hint should be on last position in "%s".', $typeHint->getTypeHint()),
+				$typeHint->getStartPointer(),
+				self::CODE_NULL_TYPE_HINT_NOT_ON_LAST_POSITION,
+			);
+			if ($fix) {
+				$this->fixTypeHint($phpcsFile, $typeHint, self::getTypeHintContentWithoutNull($phpcsFile, $typeHint) . '|null');
+			}
+		}
+	}
+
+	private function getTypeHintContentWithoutNull(File $phpcsFile, TypeHint $typeHint): string
+	{
+		$tokens = $phpcsFile->getTokens();
+
+		if (strtolower($tokens[$typeHint->getEndPointer()]['content']) === 'null') {
+			$previousTypeHintPointer = TokenHelper::findPrevious(
+				$phpcsFile,
+				TokenHelper::ONLY_TYPE_HINT_TOKEN_CODES,
+				$typeHint->getEndPointer() - 1,
+			);
+			return TokenHelper::getContent($phpcsFile, $typeHint->getStartPointer(), $previousTypeHintPointer);
+		}
+
+		$content = '';
+
+		for ($i = $typeHint->getStartPointer(); $i <= $typeHint->getEndPointer(); $i++) {
+			if (strtolower($tokens[$i]['content']) === 'null') {
+				$i = TokenHelper::findNext($phpcsFile, TokenHelper::ONLY_TYPE_HINT_TOKEN_CODES, $i + 1);
+			}
+
+			$content .= $tokens[$i]['content'];
+		}
+
+		return $content;
+	}
+
+	private function fixTypeHint(File $phpcsFile, TypeHint $typeHint, string $fixedTypeHint): void
+	{
+		$phpcsFile->fixer->beginChangeset();
+
+		FixerHelper::change($phpcsFile, $typeHint->getStartPointer(), $typeHint->getEndPointer(), $fixedTypeHint);
+
+		$phpcsFile->fixer->endChangeset();
+	}
+
+}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/DeclareStrictTypesSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/DeclareStrictTypesSniff.php
index 998798182..bc2a64341 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/DeclareStrictTypesSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/DeclareStrictTypesSniff.php
@@ -4,6 +4,7 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
+use SlevomatCodingStandard\Helpers\CommentHelper;
 use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\SniffSettingsHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
@@ -12,6 +13,7 @@
 use function strlen;
 use function substr;
 use function substr_count;
+use const T_COMMENT;
 use const T_DECLARE;
 use const T_LNUMBER;
 use const T_OPEN_TAG;
@@ -28,17 +30,13 @@ class DeclareStrictTypesSniff implements Sniff
 
 	public const CODE_INCORRECT_WHITESPACE_AFTER_DECLARE = 'IncorrectWhitespaceAfterDeclare';
 
-	/** @var bool */
-	public $declareOnFirstLine = false;
+	public bool $declareOnFirstLine = false;
 
-	/** @var int */
-	public $linesCountBeforeDeclare = 1;
+	public int $linesCountBeforeDeclare = 1;
 
-	/** @var int */
-	public $linesCountAfterDeclare = 1;
+	public int $linesCountAfterDeclare = 1;
 
-	/** @var int */
-	public $spacesCountAroundEqualsSign = 1;
+	public int $spacesCountAroundEqualsSign = 1;
 
 	/**
 	 * @return array
@@ -71,13 +69,15 @@ public function process(File $phpcsFile, $openTagPointer): void
 			$fix = $phpcsFile->addFixableError(
 				sprintf('Missing declare(%s).', $this->getStrictTypeDeclaration()),
 				$openTagPointer,
-				self::CODE_DECLARE_STRICT_TYPES_MISSING
+				self::CODE_DECLARE_STRICT_TYPES_MISSING,
 			);
 			if ($fix) {
 				$phpcsFile->fixer->beginChangeset();
-				$phpcsFile->fixer->addContent(
+				FixerHelper::change(
+					$phpcsFile,
 					$openTagPointer,
-					sprintf('declare(%s);%s', $this->getStrictTypeDeclaration(), $phpcsFile->eolChar)
+					substr($tokens[$openTagPointer]['content'], -1) === $phpcsFile->eolChar ? $openTagPointer : $openTagPointer + 1,
+					sprintf('getStrictTypeDeclaration(), $phpcsFile->eolChar),
 				);
 				$phpcsFile->fixer->endChangeset();
 			}
@@ -98,13 +98,14 @@ public function process(File $phpcsFile, $openTagPointer): void
 			$fix = $phpcsFile->addFixableError(
 				sprintf('Missing declare(%s).', $this->getStrictTypeDeclaration()),
 				$declarePointer,
-				self::CODE_DECLARE_STRICT_TYPES_MISSING
+				self::CODE_DECLARE_STRICT_TYPES_MISSING,
 			);
 			if ($fix) {
 				$phpcsFile->fixer->beginChangeset();
-				$phpcsFile->fixer->addContentBefore(
+				FixerHelper::addBefore(
+					$phpcsFile,
 					$tokens[$declarePointer]['parenthesis_closer'],
-					', ' . $this->getStrictTypeDeclaration()
+					', ' . $this->getStrictTypeDeclaration(),
 				);
 				$phpcsFile->fixer->endChangeset();
 			}
@@ -118,14 +119,14 @@ public function process(File $phpcsFile, $openTagPointer): void
 				sprintf(
 					'Expected %s, found %s.',
 					$this->getStrictTypeDeclaration(),
-					TokenHelper::getContent($phpcsFile, $strictTypesPointer, $numberPointer)
+					TokenHelper::getContent($phpcsFile, $strictTypesPointer, $numberPointer),
 				),
 				$declarePointer,
-				self::CODE_DECLARE_STRICT_TYPES_MISSING
+				self::CODE_DECLARE_STRICT_TYPES_MISSING,
 			);
 			if ($fix) {
 				$phpcsFile->fixer->beginChangeset();
-				$phpcsFile->fixer->replaceToken($numberPointer, '1');
+				FixerHelper::replace($phpcsFile, $numberPointer, '1');
 				$phpcsFile->fixer->endChangeset();
 			}
 			return;
@@ -138,10 +139,10 @@ public function process(File $phpcsFile, $openTagPointer): void
 				sprintf(
 					'Expected %s, found %s.',
 					$format,
-					$strictTypesContent
+					$strictTypesContent,
 				),
 				$strictTypesPointer,
-				self::CODE_INCORRECT_STRICT_TYPES_FORMAT
+				self::CODE_INCORRECT_STRICT_TYPES_FORMAT,
 			);
 			if ($fix) {
 				$phpcsFile->fixer->beginChangeset();
@@ -168,7 +169,7 @@ public function process(File $phpcsFile, $openTagPointer): void
 				$fix = $phpcsFile->addFixableError(
 					'There must be a single space between the PHP open tag and declare statement.',
 					$declarePointer,
-					self::CODE_INCORRECT_WHITESPACE_BEFORE_DECLARE
+					self::CODE_INCORRECT_WHITESPACE_BEFORE_DECLARE,
 				);
 				if ($fix) {
 					$phpcsFile->fixer->beginChangeset();
@@ -180,28 +181,43 @@ public function process(File $phpcsFile, $openTagPointer): void
 			}
 		} else {
 			$declareOnFirstLine = $tokens[$declarePointer]['line'] === $tokens[$openTagPointer]['line'];
-			$linesCountBefore = $declareOnFirstLine ? 0 : substr_count($whitespaceBefore, $phpcsFile->eolChar) - 1;
+			$whitespaceLinesBeforeDeclare = $this->linesCountBeforeDeclare;
+			$linesCountBefore = 0;
+
+			if (!$declareOnFirstLine) {
+				$linesCountBefore = substr_count($whitespaceBefore, $phpcsFile->eolChar);
+
+				if (
+					$tokens[$pointerBeforeDeclare]['code'] === T_COMMENT
+					&& CommentHelper::isLineComment($phpcsFile, $pointerBeforeDeclare)
+				) {
+					$whitespaceLinesBeforeDeclare--;
+				} else {
+					$linesCountBefore--;
+				}
+			}
+
 			if ($declareOnFirstLine || $linesCountBefore !== $this->linesCountBeforeDeclare) {
 				$fix = $phpcsFile->addFixableError(
 					sprintf(
 						'Expected %d line%s before declare statement, found %d.',
 						$this->linesCountBeforeDeclare,
 						$this->linesCountBeforeDeclare === 1 ? '' : 's',
-						$linesCountBefore
+						$linesCountBefore,
 					),
 					$declarePointer,
-					self::CODE_INCORRECT_WHITESPACE_BEFORE_DECLARE
+					self::CODE_INCORRECT_WHITESPACE_BEFORE_DECLARE,
 				);
 				if ($fix) {
 					$phpcsFile->fixer->beginChangeset();
 
 					if ($pointerBeforeDeclare === $openTagPointer) {
-						$phpcsFile->fixer->replaceToken($openTagPointer, 'linesCountBeforeDeclare; $i++) {
+					for ($i = 0; $i <= $whitespaceLinesBeforeDeclare; $i++) {
 						$phpcsFile->fixer->addNewline($pointerBeforeDeclare);
 					}
 					$phpcsFile->fixer->endChangeset();
@@ -230,10 +246,10 @@ public function process(File $phpcsFile, $openTagPointer): void
 				'Expected %d line%s after declare statement, found %d.',
 				$this->linesCountAfterDeclare,
 				$this->linesCountAfterDeclare === 1 ? '' : 's',
-				$linesCountAfter
+				$linesCountAfter,
 			),
 			$declarePointer,
-			self::CODE_INCORRECT_WHITESPACE_AFTER_DECLARE
+			self::CODE_INCORRECT_WHITESPACE_AFTER_DECLARE,
 		);
 		if (!$fix) {
 			return;
@@ -255,7 +271,7 @@ protected function getStrictTypeDeclaration(): string
 		return sprintf(
 			'strict_types%s=%s1',
 			str_repeat(' ', $this->spacesCountAroundEqualsSign),
-			str_repeat(' ', $this->spacesCountAroundEqualsSign)
+			str_repeat(' ', $this->spacesCountAroundEqualsSign),
 		);
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/DisallowArrayTypeHintSyntaxSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/DisallowArrayTypeHintSyntaxSniff.php
index bc8bc6262..7a06b5e43 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/DisallowArrayTypeHintSyntaxSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/DisallowArrayTypeHintSyntaxSniff.php
@@ -39,10 +39,10 @@ class DisallowArrayTypeHintSyntaxSniff implements Sniff
 	public const CODE_DISALLOWED_ARRAY_TYPE_HINT_SYNTAX = 'DisallowedArrayTypeHintSyntax';
 
 	/** @var list */
-	public $traversableTypeHints = [];
+	public array $traversableTypeHints = [];
 
 	/** @var array|null */
-	private $normalizedTraversableTypeHints;
+	private ?array $normalizedTraversableTypeHints = null;
 
 	/**
 	 * @return array
@@ -69,10 +69,10 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 				$fix = $phpcsFile->addFixableError(
 					sprintf(
 						'Usage of array type hint syntax in "%s" is disallowed, use generic type hint syntax instead.',
-						AnnotationTypeHelper::print($arrayTypeNode)
+						AnnotationTypeHelper::print($arrayTypeNode),
 					),
 					$annotation->getStartPointer(),
-					self::CODE_DISALLOWED_ARRAY_TYPE_HINT_SYNTAX
+					self::CODE_DISALLOWED_ARRAY_TYPE_HINT_SYNTAX,
 				);
 
 				if (!$fix) {
@@ -81,7 +81,6 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 
 				$parsedDocComment = DocCommentHelper::parseDocComment($phpcsFile, $docCommentOpenPointer);
 
-				/** @var list $unionTypeNodes */
 				$unionTypeNodes = AnnotationHelper::getAnnotationNodesByType($annotation->getNode(), UnionTypeNode::class);
 
 				$unionTypeNode = $this->findUnionTypeThatContainsArrayType($arrayTypeNode, $unionTypeNodes);
@@ -91,29 +90,29 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 						$phpcsFile,
 						$docCommentOpenPointer,
 						$unionTypeNode,
-						$annotation->getValue()
+						$annotation->getValue(),
 					);
 					if ($genericIdentifier !== null) {
 						$genericTypeNode = new GenericTypeNode(
 							new IdentifierTypeNode($genericIdentifier),
-							[$this->fixArrayNode($arrayTypeNode->type)]
+							[$this->fixArrayNode($arrayTypeNode->type)],
 						);
 						$fixedDocComment = AnnotationHelper::fixAnnotation(
 							$parsedDocComment,
 							$annotation,
 							$unionTypeNode,
-							$genericTypeNode
+							$genericTypeNode,
 						);
 					} else {
 						$genericTypeNode = new GenericTypeNode(
 							new IdentifierTypeNode('array'),
-							[$this->fixArrayNode($arrayTypeNode->type)]
+							[$this->fixArrayNode($arrayTypeNode->type)],
 						);
 						$fixedDocComment = AnnotationHelper::fixAnnotation(
 							$parsedDocComment,
 							$annotation,
 							$arrayTypeNode,
-							$genericTypeNode
+							$genericTypeNode,
 						);
 					}
 				} else {
@@ -121,12 +120,12 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 						$phpcsFile,
 						$docCommentOpenPointer,
 						$arrayTypeNode,
-						$annotation->getValue()
+						$annotation->getValue(),
 					) ?? 'array';
 
 					$genericTypeNode = new GenericTypeNode(
 						new IdentifierTypeNode($genericIdentifier),
-						[$this->fixArrayNode($arrayTypeNode->type)]
+						[$this->fixArrayNode($arrayTypeNode->type)],
 					);
 					$fixedDocComment = AnnotationHelper::fixAnnotation($parsedDocComment, $annotation, $arrayTypeNode, $genericTypeNode);
 				}
@@ -137,7 +136,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 					$phpcsFile,
 					$parsedDocComment->getOpenPointer(),
 					$parsedDocComment->getClosePointer(),
-					$fixedDocComment
+					$fixedDocComment,
 				);
 
 				$phpcsFile->fixer->endChangeset();
@@ -157,10 +156,10 @@ public function getArrayTypeNodes(Node $node): array
 			$visitor = new class extends AbstractNodeVisitor {
 
 				/** @var list */
-				private $nodes = [];
+				private array $nodes = [];
 
 				/**
-				 * @return Node|list|NodeTraverser::*|null
+				 * @return NodeTraverser::DONT_TRAVERSE_CHILDREN|null
 				 */
 				public function enterNode(Node $node)
 				{
@@ -237,7 +236,7 @@ private function findGenericIdentifier(
 				return null;
 			}
 
-			$functionPointer = TokenHelper::findNext($phpcsFile, TokenHelper::$functionTokenCodes, $docCommentOpenPointer + 1);
+			$functionPointer = TokenHelper::findNext($phpcsFile, TokenHelper::FUNCTION_TOKEN_CODES, $docCommentOpenPointer + 1);
 
 			if ($functionPointer === null || $phpcsFile->getTokens()[$functionPointer]['code'] !== T_FUNCTION) {
 				return null;
@@ -247,7 +246,7 @@ private function findGenericIdentifier(
 				$parameterTypeHints = FunctionHelper::getParametersTypeHints($phpcsFile, $functionPointer);
 				return array_key_exists(
 					$annotationValue->parameterName,
-					$parameterTypeHints
+					$parameterTypeHints,
 				) && $parameterTypeHints[$annotationValue->parameterName] !== null
 					? $parameterTypeHints[$annotationValue->parameterName]->getTypeHint()
 					: null;
@@ -265,7 +264,7 @@ private function findGenericIdentifier(
 			$typeNode->types[0] instanceof ArrayTypeNode
 			&& $typeNode->types[1] instanceof IdentifierTypeNode
 			&& $this->isTraversableType(
-				TypeHintHelper::getFullyQualifiedTypeHint($phpcsFile, $docCommentOpenPointer, $typeNode->types[1]->name)
+				TypeHintHelper::getFullyQualifiedTypeHint($phpcsFile, $docCommentOpenPointer, $typeNode->types[1]->name),
 			)
 		) {
 			return $typeNode->types[1]->name;
@@ -275,7 +274,7 @@ private function findGenericIdentifier(
 			$typeNode->types[1] instanceof ArrayTypeNode
 			&& $typeNode->types[0] instanceof IdentifierTypeNode
 			&& $this->isTraversableType(
-				TypeHintHelper::getFullyQualifiedTypeHint($phpcsFile, $docCommentOpenPointer, $typeNode->types[0]->name)
+				TypeHintHelper::getFullyQualifiedTypeHint($phpcsFile, $docCommentOpenPointer, $typeNode->types[0]->name),
 			)
 		) {
 			return $typeNode->types[0]->name;
@@ -295,11 +294,13 @@ private function isTraversableType(string $type): bool
 	private function getNormalizedTraversableTypeHints(): array
 	{
 		if ($this->normalizedTraversableTypeHints === null) {
-			$this->normalizedTraversableTypeHints = array_flip(array_map(static function (string $typeHint): string {
-				return NamespaceHelper::isFullyQualifiedName($typeHint)
-					? $typeHint
-					: sprintf('%s%s', NamespaceHelper::NAMESPACE_SEPARATOR, $typeHint);
-			}, SniffSettingsHelper::normalizeArray($this->traversableTypeHints)));
+			$this->normalizedTraversableTypeHints = array_flip(
+				array_map(static fn (string $typeHint): string => NamespaceHelper::isFullyQualifiedName($typeHint)
+						? $typeHint
+						: sprintf('%s%s', NamespaceHelper::NAMESPACE_SEPARATOR, $typeHint), SniffSettingsHelper::normalizeArray(
+							$this->traversableTypeHints,
+						)),
+			);
 		}
 		return $this->normalizedTraversableTypeHints;
 	}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/DisallowMixedTypeHintSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/DisallowMixedTypeHintSniff.php
index 2c29985ed..e8a834865 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/DisallowMixedTypeHintSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/DisallowMixedTypeHintSniff.php
@@ -6,6 +6,7 @@
 use PHP_CodeSniffer\Sniffs\Sniff;
 use PHPStan\PhpDocParser\Ast\Type\IdentifierTypeNode;
 use SlevomatCodingStandard\Helpers\AnnotationHelper;
+use SlevomatCodingStandard\Helpers\AttributeHelper;
 use SlevomatCodingStandard\Helpers\SuppressHelper;
 use function sprintf;
 use function strtolower;
@@ -37,15 +38,18 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 		if (SuppressHelper::isSniffSuppressed(
 			$phpcsFile,
 			$docCommentOpenPointer,
-			$this->getSniffName(self::CODE_DISALLOWED_MIXED_TYPE_HINT)
+			$this->getSniffName(self::CODE_DISALLOWED_MIXED_TYPE_HINT),
 		)) {
 			return;
 		}
 
+		if (AttributeHelper::hasAttribute($phpcsFile, $docCommentOpenPointer, '\Override')) {
+			return;
+		}
+
 		$annotations = AnnotationHelper::getAnnotations($phpcsFile, $docCommentOpenPointer);
 
 		foreach ($annotations as $annotation) {
-			/** @var list $identifierTypeNodes */
 			$identifierTypeNodes = AnnotationHelper::getAnnotationNodesByType($annotation->getNode(), IdentifierTypeNode::class);
 
 			foreach ($identifierTypeNodes as $typeHintNode) {
@@ -58,7 +62,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 				$phpcsFile->addError(
 					'Usage of "mixed" type hint is disallowed.',
 					$annotation->getStartPointer(),
-					self::CODE_DISALLOWED_MIXED_TYPE_HINT
+					self::CODE_DISALLOWED_MIXED_TYPE_HINT,
 				);
 			}
 		}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/LongTypeHintsSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/LongTypeHintsSniff.php
index 8bc9c2f2a..11403e3aa 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/LongTypeHintsSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/LongTypeHintsSniff.php
@@ -36,7 +36,6 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 		$annotations = AnnotationHelper::getAnnotations($phpcsFile, $docCommentOpenPointer);
 
 		foreach ($annotations as $annotation) {
-			/** @var list $identifierTypeNodes */
 			$identifierTypeNodes = AnnotationHelper::getAnnotationNodesByType($annotation->getNode(), IdentifierTypeNode::class);
 
 			foreach ($identifierTypeNodes as $typeHintNode) {
@@ -59,7 +58,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 					'Expected "%s" but found "%s" in %s annotation.',
 					$shortTypeHint,
 					$typeHint,
-					$annotation->getName()
+					$annotation->getName(),
 				), $annotation->getStartPointer(), self::CODE_USED_LONG_TYPE_HINT);
 
 				if (!$fix) {
@@ -72,7 +71,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 					$parsedDocComment,
 					$annotation,
 					$typeHintNode,
-					new IdentifierTypeNode($shortTypeHint)
+					new IdentifierTypeNode($shortTypeHint),
 				);
 
 				$phpcsFile->fixer->beginChangeset();
@@ -81,7 +80,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 					$phpcsFile,
 					$parsedDocComment->getOpenPointer(),
 					$parsedDocComment->getClosePointer(),
-					$fixedDocComment
+					$fixedDocComment,
 				);
 
 				$phpcsFile->fixer->endChangeset();
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/NullTypeHintOnLastPositionSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/NullTypeHintOnLastPositionSniff.php
index eb7a3a439..c9286c516 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/NullTypeHintOnLastPositionSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/NullTypeHintOnLastPositionSniff.php
@@ -40,7 +40,6 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 		$annotations = AnnotationHelper::getAnnotations($phpcsFile, $docCommentOpenPointer);
 
 		foreach ($annotations as $annotation) {
-			/** @var list $unionTypeNodes */
 			$unionTypeNodes = AnnotationHelper::getAnnotationNodesByType($annotation->getNode(), UnionTypeNode::class);
 
 			foreach ($unionTypeNodes as $unionTypeNode) {
@@ -68,7 +67,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 				$fix = $phpcsFile->addFixableError(
 					sprintf('Null type hint should be on last position in "%s".', AnnotationTypeHelper::print($unionTypeNode)),
 					$annotation->getStartPointer(),
-					self::CODE_NULL_TYPE_HINT_NOT_ON_LAST_POSITION
+					self::CODE_NULL_TYPE_HINT_NOT_ON_LAST_POSITION,
 				);
 
 				if (!$fix) {
@@ -98,7 +97,7 @@ public function process(File $phpcsFile, $docCommentOpenPointer): void
 					$phpcsFile,
 					$parsedDocComment->getOpenPointer(),
 					$parsedDocComment->getClosePointer(),
-					$fixedDocComment
+					$fixedDocComment,
 				);
 
 				$phpcsFile->fixer->endChangeset();
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/NullableTypeForNullDefaultValueSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/NullableTypeForNullDefaultValueSniff.php
index 9d97cb1ea..5c7967b00 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/NullableTypeForNullDefaultValueSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/NullableTypeForNullDefaultValueSniff.php
@@ -4,10 +4,10 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\SuppressHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use SlevomatCodingStandard\Helpers\TypeHintHelper;
-use function array_merge;
 use function in_array;
 use function preg_match;
 use function sprintf;
@@ -32,7 +32,7 @@ class NullableTypeForNullDefaultValueSniff implements Sniff
 	 */
 	public function register(): array
 	{
-		return TokenHelper::$functionTokenCodes;
+		return TokenHelper::FUNCTION_TOKEN_CODES;
 	}
 
 	/**
@@ -49,8 +49,6 @@ public function process(File $phpcsFile, $functionPointer): void
 		$startPointer = $tokens[$functionPointer]['parenthesis_opener'] + 1;
 		$endPointer = $tokens[$functionPointer]['parenthesis_closer'];
 
-		$typeHintTokenCodes = TokenHelper::getOnlyTypeHintTokenCodes();
-
 		for ($i = $startPointer; $i < $endPointer; $i++) {
 			if ($tokens[$i]['code'] !== T_VARIABLE) {
 				continue;
@@ -68,12 +66,12 @@ public function process(File $phpcsFile, $functionPointer): void
 				continue;
 			}
 
-			$ignoreTokensToFindTypeHint = array_merge(TokenHelper::$ineffectiveTokenCodes, [T_BITWISE_AND, T_ELLIPSIS]);
+			$ignoreTokensToFindTypeHint = [...TokenHelper::INEFFECTIVE_TOKEN_CODES, T_BITWISE_AND, T_ELLIPSIS];
 			$typeHintEndPointer = TokenHelper::findPreviousExcluding($phpcsFile, $ignoreTokensToFindTypeHint, $i - 1, $startPointer);
 
 			if (
 				$typeHintEndPointer === null
-				|| !in_array($tokens[$typeHintEndPointer]['code'], $typeHintTokenCodes, true)
+				|| !in_array($tokens[$typeHintEndPointer]['code'], TokenHelper::ONLY_TYPE_HINT_TOKEN_CODES, true)
 			) {
 				continue;
 			}
@@ -89,7 +87,7 @@ public function process(File $phpcsFile, $functionPointer): void
 			$nullableSymbolPointer = TokenHelper::findPreviousEffective(
 				$phpcsFile,
 				$typeHintStartPointer - 1,
-				$tokens[$functionPointer]['parenthesis_opener']
+				$tokens[$functionPointer]['parenthesis_opener'],
 			);
 
 			if ($nullableSymbolPointer !== null && $tokens[$nullableSymbolPointer]['code'] === T_NULLABLE) {
@@ -103,7 +101,7 @@ public function process(File $phpcsFile, $functionPointer): void
 			$fix = $phpcsFile->addFixableError(
 				sprintf('Parameter %s has null default value, but is not marked as nullable.', $parameterName),
 				$i,
-				self::CODE_NULLABILITY_TYPE_MISSING
+				self::CODE_NULLABILITY_TYPE_MISSING,
 			);
 
 			if (!$fix) {
@@ -113,9 +111,9 @@ public function process(File $phpcsFile, $functionPointer): void
 			$phpcsFile->fixer->beginChangeset();
 
 			if (substr_count($typeHint, '|') > 0) {
-				$phpcsFile->fixer->addContent($typeHintEndPointer, '|null');
+				FixerHelper::add($phpcsFile, $typeHintEndPointer, '|null');
 			} else {
-				$phpcsFile->fixer->addContentBefore($typeHintStartPointer, '?');
+				FixerHelper::addBefore($phpcsFile, $typeHintStartPointer, '?');
 			}
 
 			$phpcsFile->fixer->endChangeset();
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/ParameterTypeHintSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/ParameterTypeHintSniff.php
index fa71a58fb..504afb53d 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/ParameterTypeHintSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/ParameterTypeHintSniff.php
@@ -22,6 +22,7 @@
 use SlevomatCodingStandard\Helpers\Annotation;
 use SlevomatCodingStandard\Helpers\AnnotationHelper;
 use SlevomatCodingStandard\Helpers\AnnotationTypeHelper;
+use SlevomatCodingStandard\Helpers\AttributeHelper;
 use SlevomatCodingStandard\Helpers\DocCommentHelper;
 use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\FunctionHelper;
@@ -35,7 +36,7 @@
 use function array_key_exists;
 use function array_keys;
 use function array_map;
-use function array_merge;
+use function array_push;
 use function array_unique;
 use function array_values;
 use function count;
@@ -69,26 +70,21 @@ class ParameterTypeHintSniff implements Sniff
 
 	private const NAME = 'SlevomatCodingStandard.TypeHints.ParameterTypeHint';
 
-	/** @var bool|null */
-	public $enableObjectTypeHint = null;
+	public ?bool $enableObjectTypeHint = null;
 
-	/** @var bool|null */
-	public $enableMixedTypeHint = null;
+	public ?bool $enableMixedTypeHint = null;
 
-	/** @var bool|null */
-	public $enableUnionTypeHint = null;
+	public ?bool $enableUnionTypeHint = null;
 
-	/** @var bool|null */
-	public $enableIntersectionTypeHint = null;
+	public ?bool $enableIntersectionTypeHint = null;
 
-	/** @var bool|null */
-	public $enableStandaloneNullTrueFalseTypeHints = null;
+	public ?bool $enableStandaloneNullTrueFalseTypeHints = null;
 
 	/** @var list */
-	public $traversableTypeHints = [];
+	public array $traversableTypeHints = [];
 
-	/** @var array|null */
-	private $normalizedTraversableTypeHints;
+	/** @var list|null */
+	private ?array $normalizedTraversableTypeHints = null;
 
 	/**
 	 * @return array
@@ -112,7 +108,7 @@ public function process(File $phpcsFile, $functionPointer): void
 		$this->enableIntersectionTypeHint = SniffSettingsHelper::isEnabledByPhpVersion($this->enableIntersectionTypeHint, 80100);
 		$this->enableStandaloneNullTrueFalseTypeHints = SniffSettingsHelper::isEnabledByPhpVersion(
 			$this->enableStandaloneNullTrueFalseTypeHints,
-			80200
+			80200,
 		);
 
 		if (SuppressHelper::isSniffSuppressed($phpcsFile, $functionPointer, self::NAME)) {
@@ -133,7 +129,7 @@ public function process(File $phpcsFile, $functionPointer): void
 			$functionPointer,
 			$parametersTypeHints,
 			$parametersAnnotations,
-			$prefixedParametersAnnotations
+			$prefixedParametersAnnotations,
 		);
 		$this->checkUselessAnnotations($phpcsFile, $functionPointer, $parametersTypeHints, $parametersAnnotations);
 	}
@@ -160,9 +156,7 @@ private function checkTypeHints(
 		$suppressedErrors = 0;
 
 		$parametersWithoutTypeHint = array_keys(
-			array_filter($parametersTypeHints, static function (?TypeHint $parameterTypeHint = null): bool {
-				return $parameterTypeHint === null;
-			})
+			array_filter($parametersTypeHints, static fn (?TypeHint $parameterTypeHint = null): bool => $parameterTypeHint === null),
 		);
 
 		$tokens = $phpcsFile->getTokens();
@@ -179,7 +173,7 @@ private function checkTypeHints(
 					T_VARIABLE,
 					$parameterName,
 					$tokens[$functionPointer]['parenthesis_opener'],
-					$tokens[$functionPointer]['parenthesis_closer']
+					$tokens[$functionPointer]['parenthesis_closer'],
 				);
 
 				$pointerBeforeParameter = TokenHelper::findPrevious($phpcsFile, [T_COMMA, T_OPEN_PARENTHESIS], $parameterPointer - 1);
@@ -207,15 +201,19 @@ private function checkTypeHints(
 						'%s %s() does not have parameter type hint nor @param annotation for its parameter %s.',
 						FunctionHelper::getTypeLabel($phpcsFile, $functionPointer),
 						FunctionHelper::getFullyQualifiedName($phpcsFile, $functionPointer),
-						$parameterName
+						$parameterName,
 					),
 					$functionPointer,
-					self::CODE_MISSING_ANY_TYPE_HINT
+					self::CODE_MISSING_ANY_TYPE_HINT,
 				);
 
 				continue;
 			}
 
+			if (AttributeHelper::hasAttribute($phpcsFile, $functionPointer, '\Override')) {
+				continue;
+			}
+
 			$parameterTypeNode = $parametersAnnotations[$parameterName]->getValue()->type;
 
 			if (
@@ -243,7 +241,7 @@ private function checkTypeHints(
 				$typeHints[] = AnnotationTypeHelper::getTypeHintFromOneType(
 					$parameterTypeNode,
 					false,
-					$this->enableStandaloneNullTrueFalseTypeHints
+					$this->enableStandaloneNullTrueFalseTypeHints,
 				);
 
 			} elseif (
@@ -268,7 +266,7 @@ private function checkTypeHints(
 
 					$isTraversable = TypeHintHelper::isTraversableType(
 						TypeHintHelper::getFullyQualifiedTypeHint($phpcsFile, $functionPointer, $typeHint),
-						$this->getTraversableTypeHints()
+						$this->getTraversableTypeHints(),
 					);
 
 					if (
@@ -301,7 +299,7 @@ private function checkTypeHints(
 						$phpcsFile,
 						$functionPointer,
 						$this->getTraversableTypeHints(),
-						$canTryUnionTypeHint
+						$canTryUnionTypeHint,
 					);
 				}
 			}
@@ -314,9 +312,9 @@ private function checkTypeHints(
 			foreach ($typeHints as $typeHint) {
 				if ($this->enableUnionTypeHint && TypeHintHelper::isUnofficialUnionTypeHint($typeHint)) {
 					$canTryUnionTypeHint = true;
-					$typeHintsWithConvertedUnion = array_merge(
+					array_push(
 						$typeHintsWithConvertedUnion,
-						TypeHintHelper::convertUnofficialUnionTypeHintToOfficialTypeHints($typeHint)
+						...TypeHintHelper::convertUnofficialUnionTypeHintToOfficialTypeHints($typeHint),
 					);
 				} else {
 					$typeHintsWithConvertedUnion[] = $typeHint;
@@ -348,7 +346,7 @@ private function checkTypeHints(
 					$this->enableObjectTypeHint,
 					false,
 					$this->enableMixedTypeHint,
-					$this->enableStandaloneNullTrueFalseTypeHints
+					$this->enableStandaloneNullTrueFalseTypeHints,
 				)) {
 					continue 2;
 				}
@@ -375,10 +373,10 @@ private function checkTypeHints(
 					FunctionHelper::getTypeLabel($phpcsFile, $functionPointer),
 					FunctionHelper::getFullyQualifiedName($phpcsFile, $functionPointer),
 					$parameterName,
-					AnnotationTypeHelper::print($parameterTypeNode)
+					AnnotationTypeHelper::print($parameterTypeNode),
 				),
 				$functionPointer,
-				self::CODE_MISSING_NATIVE_TYPE_HINT
+				self::CODE_MISSING_NATIVE_TYPE_HINT,
 			);
 			if (!$fix) {
 				continue;
@@ -406,7 +404,7 @@ private function checkTypeHints(
 				T_VARIABLE,
 				$parameterName,
 				$tokens[$functionPointer]['parenthesis_opener'],
-				$tokens[$functionPointer]['parenthesis_closer']
+				$tokens[$functionPointer]['parenthesis_closer'],
 			);
 
 			$beforeParameterPointer = $parameterPointer;
@@ -414,7 +412,7 @@ private function checkTypeHints(
 				$previousPointer = TokenHelper::findPreviousEffective(
 					$phpcsFile,
 					$beforeParameterPointer - 1,
-					$tokens[$functionPointer]['parenthesis_opener'] + 1
+					$tokens[$functionPointer]['parenthesis_opener'] + 1,
 				);
 				if (
 					$previousPointer === null
@@ -428,9 +426,10 @@ private function checkTypeHints(
 			} while (true);
 
 			$phpcsFile->fixer->beginChangeset();
-			$phpcsFile->fixer->addContentBefore(
+			FixerHelper::addBefore(
+				$phpcsFile,
 				$beforeParameterPointer,
-				sprintf('%s ', $parameterTypeHint)
+				sprintf('%s ', $parameterTypeHint),
 			);
 			$phpcsFile->fixer->endChangeset();
 		}
@@ -475,7 +474,7 @@ private function checkTraversableTypeHintSpecification(
 				$parameterTypeHint !== null
 				&& TypeHintHelper::isTraversableType(
 					TypeHintHelper::getFullyQualifiedTypeHint($phpcsFile, $functionPointer, $parameterTypeHint->getTypeHint()),
-					$this->getTraversableTypeHints()
+					$this->getTraversableTypeHints(),
 				)
 			) {
 				$hasTraversableTypeHint = true;
@@ -486,7 +485,7 @@ private function checkTraversableTypeHintSpecification(
 					$parametersAnnotations[$parameterName]->getValue()->type,
 					$phpcsFile,
 					$functionPointer,
-					$this->getTraversableTypeHints()
+					$this->getTraversableTypeHints(),
 				)
 			) {
 				$hasTraversableTypeHint = true;
@@ -501,10 +500,10 @@ private function checkTraversableTypeHintSpecification(
 							'%s %s() does not have @param annotation for its traversable parameter %s.',
 							FunctionHelper::getTypeLabel($phpcsFile, $functionPointer),
 							FunctionHelper::getFullyQualifiedName($phpcsFile, $functionPointer),
-							$parameterName
+							$parameterName,
 						),
 						$functionPointer,
-						self::CODE_MISSING_TRAVERSABLE_TYPE_HINT_SPECIFICATION
+						self::CODE_MISSING_TRAVERSABLE_TYPE_HINT_SPECIFICATION,
 					);
 				}
 
@@ -528,14 +527,14 @@ private function checkTraversableTypeHintSpecification(
 						$parameterTypeNode,
 						$phpcsFile,
 						$functionPointer,
-						$this->getTraversableTypeHints()
+						$this->getTraversableTypeHints(),
 					)
 				)
 				|| AnnotationTypeHelper::containsItemsSpecificationForTraversable(
 					$parameterTypeNode,
 					$phpcsFile,
 					$functionPointer,
-					$this->getTraversableTypeHints()
+					$this->getTraversableTypeHints(),
 				)
 			) {
 				continue;
@@ -552,10 +551,10 @@ private function checkTraversableTypeHintSpecification(
 					'@param annotation of %s %s() does not specify type hint for items of its traversable parameter %s.',
 					lcfirst(FunctionHelper::getTypeLabel($phpcsFile, $functionPointer)),
 					FunctionHelper::getFullyQualifiedName($phpcsFile, $functionPointer),
-					$parameterName
+					$parameterName,
 				),
 				$parametersAnnotations[$parameterName]->getStartPointer(),
-				self::CODE_MISSING_TRAVERSABLE_TYPE_HINT_SPECIFICATION
+				self::CODE_MISSING_TRAVERSABLE_TYPE_HINT_SPECIFICATION,
 			);
 		}
 
@@ -598,7 +597,7 @@ private function checkUselessAnnotations(
 				$this->getTraversableTypeHints(),
 				$this->enableUnionTypeHint,
 				$this->enableIntersectionTypeHint,
-				$this->enableStandaloneNullTrueFalseTypeHints
+				$this->enableStandaloneNullTrueFalseTypeHints,
 			)) {
 				continue;
 			}
@@ -614,10 +613,10 @@ private function checkUselessAnnotations(
 					'%s %s() has useless @param annotation for parameter %s.',
 					FunctionHelper::getTypeLabel($phpcsFile, $functionPointer),
 					FunctionHelper::getFullyQualifiedName($phpcsFile, $functionPointer),
-					$parameterName
+					$parameterName,
 				),
 				$parameterAnnotation->getStartPointer(),
-				self::CODE_USELESS_ANNOTATION
+				self::CODE_USELESS_ANNOTATION,
 			);
 			if (!$fix) {
 				continue;
@@ -631,7 +630,7 @@ private function checkUselessAnnotations(
 				$phpcsFile,
 				T_DOC_COMMENT_STAR,
 				$parameterAnnotation->getStartPointer() - 1,
-				$docCommentOpenPointer
+				$docCommentOpenPointer,
 			);
 
 			$changeStart = $starPointer ?? $parameterAnnotation->getStartPointer();
@@ -639,7 +638,7 @@ private function checkUselessAnnotations(
 			$changeEnd = TokenHelper::findNext(
 				$phpcsFile,
 				[T_DOC_COMMENT_CLOSE_TAG, T_DOC_COMMENT_STAR],
-				$parameterAnnotation->getEndPointer()
+				$parameterAnnotation->getEndPointer(),
 			) - 1;
 
 			$phpcsFile->fixer->beginChangeset();
@@ -657,7 +656,7 @@ private function reportUselessSuppress(File $phpcsFile, int $pointer, string $su
 		$fix = $phpcsFile->addFixableError(
 			sprintf('Useless %s %s', SuppressHelper::ANNOTATION, $suppressName),
 			$pointer,
-			self::CODE_USELESS_SUPPRESS
+			self::CODE_USELESS_SUPPRESS,
 		);
 
 		if ($fix) {
@@ -676,11 +675,12 @@ private function getSniffName(string $sniffName): string
 	private function getTraversableTypeHints(): array
 	{
 		if ($this->normalizedTraversableTypeHints === null) {
-			$this->normalizedTraversableTypeHints = array_map(static function (string $typeHint): string {
-				return NamespaceHelper::isFullyQualifiedName($typeHint)
-					? $typeHint
-					: sprintf('%s%s', NamespaceHelper::NAMESPACE_SEPARATOR, $typeHint);
-			}, SniffSettingsHelper::normalizeArray($this->traversableTypeHints));
+			$this->normalizedTraversableTypeHints = array_map(
+				static fn (string $typeHint): string => NamespaceHelper::isFullyQualifiedName($typeHint)
+						? $typeHint
+						: sprintf('%s%s', NamespaceHelper::NAMESPACE_SEPARATOR, $typeHint),
+				SniffSettingsHelper::normalizeArray($this->traversableTypeHints),
+			);
 		}
 		return $this->normalizedTraversableTypeHints;
 	}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/ParameterTypeHintSpacingSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/ParameterTypeHintSpacingSniff.php
index 69beededb..a1901b0fa 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/ParameterTypeHintSpacingSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/ParameterTypeHintSpacingSniff.php
@@ -4,6 +4,7 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use SlevomatCodingStandard\Helpers\TypeHintHelper;
 use function array_keys;
@@ -30,7 +31,7 @@ class ParameterTypeHintSpacingSniff implements Sniff
 	 */
 	public function register(): array
 	{
-		return TokenHelper::$functionTokenCodes;
+		return TokenHelper::FUNCTION_TOKEN_CODES;
 	}
 
 	/**
@@ -44,8 +45,6 @@ public function process(File $phpcsFile, $functionPointer): void
 		$parametersStartPointer = $tokens[$functionPointer]['parenthesis_opener'] + 1;
 		$parametersEndPointer = $tokens[$functionPointer]['parenthesis_closer'] - 1;
 
-		$typeHintTokenCodes = TokenHelper::getTypeHintTokenCodes();
-
 		for ($i = $parametersStartPointer; $i <= $parametersEndPointer; $i++) {
 			if ($tokens[$i]['code'] !== T_VARIABLE) {
 				continue;
@@ -68,9 +67,9 @@ public function process(File $phpcsFile, $functionPointer): void
 
 			$typeHintEndPointer = TokenHelper::findPrevious(
 				$phpcsFile,
-				$typeHintTokenCodes,
+				TokenHelper::TYPE_HINT_TOKEN_CODES,
 				$parameterPointer - 1,
-				$attributeCloserPointer ?? $parameterStartPointer
+				$attributeCloserPointer ?? $parameterStartPointer,
 			);
 			if ($typeHintEndPointer === null) {
 				continue;
@@ -87,35 +86,35 @@ public function process(File $phpcsFile, $functionPointer): void
 				$phpcsFile,
 				array_keys($nextTokenNames),
 				$typeHintEndPointer + 1,
-				$parameterEndPointer + 1
+				$parameterEndPointer + 1,
 			);
 
 			if ($tokens[$typeHintEndPointer + 1]['code'] !== T_WHITESPACE) {
 				$fix = $phpcsFile->addFixableError(
 					sprintf(
 						'There must be exactly one space between parameter type hint and %s.',
-						$nextTokenNames[$tokens[$nextTokenPointer]['code']]
+						$nextTokenNames[$tokens[$nextTokenPointer]['code']],
 					),
 					$typeHintEndPointer,
-					self::CODE_NO_SPACE_BETWEEN_TYPE_HINT_AND_PARAMETER
+					self::CODE_NO_SPACE_BETWEEN_TYPE_HINT_AND_PARAMETER,
 				);
 				if ($fix) {
 					$phpcsFile->fixer->beginChangeset();
-					$phpcsFile->fixer->addContent($typeHintEndPointer, ' ');
+					FixerHelper::add($phpcsFile, $typeHintEndPointer, ' ');
 					$phpcsFile->fixer->endChangeset();
 				}
 			} elseif ($tokens[$typeHintEndPointer + 1]['content'] !== ' ') {
 				$fix = $phpcsFile->addFixableError(
 					sprintf(
 						'There must be exactly one space between parameter type hint and %s.',
-						$nextTokenNames[$tokens[$nextTokenPointer]['code']]
+						$nextTokenNames[$tokens[$nextTokenPointer]['code']],
 					),
 					$typeHintEndPointer,
-					self::CODE_MULTIPLE_SPACES_BETWEEN_TYPE_HINT_AND_PARAMETER
+					self::CODE_MULTIPLE_SPACES_BETWEEN_TYPE_HINT_AND_PARAMETER,
 				);
 				if ($fix) {
 					$phpcsFile->fixer->beginChangeset();
-					$phpcsFile->fixer->replaceToken($typeHintEndPointer + 1, ' ');
+					FixerHelper::replace($phpcsFile, $typeHintEndPointer + 1, ' ');
 					$phpcsFile->fixer->endChangeset();
 				}
 			}
@@ -136,17 +135,17 @@ public function process(File $phpcsFile, $functionPointer): void
 			$fix = $phpcsFile->addFixableError(
 				sprintf(
 					'There must be no whitespace between parameter type hint nullability symbol and parameter type hint of parameter %s.',
-					$parameterName
+					$parameterName,
 				),
 				$typeHintStartPointer,
-				self::CODE_WHITESPACE_AFTER_NULLABILITY_SYMBOL
+				self::CODE_WHITESPACE_AFTER_NULLABILITY_SYMBOL,
 			);
 			if (!$fix) {
 				continue;
 			}
 
 			$phpcsFile->fixer->beginChangeset();
-			$phpcsFile->fixer->replaceToken($nullabilitySymbolPointer + 1, '');
+			FixerHelper::replace($phpcsFile, $nullabilitySymbolPointer + 1, '');
 			$phpcsFile->fixer->endChangeset();
 		}
 	}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/PropertyTypeHintSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/PropertyTypeHintSniff.php
index 82a100fdd..bdf33fa5e 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/PropertyTypeHintSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/PropertyTypeHintSniff.php
@@ -29,7 +29,7 @@
 use SlevomatCodingStandard\Helpers\TypeHint;
 use SlevomatCodingStandard\Helpers\TypeHintHelper;
 use function array_map;
-use function array_merge;
+use function array_push;
 use function array_unique;
 use function array_values;
 use function count;
@@ -43,11 +43,11 @@
 use const T_CONST;
 use const T_DOC_COMMENT_CLOSE_TAG;
 use const T_DOC_COMMENT_STAR;
+use const T_FINAL;
 use const T_FUNCTION;
 use const T_PRIVATE;
 use const T_PROTECTED;
 use const T_PUBLIC;
-use const T_READONLY;
 use const T_SEMICOLON;
 use const T_STATIC;
 use const T_VAR;
@@ -68,38 +68,35 @@ class PropertyTypeHintSniff implements Sniff
 
 	private const NAME = 'SlevomatCodingStandard.TypeHints.PropertyTypeHint';
 
-	/** @var bool|null */
-	public $enableNativeTypeHint = null;
+	public ?bool $enableNativeTypeHint = null;
 
-	/** @var bool|null */
-	public $enableMixedTypeHint = null;
+	public ?bool $enableMixedTypeHint = null;
 
-	/** @var bool|null */
-	public $enableUnionTypeHint = null;
+	public ?bool $enableUnionTypeHint = null;
 
-	/** @var bool|null */
-	public $enableIntersectionTypeHint = null;
+	public ?bool $enableIntersectionTypeHint = null;
 
-	/** @var bool|null */
-	public $enableStandaloneNullTrueFalseTypeHints = null;
+	public ?bool $enableStandaloneNullTrueFalseTypeHints = null;
 
 	/** @var list */
-	public $traversableTypeHints = [];
+	public array $traversableTypeHints = [];
 
-	/** @var array|null */
-	private $normalizedTraversableTypeHints;
+	/** @var list|null */
+	private ?array $normalizedTraversableTypeHints = null;
 
 	/**
 	 * @return array
 	 */
 	public function register(): array
 	{
+		// Other modifiers cannot be used without type hint
 		return [
 			T_VAR,
 			T_PUBLIC,
 			T_PROTECTED,
 			T_PRIVATE,
 			T_STATIC,
+			T_FINAL,
 		];
 	}
 
@@ -131,8 +128,8 @@ public function process(File $phpcsFile, $pointer): void
 		}
 
 		$nextPointer = TokenHelper::findNextEffective($phpcsFile, $pointer + 1);
-		if (in_array($tokens[$nextPointer]['code'], [T_VAR, T_PUBLIC, T_PROTECTED, T_PRIVATE, T_READONLY, T_STATIC], true)) {
-			// We don't want to report the same property twice
+		if (in_array($tokens[$nextPointer]['code'], TokenHelper::PROPERTY_MODIFIERS_TOKEN_CODES, true)) {
+			// We don't want to report the same property multiple times
 			return;
 		}
 
@@ -173,7 +170,7 @@ public function process(File $phpcsFile, $pointer): void
 			$propertyPointer,
 			$propertyTypeHint,
 			$propertyAnnotation,
-			$prefixedPropertyAnnotations
+			$prefixedPropertyAnnotations,
 		);
 		$this->checkUselessAnnotation($phpcsFile, $propertyPointer, $propertyTypeHint, $propertyAnnotation);
 	}
@@ -214,10 +211,10 @@ private function checkTypeHint(
 						$this->enableNativeTypeHint
 							? 'Property %s does not have native type hint nor @var annotation for its value.'
 							: 'Property %s does not have @var annotation for its value.',
-						PropertyHelper::getFullyQualifiedName($phpcsFile, $propertyPointer)
+						PropertyHelper::getFullyQualifiedName($phpcsFile, $propertyPointer),
 					),
 					$propertyPointer,
-					self::CODE_MISSING_ANY_TYPE_HINT
+					self::CODE_MISSING_ANY_TYPE_HINT,
 				);
 			}
 
@@ -265,7 +262,7 @@ private function checkTypeHint(
 
 				$isTraversable = TypeHintHelper::isTraversableType(
 					TypeHintHelper::getFullyQualifiedTypeHint($phpcsFile, $propertyPointer, $typeHint),
-					$this->getTraversableTypeHints()
+					$this->getTraversableTypeHints(),
 				);
 
 				if (
@@ -299,7 +296,7 @@ private function checkTypeHint(
 					$phpcsFile,
 					$propertyPointer,
 					$this->getTraversableTypeHints(),
-					$this->enableUnionTypeHint
+					$this->enableUnionTypeHint,
 				);
 			}
 		}
@@ -313,10 +310,7 @@ private function checkTypeHint(
 		foreach ($typeHints as $typeHint) {
 			if ($this->enableUnionTypeHint && TypeHintHelper::isUnofficialUnionTypeHint($typeHint)) {
 				$canTryUnionTypeHint = true;
-				$typeHintsWithConvertedUnion = array_merge(
-					$typeHintsWithConvertedUnion,
-					TypeHintHelper::convertUnofficialUnionTypeHintToOfficialTypeHints($typeHint)
-				);
+				array_push($typeHintsWithConvertedUnion, ...TypeHintHelper::convertUnofficialUnionTypeHintToOfficialTypeHints($typeHint));
 			} else {
 				$typeHintsWithConvertedUnion[] = $typeHint;
 			}
@@ -349,7 +343,7 @@ private function checkTypeHint(
 				true,
 				false,
 				$this->enableMixedTypeHint,
-				$this->enableStandaloneNullTrueFalseTypeHints
+				$this->enableStandaloneNullTrueFalseTypeHints,
 			)) {
 				$this->reportUselessSuppress($phpcsFile, $propertyPointer, $isSuppressedNativeTypeHint, $suppressNameNativeTypeHint);
 				return;
@@ -375,10 +369,10 @@ private function checkTypeHint(
 			sprintf(
 				'Property %s does not have native type hint for its value but it should be possible to add it based on @var annotation "%s".',
 				PropertyHelper::getFullyQualifiedName($phpcsFile, $propertyPointer),
-				AnnotationTypeHelper::print($typeNode)
+				AnnotationTypeHelper::print($typeNode),
 			),
 			$propertyPointer,
-			self::CODE_MISSING_NATIVE_TYPE_HINT
+			self::CODE_MISSING_NATIVE_TYPE_HINT,
 		);
 		if (!$fix) {
 			return;
@@ -399,12 +393,6 @@ private function checkTypeHint(
 			}
 		}
 
-		$propertyStartPointer = TokenHelper::findPrevious(
-			$phpcsFile,
-			[T_PRIVATE, T_PROTECTED, T_PUBLIC, T_VAR, T_STATIC, T_READONLY],
-			$propertyPointer - 1
-		);
-
 		$tokens = $phpcsFile->getTokens();
 
 		$pointerAfterProperty = null;
@@ -413,13 +401,13 @@ private function checkTypeHint(
 		}
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->addContent($propertyStartPointer, sprintf(' %s', $propertyTypeHint));
+		FixerHelper::addBefore($phpcsFile, $propertyPointer, sprintf('%s ', $propertyTypeHint));
 
 		if (
 			$pointerAfterProperty !== null
 			&& in_array($tokens[$pointerAfterProperty]['code'], [T_SEMICOLON, T_COMMA], true)
 		) {
-			$phpcsFile->fixer->addContent($propertyPointer, ' = null');
+			FixerHelper::add($phpcsFile, $propertyPointer, ' = null');
 		}
 
 		$phpcsFile->fixer->endChangeset();
@@ -454,10 +442,10 @@ private function checkTraversableTypeHintSpecification(
 					$phpcsFile->addError(
 						sprintf(
 							'@var annotation of property %s does not specify type hint for its items.',
-							PropertyHelper::getFullyQualifiedName($phpcsFile, $propertyPointer)
+							PropertyHelper::getFullyQualifiedName($phpcsFile, $propertyPointer),
 						),
 						$propertyPointer,
-						self::CODE_MISSING_TRAVERSABLE_TYPE_HINT_SPECIFICATION
+						self::CODE_MISSING_TRAVERSABLE_TYPE_HINT_SPECIFICATION,
 					);
 				}
 			}
@@ -479,7 +467,7 @@ private function checkTraversableTypeHintSpecification(
 			$typeNode,
 			$phpcsFile,
 			$propertyPointer,
-			$this->getTraversableTypeHints()
+			$this->getTraversableTypeHints(),
 		)) {
 			$this->reportUselessSuppress($phpcsFile, $propertyPointer, $isSuppressed, $suppressName);
 			return;
@@ -492,10 +480,10 @@ private function checkTraversableTypeHintSpecification(
 		$phpcsFile->addError(
 			sprintf(
 				'@var annotation of property %s does not specify type hint for its items.',
-				PropertyHelper::getFullyQualifiedName($phpcsFile, $propertyPointer)
+				PropertyHelper::getFullyQualifiedName($phpcsFile, $propertyPointer),
 			),
 			$propertyAnnotation->getStartPointer(),
-			self::CODE_MISSING_TRAVERSABLE_TYPE_HINT_SPECIFICATION
+			self::CODE_MISSING_TRAVERSABLE_TYPE_HINT_SPECIFICATION,
 		);
 	}
 
@@ -521,7 +509,7 @@ private function checkUselessAnnotation(
 			$this->getTraversableTypeHints(),
 			$this->enableUnionTypeHint,
 			$this->enableIntersectionTypeHint,
-			$this->enableStandaloneNullTrueFalseTypeHints
+			$this->enableStandaloneNullTrueFalseTypeHints,
 		)) {
 			$this->reportUselessSuppress($phpcsFile, $propertyPointer, $isSuppressed, $suppressName);
 			return;
@@ -534,10 +522,10 @@ private function checkUselessAnnotation(
 		$fix = $phpcsFile->addFixableError(
 			sprintf(
 				'Property %s has useless @var annotation.',
-				PropertyHelper::getFullyQualifiedName($phpcsFile, $propertyPointer)
+				PropertyHelper::getFullyQualifiedName($phpcsFile, $propertyPointer),
 			),
 			$propertyAnnotation->getStartPointer(),
-			self::CODE_USELESS_ANNOTATION
+			self::CODE_USELESS_ANNOTATION,
 		);
 
 		if (!$fix) {
@@ -566,7 +554,7 @@ private function checkUselessAnnotation(
 		$changeEnd = TokenHelper::findNext(
 			$phpcsFile,
 			[T_DOC_COMMENT_CLOSE_TAG, T_DOC_COMMENT_STAR],
-			$propertyAnnotation->getEndPointer() + 1
+			$propertyAnnotation->getEndPointer() + 1,
 		) - 1;
 
 		$phpcsFile->fixer->beginChangeset();
@@ -598,7 +586,7 @@ private function reportUselessSuppress(File $phpcsFile, int $pointer, bool $isSu
 		$fix = $phpcsFile->addFixableError(
 			sprintf('Useless %s %s', SuppressHelper::ANNOTATION, $suppressName),
 			$pointer,
-			self::CODE_USELESS_SUPPRESS
+			self::CODE_USELESS_SUPPRESS,
 		);
 
 		if ($fix) {
@@ -617,11 +605,12 @@ private function getSniffName(string $sniffName): string
 	private function getTraversableTypeHints(): array
 	{
 		if ($this->normalizedTraversableTypeHints === null) {
-			$this->normalizedTraversableTypeHints = array_map(static function (string $typeHint): string {
-				return NamespaceHelper::isFullyQualifiedName($typeHint)
-					? $typeHint
-					: sprintf('%s%s', NamespaceHelper::NAMESPACE_SEPARATOR, $typeHint);
-			}, SniffSettingsHelper::normalizeArray($this->traversableTypeHints));
+			$this->normalizedTraversableTypeHints = array_map(
+				static fn (string $typeHint): string => NamespaceHelper::isFullyQualifiedName($typeHint)
+						? $typeHint
+						: sprintf('%s%s', NamespaceHelper::NAMESPACE_SEPARATOR, $typeHint),
+				SniffSettingsHelper::normalizeArray($this->traversableTypeHints),
+			);
 		}
 		return $this->normalizedTraversableTypeHints;
 	}
@@ -647,9 +636,9 @@ private function hasTraversableTypeHint(
 				TypeHintHelper::getFullyQualifiedTypeHint(
 					$phpcsFile,
 					$propertyPointer,
-					$propertyTypeHint->getTypeHintWithoutNullabilitySymbol()
+					$propertyTypeHint->getTypeHintWithoutNullabilitySymbol(),
 				),
-				$this->getTraversableTypeHints()
+				$this->getTraversableTypeHints(),
 			)
 		) {
 			return true;
@@ -661,7 +650,7 @@ private function hasTraversableTypeHint(
 				$propertyAnnotation->getValue()->type,
 				$phpcsFile,
 				$propertyPointer,
-				$this->getTraversableTypeHints()
+				$this->getTraversableTypeHints(),
 			);
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/ReturnTypeHintSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/ReturnTypeHintSniff.php
index 594dc77f7..bde658758 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/ReturnTypeHintSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/ReturnTypeHintSniff.php
@@ -30,7 +30,7 @@
 use SlevomatCodingStandard\Helpers\TypeHintHelper;
 use function array_key_exists;
 use function array_map;
-use function array_merge;
+use function array_push;
 use function array_unique;
 use function array_values;
 use function count;
@@ -61,32 +61,25 @@ class ReturnTypeHintSniff implements Sniff
 
 	private const NAME = 'SlevomatCodingStandard.TypeHints.ReturnTypeHint';
 
-	/** @var bool|null */
-	public $enableObjectTypeHint = null;
+	public ?bool $enableObjectTypeHint = null;
 
-	/** @var bool|null */
-	public $enableStaticTypeHint = null;
+	public ?bool $enableStaticTypeHint = null;
 
-	/** @var bool|null */
-	public $enableMixedTypeHint = null;
+	public ?bool $enableMixedTypeHint = null;
 
-	/** @var bool|null */
-	public $enableUnionTypeHint = null;
+	public ?bool $enableUnionTypeHint = null;
 
-	/** @var bool|null */
-	public $enableIntersectionTypeHint = null;
+	public ?bool $enableIntersectionTypeHint = null;
 
-	/** @var bool|null */
-	public $enableNeverTypeHint = null;
+	public ?bool $enableNeverTypeHint = null;
 
-	/** @var bool|null */
-	public $enableStandaloneNullTrueFalseTypeHints = null;
+	public ?bool $enableStandaloneNullTrueFalseTypeHints = null;
 
 	/** @var list */
-	public $traversableTypeHints = [];
+	public array $traversableTypeHints = [];
 
-	/** @var array|null */
-	private $normalizedTraversableTypeHints;
+	/** @var list|null */
+	private ?array $normalizedTraversableTypeHints = null;
 
 	/**
 	 * @return array
@@ -113,7 +106,7 @@ public function process(File $phpcsFile, $pointer): void
 		$this->enableNeverTypeHint = SniffSettingsHelper::isEnabledByPhpVersion($this->enableNeverTypeHint, 80100);
 		$this->enableStandaloneNullTrueFalseTypeHints = SniffSettingsHelper::isEnabledByPhpVersion(
 			$this->enableStandaloneNullTrueFalseTypeHints,
-			80200
+			80200,
 		);
 
 		if (SuppressHelper::isSniffSuppressed($phpcsFile, $pointer, self::NAME)) {
@@ -137,7 +130,7 @@ public function process(File $phpcsFile, $pointer): void
 				$pointer,
 				$returnTypeHint,
 				$returnAnnotation,
-				$prefixedReturnAnnotations
+				$prefixedReturnAnnotations,
 			);
 			$this->checkFunctionUselessAnnotation($phpcsFile, $pointer, $returnTypeHint, $returnAnnotation);
 		} elseif ($token['code'] === T_CLOSURE) {
@@ -177,15 +170,15 @@ private function checkFunctionTypeHint(
 						'%s %s() has return type hint "void" but it should be possible to add "never" based on @return annotation "%s".',
 						FunctionHelper::getTypeLabel($phpcsFile, $functionPointer),
 						FunctionHelper::getFullyQualifiedName($phpcsFile, $functionPointer),
-						AnnotationTypeHelper::print($returnTypeNode)
+						AnnotationTypeHelper::print($returnTypeNode),
 					),
 					$functionPointer,
-					self::CODE_LESS_SPECIFIC_NATIVE_TYPE_HINT
+					self::CODE_LESS_SPECIFIC_NATIVE_TYPE_HINT,
 				);
 
 				if ($fix) {
 					$phpcsFile->fixer->beginChangeset();
-					$phpcsFile->fixer->replaceToken($returnTypeHint->getStartPointer(), 'never');
+					FixerHelper::replace($phpcsFile, $returnTypeHint->getStartPointer(), 'never');
 					$phpcsFile->fixer->endChangeset();
 				}
 			}
@@ -223,10 +216,10 @@ private function checkFunctionTypeHint(
 					sprintf(
 						'%s %s() does not have return type hint nor @return annotation for its return value.',
 						FunctionHelper::getTypeLabel($phpcsFile, $functionPointer),
-						FunctionHelper::getFullyQualifiedName($phpcsFile, $functionPointer)
+						FunctionHelper::getFullyQualifiedName($phpcsFile, $functionPointer),
 					),
 					$functionPointer,
-					self::CODE_MISSING_ANY_TYPE_HINT
+					self::CODE_MISSING_ANY_TYPE_HINT,
 				);
 			}
 
@@ -245,13 +238,13 @@ private function checkFunctionTypeHint(
 					? sprintf(
 						'%s %s() does not have void return type hint.',
 						FunctionHelper::getTypeLabel($phpcsFile, $functionPointer),
-						FunctionHelper::getFullyQualifiedName($phpcsFile, $functionPointer)
+						FunctionHelper::getFullyQualifiedName($phpcsFile, $functionPointer),
 					)
 					: sprintf(
 						'%s %s() does not have native return type hint for its return value but it should be possible to add it based on @return annotation "%s".',
 						FunctionHelper::getTypeLabel($phpcsFile, $functionPointer),
 						FunctionHelper::getFullyQualifiedName($phpcsFile, $functionPointer),
-						AnnotationTypeHelper::print($returnTypeNode)
+						AnnotationTypeHelper::print($returnTypeNode),
 					);
 
 				$fix = $phpcsFile->addFixableError($message, $functionPointer, self::getSniffName(self::CODE_MISSING_NATIVE_TYPE_HINT));
@@ -262,9 +255,10 @@ private function checkFunctionTypeHint(
 						: 'void';
 
 					$phpcsFile->fixer->beginChangeset();
-					$phpcsFile->fixer->addContent(
+					FixerHelper::add(
+						$phpcsFile,
 						$phpcsFile->getTokens()[$functionPointer]['parenthesis_closer'],
-						sprintf(': %s', $fixedReturnType)
+						sprintf(': %s', $fixedReturnType),
 					);
 					$phpcsFile->fixer->endChangeset();
 				}
@@ -278,7 +272,7 @@ private function checkFunctionTypeHint(
 				'%s %s() does not have native return type hint for its return value but it should be possible to add it based on @return annotation "%s".',
 				FunctionHelper::getTypeLabel($phpcsFile, $functionPointer),
 				FunctionHelper::getFullyQualifiedName($phpcsFile, $functionPointer),
-				AnnotationTypeHelper::print($returnTypeNode)
+				AnnotationTypeHelper::print($returnTypeNode),
 			);
 
 			$phpcsFile->addError($message, $functionPointer, self::getSniffName(self::CODE_MISSING_NATIVE_TYPE_HINT));
@@ -302,7 +296,7 @@ private function checkFunctionTypeHint(
 			$typeHints[] = AnnotationTypeHelper::getTypeHintFromOneType(
 				$returnTypeNode,
 				false,
-				$this->enableStandaloneNullTrueFalseTypeHints
+				$this->enableStandaloneNullTrueFalseTypeHints,
 			);
 
 		} elseif ($returnTypeNode instanceof UnionTypeNode || $returnTypeNode instanceof IntersectionTypeNode) {
@@ -325,7 +319,7 @@ private function checkFunctionTypeHint(
 
 				$isTraversable = TypeHintHelper::isTraversableType(
 					TypeHintHelper::getFullyQualifiedTypeHint($phpcsFile, $functionPointer, $typeHint),
-					$this->getTraversableTypeHints()
+					$this->getTraversableTypeHints(),
 				);
 
 				if (
@@ -359,7 +353,7 @@ private function checkFunctionTypeHint(
 					$phpcsFile,
 					$functionPointer,
 					$this->getTraversableTypeHints(),
-					$canTryUnionTypeHint
+					$canTryUnionTypeHint,
 				);
 			}
 		}
@@ -373,10 +367,7 @@ private function checkFunctionTypeHint(
 		foreach ($typeHints as $typeHint) {
 			if ($this->enableUnionTypeHint && TypeHintHelper::isUnofficialUnionTypeHint($typeHint)) {
 				$canTryUnionTypeHint = true;
-				$typeHintsWithConvertedUnion = array_merge(
-					$typeHintsWithConvertedUnion,
-					TypeHintHelper::convertUnofficialUnionTypeHintToOfficialTypeHints($typeHint)
-				);
+				array_push($typeHintsWithConvertedUnion, ...TypeHintHelper::convertUnofficialUnionTypeHintToOfficialTypeHints($typeHint));
 			} else {
 				$typeHintsWithConvertedUnion[] = $typeHint;
 			}
@@ -404,7 +395,7 @@ private function checkFunctionTypeHint(
 				$this->enableObjectTypeHint,
 				$this->enableStaticTypeHint,
 				$this->enableMixedTypeHint,
-				$this->enableStandaloneNullTrueFalseTypeHints
+				$this->enableStandaloneNullTrueFalseTypeHints,
 			)) {
 				$this->reportUselessSuppress($phpcsFile, $functionPointer, $isSuppressedNativeTypeHint, $suppressNameNativeTypeHint);
 				return;
@@ -433,10 +424,10 @@ private function checkFunctionTypeHint(
 				'%s %s() does not have native return type hint for its return value but it should be possible to add it based on @return annotation "%s".',
 				FunctionHelper::getTypeLabel($phpcsFile, $functionPointer),
 				FunctionHelper::getFullyQualifiedName($phpcsFile, $functionPointer),
-				AnnotationTypeHelper::print($returnTypeNode)
+				AnnotationTypeHelper::print($returnTypeNode),
 			),
 			$functionPointer,
-			self::CODE_MISSING_NATIVE_TYPE_HINT
+			self::CODE_MISSING_NATIVE_TYPE_HINT,
 		);
 		if (!$fix) {
 			return;
@@ -458,9 +449,10 @@ private function checkFunctionTypeHint(
 		}
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->addContent(
+		FixerHelper::add(
+			$phpcsFile,
 			$phpcsFile->getTokens()[$functionPointer]['parenthesis_closer'],
-			sprintf(': %s', $returnTypeHint)
+			sprintf(': %s', $returnTypeHint),
 		);
 		$phpcsFile->fixer->endChangeset();
 	}
@@ -494,10 +486,10 @@ private function checkFunctionTraversableTypeHintSpecification(
 						sprintf(
 							'%s %s() does not have @return annotation for its traversable return value.',
 							FunctionHelper::getTypeLabel($phpcsFile, $functionPointer),
-							FunctionHelper::getFullyQualifiedName($phpcsFile, $functionPointer)
+							FunctionHelper::getFullyQualifiedName($phpcsFile, $functionPointer),
 						),
 						$functionPointer,
-						self::CODE_MISSING_TRAVERSABLE_TYPE_HINT_SPECIFICATION
+						self::CODE_MISSING_TRAVERSABLE_TYPE_HINT_SPECIFICATION,
 					);
 				}
 			}
@@ -513,7 +505,7 @@ private function checkFunctionTraversableTypeHintSpecification(
 				$returnTypeNode,
 				$phpcsFile,
 				$functionPointer,
-				$this->getTraversableTypeHints()
+				$this->getTraversableTypeHints(),
 			)
 		) {
 			$this->reportUselessSuppress($phpcsFile, $functionPointer, $isSuppressed, $suppressName);
@@ -524,7 +516,7 @@ private function checkFunctionTraversableTypeHintSpecification(
 			$returnTypeNode,
 			$phpcsFile,
 			$functionPointer,
-			$this->getTraversableTypeHints()
+			$this->getTraversableTypeHints(),
 		)) {
 			$this->reportUselessSuppress($phpcsFile, $functionPointer, $isSuppressed, $suppressName);
 			return;
@@ -541,10 +533,10 @@ private function checkFunctionTraversableTypeHintSpecification(
 			sprintf(
 				'@return annotation of %s %s() does not specify type hint for items of its traversable return value.',
 				lcfirst(FunctionHelper::getTypeLabel($phpcsFile, $functionPointer)),
-				FunctionHelper::getFullyQualifiedName($phpcsFile, $functionPointer)
+				FunctionHelper::getFullyQualifiedName($phpcsFile, $functionPointer),
 			),
 			$returnAnnotation->getStartPointer(),
-			self::CODE_MISSING_TRAVERSABLE_TYPE_HINT_SPECIFICATION
+			self::CODE_MISSING_TRAVERSABLE_TYPE_HINT_SPECIFICATION,
 		);
 	}
 
@@ -570,7 +562,7 @@ private function checkFunctionUselessAnnotation(
 			$this->getTraversableTypeHints(),
 			$this->enableUnionTypeHint,
 			$this->enableIntersectionTypeHint,
-			$this->enableStandaloneNullTrueFalseTypeHints
+			$this->enableStandaloneNullTrueFalseTypeHints,
 		)) {
 			$this->reportUselessSuppress($phpcsFile, $functionPointer, $isSuppressed, $suppressName);
 			return;
@@ -584,10 +576,10 @@ private function checkFunctionUselessAnnotation(
 			sprintf(
 				'%s %s() has useless @return annotation.',
 				FunctionHelper::getTypeLabel($phpcsFile, $functionPointer),
-				FunctionHelper::getFullyQualifiedName($phpcsFile, $functionPointer)
+				FunctionHelper::getFullyQualifiedName($phpcsFile, $functionPointer),
 			),
 			$returnAnnotation->getStartPointer(),
-			self::CODE_USELESS_ANNOTATION
+			self::CODE_USELESS_ANNOTATION,
 		);
 
 		if (!$fix) {
@@ -599,7 +591,7 @@ private function checkFunctionUselessAnnotation(
 			$phpcsFile,
 			T_DOC_COMMENT_STAR,
 			$returnAnnotation->getStartPointer() - 1,
-			$docCommentOpenPointer
+			$docCommentOpenPointer,
 		);
 
 		$changeStart = $starPointer ?? $returnAnnotation->getStartPointer();
@@ -608,7 +600,7 @@ private function checkFunctionUselessAnnotation(
 		$changeEnd = TokenHelper::findNext(
 			$phpcsFile,
 			[T_DOC_COMMENT_CLOSE_TAG, T_DOC_COMMENT_STAR],
-			$returnAnnotation->getEndPointer() + 1
+			$returnAnnotation->getEndPointer() + 1,
 		) - 1;
 
 		$phpcsFile->fixer->beginChangeset();
@@ -628,7 +620,7 @@ private function checkClosureTypeHint(File $phpcsFile, int $closurePointer): voi
 		$fix = $phpcsFile->addFixableError(
 			'Closure does not have void return type hint.',
 			$closurePointer,
-			self::CODE_MISSING_NATIVE_TYPE_HINT
+			self::CODE_MISSING_NATIVE_TYPE_HINT,
 		);
 
 		if (!$fix) {
@@ -640,7 +632,7 @@ private function checkClosureTypeHint(File $phpcsFile, int $closurePointer): voi
 		$position = TokenHelper::findPreviousEffective($phpcsFile, $tokens[$closurePointer]['scope_opener'] - 1, $closurePointer);
 
 		$phpcsFile->fixer->beginChangeset();
-		$phpcsFile->fixer->addContent($position, ': void');
+		FixerHelper::add($phpcsFile, $position, ': void');
 		$phpcsFile->fixer->endChangeset();
 	}
 
@@ -669,9 +661,9 @@ private function hasTraversableTypeHint(
 				TypeHintHelper::getFullyQualifiedTypeHint(
 					$phpcsFile,
 					$functionPointer,
-					$returnTypeHint->getTypeHintWithoutNullabilitySymbol()
+					$returnTypeHint->getTypeHintWithoutNullabilitySymbol(),
 				),
-				$this->getTraversableTypeHints()
+				$this->getTraversableTypeHints(),
 			)
 		) {
 			return true;
@@ -683,7 +675,7 @@ private function hasTraversableTypeHint(
 				$this->getReturnTypeNode($returnAnnotation),
 				$phpcsFile,
 				$functionPointer,
-				$this->getTraversableTypeHints()
+				$this->getTraversableTypeHints(),
 			);
 	}
 
@@ -701,7 +693,7 @@ private function reportUselessSuppress(File $phpcsFile, int $pointer, bool $isSu
 		$fix = $phpcsFile->addFixableError(
 			sprintf('Useless %s %s', SuppressHelper::ANNOTATION, $suppressName),
 			$pointer,
-			self::CODE_USELESS_SUPPRESS
+			self::CODE_USELESS_SUPPRESS,
 		);
 
 		if ($fix) {
@@ -715,16 +707,17 @@ private function getSniffName(string $sniffName): string
 	}
 
 	/**
-	 * @return array
+	 * @return list
 	 */
 	private function getTraversableTypeHints(): array
 	{
 		if ($this->normalizedTraversableTypeHints === null) {
-			$this->normalizedTraversableTypeHints = array_map(static function (string $typeHint): string {
-				return NamespaceHelper::isFullyQualifiedName($typeHint)
-					? $typeHint
-					: sprintf('%s%s', NamespaceHelper::NAMESPACE_SEPARATOR, $typeHint);
-			}, SniffSettingsHelper::normalizeArray($this->traversableTypeHints));
+			$this->normalizedTraversableTypeHints = array_map(
+				static fn (string $typeHint): string => NamespaceHelper::isFullyQualifiedName($typeHint)
+						? $typeHint
+						: sprintf('%s%s', NamespaceHelper::NAMESPACE_SEPARATOR, $typeHint),
+				SniffSettingsHelper::normalizeArray($this->traversableTypeHints),
+			);
 		}
 		return $this->normalizedTraversableTypeHints;
 	}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/ReturnTypeHintSpacingSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/ReturnTypeHintSpacingSniff.php
index a2dda3496..ceb0d89f6 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/ReturnTypeHintSpacingSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/ReturnTypeHintSpacingSniff.php
@@ -4,6 +4,7 @@
 
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\FunctionHelper;
 use SlevomatCodingStandard\Helpers\SniffSettingsHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
@@ -30,15 +31,14 @@ class ReturnTypeHintSpacingSniff implements Sniff
 
 	public const CODE_WHITESPACE_AFTER_NULLABILITY_SYMBOL = 'WhitespaceAfterNullabilitySymbol';
 
-	/** @var int */
-	public $spacesCountBeforeColon = 0;
+	public int $spacesCountBeforeColon = 0;
 
 	/**
 	 * @return array
 	 */
 	public function register(): array
 	{
-		return TokenHelper::$functionTokenCodes;
+		return TokenHelper::FUNCTION_TOKEN_CODES;
 	}
 
 	/**
@@ -67,22 +67,22 @@ public function process(File $phpcsFile, $functionPointer): void
 				$fix = $phpcsFile->addFixableError(
 					'There must be exactly one space between return type hint colon and return type hint.',
 					$typeHintStartPointer,
-					self::CODE_NO_SPACE_BETWEEN_COLON_AND_TYPE_HINT
+					self::CODE_NO_SPACE_BETWEEN_COLON_AND_TYPE_HINT,
 				);
 				if ($fix) {
 					$phpcsFile->fixer->beginChangeset();
-					$phpcsFile->fixer->addContent($colonPointer, ' ');
+					FixerHelper::add($phpcsFile, $colonPointer, ' ');
 					$phpcsFile->fixer->endChangeset();
 				}
 			} elseif ($tokens[$colonPointer + 1]['content'] !== ' ') {
 				$fix = $phpcsFile->addFixableError(
 					'There must be exactly one space between return type hint colon and return type hint.',
 					$typeHintStartPointer,
-					self::CODE_MULTIPLE_SPACES_BETWEEN_COLON_AND_TYPE_HINT
+					self::CODE_MULTIPLE_SPACES_BETWEEN_COLON_AND_TYPE_HINT,
 				);
 				if ($fix) {
 					$phpcsFile->fixer->beginChangeset();
-					$phpcsFile->fixer->replaceToken($colonPointer + 1, ' ');
+					FixerHelper::replace($phpcsFile, $colonPointer + 1, ' ');
 					$phpcsFile->fixer->endChangeset();
 				}
 			}
@@ -91,22 +91,22 @@ public function process(File $phpcsFile, $functionPointer): void
 				$fix = $phpcsFile->addFixableError(
 					'There must be exactly one space between return type hint colon and return type hint nullability symbol.',
 					$typeHintStartPointer,
-					self::CODE_NO_SPACE_BETWEEN_COLON_AND_NULLABILITY_SYMBOL
+					self::CODE_NO_SPACE_BETWEEN_COLON_AND_NULLABILITY_SYMBOL,
 				);
 				if ($fix) {
 					$phpcsFile->fixer->beginChangeset();
-					$phpcsFile->fixer->addContent($colonPointer, ' ');
+					FixerHelper::add($phpcsFile, $colonPointer, ' ');
 					$phpcsFile->fixer->endChangeset();
 				}
 			} elseif ($tokens[$colonPointer + 1]['content'] !== ' ') {
 				$fix = $phpcsFile->addFixableError(
 					'There must be exactly one space between return type hint colon and return type hint nullability symbol.',
 					$typeHintStartPointer,
-					self::CODE_MULTIPLE_SPACES_BETWEEN_COLON_AND_NULLABILITY_SYMBOL
+					self::CODE_MULTIPLE_SPACES_BETWEEN_COLON_AND_NULLABILITY_SYMBOL,
 				);
 				if ($fix) {
 					$phpcsFile->fixer->beginChangeset();
-					$phpcsFile->fixer->replaceToken($colonPointer + 1, ' ');
+					FixerHelper::replace($phpcsFile, $colonPointer + 1, ' ');
 					$phpcsFile->fixer->endChangeset();
 				}
 			}
@@ -115,11 +115,11 @@ public function process(File $phpcsFile, $functionPointer): void
 				$fix = $phpcsFile->addFixableError(
 					'There must be no whitespace between return type hint nullability symbol and return type hint.',
 					$typeHintStartPointer,
-					self::CODE_WHITESPACE_AFTER_NULLABILITY_SYMBOL
+					self::CODE_WHITESPACE_AFTER_NULLABILITY_SYMBOL,
 				);
 				if ($fix) {
 					$phpcsFile->fixer->beginChangeset();
-					$phpcsFile->fixer->replaceToken($typeHintStartPointer + 1, '');
+					FixerHelper::replace($phpcsFile, $typeHintStartPointer + 1, '');
 					$phpcsFile->fixer->endChangeset();
 				}
 			}
@@ -135,20 +135,20 @@ public function process(File $phpcsFile, $functionPointer): void
 				? $phpcsFile->addFixableError(
 					'There must be no whitespace between closing parenthesis and return type colon.',
 					$typeHintStartPointer,
-					self::CODE_WHITESPACE_BEFORE_COLON
+					self::CODE_WHITESPACE_BEFORE_COLON,
 				)
 				: $phpcsFile->addFixableError(
 					sprintf(
 						'There must be exactly %d whitespace%s between closing parenthesis and return type colon.',
 						$this->spacesCountBeforeColon,
-						$this->spacesCountBeforeColon !== 1 ? 's' : ''
+						$this->spacesCountBeforeColon !== 1 ? 's' : '',
 					),
 					$typeHintStartPointer,
-					self::CODE_INCORRECT_SPACES_BEFORE_COLON
+					self::CODE_INCORRECT_SPACES_BEFORE_COLON,
 				);
 			if ($fix) {
 				$phpcsFile->fixer->beginChangeset();
-				$phpcsFile->fixer->replaceToken($colonPointer - 1, $expectedSpaces);
+				FixerHelper::replace($phpcsFile, $colonPointer - 1, $expectedSpaces);
 				$phpcsFile->fixer->endChangeset();
 			}
 		} elseif ($tokens[$colonPointer - 1]['code'] === T_CLOSE_PARENTHESIS && $this->spacesCountBeforeColon !== 0) {
@@ -156,14 +156,14 @@ public function process(File $phpcsFile, $functionPointer): void
 				sprintf(
 					'There must be exactly %d whitespace%s between closing parenthesis and return type colon.',
 					$this->spacesCountBeforeColon,
-					$this->spacesCountBeforeColon !== 1 ? 's' : ''
+					$this->spacesCountBeforeColon !== 1 ? 's' : '',
 				),
 				$typeHintStartPointer,
-				self::CODE_INCORRECT_SPACES_BEFORE_COLON
+				self::CODE_INCORRECT_SPACES_BEFORE_COLON,
 			);
 			if ($fix) {
 				$phpcsFile->fixer->beginChangeset();
-				$phpcsFile->fixer->addContent($colonPointer - 1, $expectedSpaces);
+				FixerHelper::add($phpcsFile, $colonPointer - 1, $expectedSpaces);
 				$phpcsFile->fixer->endChangeset();
 			}
 		}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/UnionTypeHintFormatSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/UnionTypeHintFormatSniff.php
index 2e189487b..952d5302c 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/UnionTypeHintFormatSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/UnionTypeHintFormatSniff.php
@@ -3,6 +3,7 @@
 namespace SlevomatCodingStandard\Sniffs\TypeHints;
 
 use PHP_CodeSniffer\Files\File;
+use PHP_CodeSniffer\Sniffs\DeprecatedSniff;
 use PHP_CodeSniffer\Sniffs\Sniff;
 use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\FunctionHelper;
@@ -10,7 +11,6 @@
 use SlevomatCodingStandard\Helpers\SniffSettingsHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use SlevomatCodingStandard\Helpers\TypeHint;
-use function array_merge;
 use function explode;
 use function implode;
 use function sprintf;
@@ -22,7 +22,10 @@
 use const T_VARIABLE;
 use const T_WHITESPACE;
 
-class UnionTypeHintFormatSniff implements Sniff
+/**
+ * @deprecated
+ */
+class UnionTypeHintFormatSniff implements Sniff, DeprecatedSniff
 {
 
 	public const CODE_DISALLOWED_WHITESPACE = 'DisallowedWhitespace';
@@ -38,27 +41,47 @@ class UnionTypeHintFormatSniff implements Sniff
 	private const FIRST = 'first';
 	private const LAST = 'last';
 
-	/** @var bool|null */
-	public $enable = null;
+	public ?bool $enable = null;
 
-	/** @var string|null */
-	public $withSpaces = null;
+	public ?string $withSpaces = null;
 
-	/** @var string|null */
-	public $shortNullable = null;
+	public ?string $shortNullable = null;
 
-	/** @var string|null */
-	public $nullPosition = null;
+	public ?string $nullPosition = null;
+
+	/**
+	 * @codeCoverageIgnore
+	 */
+	public function getDeprecationVersion(): string
+	{
+		return 'Slevomat Coding Standard 8.16.0';
+	}
+
+	/**
+	 * @codeCoverageIgnore
+	 */
+	public function getRemovalVersion(): string
+	{
+		return 'Slevomat Coding Standard 9.0.0';
+	}
+
+	/**
+	 * @codeCoverageIgnore
+	 */
+	public function getDeprecationMessage(): string
+	{
+		return 'Use SlevomatCodingStandard.TypeHints.DNFTypeHintFormat instead.';
+	}
 
 	/**
 	 * @return array
 	 */
 	public function register(): array
 	{
-		return array_merge(
-			[T_VARIABLE],
-			TokenHelper::$functionTokenCodes
-		);
+		return [
+			T_VARIABLE,
+			...TokenHelper::FUNCTION_TOKEN_CODES,
+		];
 	}
 
 	/**
@@ -112,14 +135,14 @@ private function checkTypeHint(File $phpcsFile, TypeHint $typeHint): void
 					$phpcsFile,
 					T_WHITESPACE,
 					$typeHint->getStartPointer() + 1,
-					$typeHint->getEndPointer()
+					$typeHint->getEndPointer(),
 				);
 				if ($whitespacePointer !== null) {
 					$originalTypeHint = TokenHelper::getContent($phpcsFile, $typeHint->getStartPointer(), $typeHint->getEndPointer());
 					$fix = $phpcsFile->addFixableError(
 						sprintf('Spaces in type hint "%s" are disallowed.', $originalTypeHint),
 						$typeHint->getStartPointer(),
-						self::CODE_DISALLOWED_WHITESPACE
+						self::CODE_DISALLOWED_WHITESPACE,
 					);
 					if ($fix) {
 						$this->fixTypeHint($phpcsFile, $typeHint, $typeHint->getTypeHint());
@@ -131,7 +154,7 @@ private function checkTypeHint(File $phpcsFile, TypeHint $typeHint): void
 					$phpcsFile,
 					[T_TYPE_UNION],
 					$typeHint->getStartPointer(),
-					$typeHint->getEndPointer()
+					$typeHint->getEndPointer(),
 				) as $unionSeparator) {
 					if ($tokens[$unionSeparator - 1]['content'] !== ' ') {
 						$error = true;
@@ -148,7 +171,7 @@ private function checkTypeHint(File $phpcsFile, TypeHint $typeHint): void
 					$fix = $phpcsFile->addFixableError(
 						sprintf('One space required before and after each "|" in type hint "%s".', $originalTypeHint),
 						$typeHint->getStartPointer(),
-						self::CODE_REQUIRED_WHITESPACE
+						self::CODE_REQUIRED_WHITESPACE,
 					);
 					if ($fix) {
 						$fixedTypeHint = implode(' | ', explode('|', $typeHint->getTypeHint()));
@@ -168,7 +191,7 @@ private function checkTypeHint(File $phpcsFile, TypeHint $typeHint): void
 			$fix = $phpcsFile->addFixableError(
 				sprintf('Short nullable type hint in "%s" is required.', $typeHint->getTypeHint()),
 				$typeHint->getStartPointer(),
-				self::CODE_REQUIRED_SHORT_NULLABLE
+				self::CODE_REQUIRED_SHORT_NULLABLE,
 			);
 			if ($fix) {
 				$typeHintWithoutNull = self::getTypeHintContentWithoutNull($phpcsFile, $typeHint);
@@ -178,7 +201,7 @@ private function checkTypeHint(File $phpcsFile, TypeHint $typeHint): void
 			$fix = $phpcsFile->addFixableError(
 				sprintf('Usage of short nullable type hint in "%s" is disallowed.', $typeHint->getTypeHint()),
 				$typeHint->getStartPointer(),
-				self::CODE_DISALLOWED_SHORT_NULLABLE
+				self::CODE_DISALLOWED_SHORT_NULLABLE,
 			);
 			if ($fix) {
 				$this->fixTypeHint($phpcsFile, $typeHint, substr($typeHint->getTypeHint(), 1) . '|null');
@@ -193,7 +216,7 @@ private function checkTypeHint(File $phpcsFile, TypeHint $typeHint): void
 			$fix = $phpcsFile->addFixableError(
 				sprintf('Null type hint should be on first position in "%s".', $typeHint->getTypeHint()),
 				$typeHint->getStartPointer(),
-				self::CODE_NULL_TYPE_HINT_NOT_ON_FIRST_POSITION
+				self::CODE_NULL_TYPE_HINT_NOT_ON_FIRST_POSITION,
 			);
 			if ($fix) {
 				$this->fixTypeHint($phpcsFile, $typeHint, 'null|' . self::getTypeHintContentWithoutNull($phpcsFile, $typeHint));
@@ -202,7 +225,7 @@ private function checkTypeHint(File $phpcsFile, TypeHint $typeHint): void
 			$fix = $phpcsFile->addFixableError(
 				sprintf('Null type hint should be on last position in "%s".', $typeHint->getTypeHint()),
 				$typeHint->getStartPointer(),
-				self::CODE_NULL_TYPE_HINT_NOT_ON_LAST_POSITION
+				self::CODE_NULL_TYPE_HINT_NOT_ON_LAST_POSITION,
 			);
 			if ($fix) {
 				$this->fixTypeHint($phpcsFile, $typeHint, self::getTypeHintContentWithoutNull($phpcsFile, $typeHint) . '|null');
@@ -217,8 +240,8 @@ private function getTypeHintContentWithoutNull(File $phpcsFile, TypeHint $typeHi
 		if (strtolower($tokens[$typeHint->getEndPointer()]['content']) === 'null') {
 			$previousTypeHintPointer = TokenHelper::findPrevious(
 				$phpcsFile,
-				TokenHelper::getOnlyTypeHintTokenCodes(),
-				$typeHint->getEndPointer() - 1
+				TokenHelper::ONLY_TYPE_HINT_TOKEN_CODES,
+				$typeHint->getEndPointer() - 1,
 			);
 			return TokenHelper::getContent($phpcsFile, $typeHint->getStartPointer(), $previousTypeHintPointer);
 		}
@@ -227,7 +250,7 @@ private function getTypeHintContentWithoutNull(File $phpcsFile, TypeHint $typeHi
 
 		for ($i = $typeHint->getStartPointer(); $i <= $typeHint->getEndPointer(); $i++) {
 			if (strtolower($tokens[$i]['content']) === 'null') {
-				$i = TokenHelper::findNext($phpcsFile, TokenHelper::getOnlyTypeHintTokenCodes(), $i + 1);
+				$i = TokenHelper::findNext($phpcsFile, TokenHelper::ONLY_TYPE_HINT_TOKEN_CODES, $i + 1);
 			}
 
 			$content .= $tokens[$i]['content'];
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/UselessConstantTypeHintSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/UselessConstantTypeHintSniff.php
index b061adc60..c85754165 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/UselessConstantTypeHintSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/TypeHints/UselessConstantTypeHintSniff.php
@@ -60,7 +60,7 @@ public function process(File $phpcsFile, $constantPointer): void
 			$fix = $phpcsFile->addFixableError(
 				'Useless @var annotation.',
 				$annotation->getStartPointer(),
-				self::CODE_USELESS_VAR_ANNOTATION
+				self::CODE_USELESS_VAR_ANNOTATION,
 			);
 
 			/** @var int $fixerStart */
@@ -68,7 +68,7 @@ public function process(File $phpcsFile, $constantPointer): void
 				$phpcsFile,
 				T_DOC_COMMENT_WHITESPACE,
 				$phpcsFile->eolChar,
-				$annotation->getStartPointer() - 1
+				$annotation->getStartPointer() - 1,
 			);
 			$fixerEnd = $annotation->getEndPointer();
 		}
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Variables/DisallowSuperGlobalVariableSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Variables/DisallowSuperGlobalVariableSniff.php
index 716f749c2..0410f7792 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Variables/DisallowSuperGlobalVariableSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Variables/DisallowSuperGlobalVariableSniff.php
@@ -36,17 +36,17 @@ public function register(): array
 
 	/**
 	 * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
-	 * @param int $variablePointer
+	 * @param int $pointer
 	 */
-	public function process(File $phpcsFile, $variablePointer): void
+	public function process(File $phpcsFile, $pointer): void
 	{
 		$tokens = $phpcsFile->getTokens();
 
-		if (!in_array($tokens[$variablePointer]['content'], self::SUPER_GLOBALS, true)) {
+		if (!in_array($tokens[$pointer]['content'], self::SUPER_GLOBALS, true)) {
 			return;
 		}
 
-		$phpcsFile->addError('Use of super global variable is disallowed.', $variablePointer, self::CODE_DISALLOWED_SUPER_GLOBAL_VARIABLE);
+		$phpcsFile->addError('Use of super global variable is disallowed.', $pointer, self::CODE_DISALLOWED_SUPER_GLOBAL_VARIABLE);
 	}
 
 }
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Variables/DuplicateAssignmentToVariableSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Variables/DuplicateAssignmentToVariableSniff.php
index 2e73d89ad..36701025d 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Variables/DuplicateAssignmentToVariableSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Variables/DuplicateAssignmentToVariableSniff.php
@@ -63,7 +63,7 @@ public function process(File $phpcsFile, $assignmentPointer): void
 		$phpcsFile->addError(
 			sprintf('Duplicate assignment to variable %s.', $tokens[$secondVariablePointer]['content']),
 			$secondVariablePointer,
-			self::CODE_DUPLICATE_ASSIGNMENT
+			self::CODE_DUPLICATE_ASSIGNMENT,
 		);
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Variables/UnusedVariableSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Variables/UnusedVariableSniff.php
index 568d116f0..b27b0059a 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Variables/UnusedVariableSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Variables/UnusedVariableSniff.php
@@ -42,6 +42,7 @@
 use const T_HEREDOC;
 use const T_IF;
 use const T_INC;
+use const T_INLINE_ELSE;
 use const T_LIST;
 use const T_MINUS_EQUAL;
 use const T_MOD_EQUAL;
@@ -72,8 +73,7 @@ class UnusedVariableSniff implements Sniff
 
 	public const CODE_UNUSED_VARIABLE = 'UnusedVariable';
 
-	/** @var bool */
-	public $ignoreUnusedValuesWhenOnlyKeysAreUsedInForeach = false;
+	public bool $ignoreUnusedValuesWhenOnlyKeysAreUsedInForeach = false;
 
 	/**
 	 * @return array
@@ -87,17 +87,17 @@ public function register(): array
 
 	/**
 	 * @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
-	 * @param int $variablePointer
+	 * @param int $pointer
 	 */
-	public function process(File $phpcsFile, $variablePointer): void
+	public function process(File $phpcsFile, $pointer): void
 	{
-		if (!$this->isAssignment($phpcsFile, $variablePointer)) {
+		if (!$this->isAssignment($phpcsFile, $pointer)) {
 			return;
 		}
 
 		$tokens = $phpcsFile->getTokens();
 
-		$variableName = $tokens[$variablePointer]['content'];
+		$variableName = $tokens[$pointer]['content'];
 
 		if (in_array($variableName, [
 			'$this',
@@ -114,7 +114,7 @@ public function process(File $phpcsFile, $variablePointer): void
 			return;
 		}
 
-		$previousPointer = TokenHelper::findPreviousEffective($phpcsFile, $variablePointer - 1);
+		$previousPointer = TokenHelper::findPreviousEffective($phpcsFile, $pointer - 1);
 
 		if (in_array($tokens[$previousPointer]['code'], [T_OBJECT_OPERATOR, T_DOUBLE_COLON], true)) {
 			// Property
@@ -144,39 +144,39 @@ public function process(File $phpcsFile, $variablePointer): void
 			return;
 		}
 
-		if ($this->isUsedAsParameter($phpcsFile, $variablePointer)) {
+		if ($this->isUsedAsParameter($phpcsFile, $pointer)) {
 			return;
 		}
 
-		if ($this->isUsedInForLoopCondition($phpcsFile, $variablePointer, $variableName)) {
+		if ($this->isUsedInForLoopCondition($phpcsFile, $pointer, $variableName)) {
 			return;
 		}
 
-		if ($this->isDefinedInDoConditionAndUsedInLoop($phpcsFile, $variablePointer, $variableName)) {
+		if ($this->isDefinedInDoConditionAndUsedInLoop($phpcsFile, $pointer, $variableName)) {
 			return;
 		}
 
-		if ($this->isUsedInLoopCycle($phpcsFile, $variablePointer, $variableName)) {
+		if ($this->isUsedInLoopCycle($phpcsFile, $pointer, $variableName)) {
 			return;
 		}
 
-		if ($this->isUsedAsKeyOrValueInArray($phpcsFile, $variablePointer)) {
+		if ($this->isUsedAsKeyOrValueInArray($phpcsFile, $pointer)) {
 			return;
 		}
 
-		if ($this->isValueInForeachAndErrorIsIgnored($phpcsFile, $variablePointer)) {
+		if ($this->isValueInForeachAndErrorIsIgnored($phpcsFile, $pointer)) {
 			return;
 		}
 
-		$scopeOwnerPointer = ScopeHelper::getRootPointer($phpcsFile, $variablePointer - 1);
-		foreach (array_reverse($tokens[$variablePointer]['conditions'], true) as $conditionPointer => $conditionTokenCode) {
-			if (in_array($conditionTokenCode, TokenHelper::$functionTokenCodes, true)) {
+		$scopeOwnerPointer = ScopeHelper::getRootPointer($phpcsFile, $pointer - 1);
+		foreach (array_reverse($tokens[$pointer]['conditions'], true) as $conditionPointer => $conditionTokenCode) {
+			if (in_array($conditionTokenCode, TokenHelper::FUNCTION_TOKEN_CODES, true)) {
 				$scopeOwnerPointer = $conditionPointer;
 				break;
 			}
 		}
 
-		if (in_array($tokens[$scopeOwnerPointer]['code'], TokenHelper::$functionTokenCodes, true)) {
+		if (in_array($tokens[$scopeOwnerPointer]['code'], TokenHelper::FUNCTION_TOKEN_CODES, true)) {
 			if ($this->isStaticOrGlobalVariable($phpcsFile, $scopeOwnerPointer, $variableName)) {
 				return;
 			}
@@ -193,22 +193,22 @@ public function process(File $phpcsFile, $variablePointer): void
 			}
 		}
 
-		if ($this->isReference($phpcsFile, $scopeOwnerPointer, $variablePointer)) {
+		if ($this->isReference($phpcsFile, $scopeOwnerPointer, $pointer)) {
 			return;
 		}
 
-		if (VariableHelper::isUsedInScopeAfterPointer($phpcsFile, $scopeOwnerPointer, $variablePointer, $variablePointer + 1)) {
+		if (VariableHelper::isUsedInScopeAfterPointer($phpcsFile, $scopeOwnerPointer, $pointer, $pointer + 1)) {
 			return;
 		}
 
-		if ($this->isPartOfStatementAndWithIncrementOrDecrementOperator($phpcsFile, $variablePointer)) {
+		if ($this->isPartOfStatementAndWithIncrementOrDecrementOperator($phpcsFile, $pointer)) {
 			return;
 		}
 
 		$phpcsFile->addError(
 			sprintf('Unused variable %s.', $variableName),
-			$variablePointer,
-			self::CODE_UNUSED_VARIABLE
+			$pointer,
+			self::CODE_UNUSED_VARIABLE,
 		);
 	}
 
@@ -280,8 +280,8 @@ private function isAssignment(File $phpcsFile, int $variablePointer): bool
 
 		$possibleShortListCloserPointer = TokenHelper::findNextExcluding(
 			$phpcsFile,
-			array_merge(TokenHelper::$ineffectiveTokenCodes, [T_VARIABLE, T_COMMA]),
-			$variablePointer + 1
+			[...TokenHelper::INEFFECTIVE_TOKEN_CODES, T_VARIABLE, T_COMMA],
+			$variablePointer + 1,
 		);
 		if ($tokens[$possibleShortListCloserPointer]['code'] === T_CLOSE_SHORT_ARRAY) {
 			return $tokens[TokenHelper::findNextEffective($phpcsFile, $possibleShortListCloserPointer + 1)]['code'] === T_EQUAL;
@@ -370,7 +370,7 @@ private function isDefinedInDoConditionAndUsedInLoop(File $phpcsFile, int $varia
 			T_VARIABLE,
 			$variableName,
 			$tokens[$loopCloserPointer]['bracket_opener'] + 1,
-			$loopCloserPointer
+			$loopCloserPointer,
 		) !== null;
 	}
 
@@ -380,7 +380,7 @@ private function isUsedInLoopCycle(File $phpcsFile, int $variablePointer, string
 
 		$loopPointer = null;
 		foreach (array_reverse($tokens[$variablePointer]['conditions'], true) as $conditionPointer => $conditionTokenCode) {
-			if (in_array($conditionTokenCode, TokenHelper::$functionTokenCodes, true)) {
+			if (in_array($conditionTokenCode, TokenHelper::FUNCTION_TOKEN_CODES, true)) {
 				break;
 			}
 
@@ -399,7 +399,7 @@ private function isUsedInLoopCycle(File $phpcsFile, int $variablePointer, string
 				T_VARIABLE,
 				$variableName,
 				$tokens[$loopConditionPointer]['parenthesis_opener'] + 1,
-				$tokens[$loopConditionPointer]['parenthesis_closer']
+				$tokens[$loopConditionPointer]['parenthesis_closer'],
 			);
 			if (
 				$variableUsedInLoopConditionPointer === null
@@ -414,7 +414,7 @@ private function isUsedInLoopCycle(File $phpcsFile, int $variablePointer, string
 
 			$pointerBeforeVariableUsedInLoopCondition = TokenHelper::findPreviousEffective(
 				$phpcsFile,
-				$variableUsedInLoopConditionPointer - 1
+				$variableUsedInLoopConditionPointer - 1,
 			);
 			if ($tokens[$pointerBeforeVariableUsedInLoopCondition]['code'] === T_BITWISE_AND) {
 				return true;
@@ -465,6 +465,11 @@ private function isUsedInLoopCycle(File $phpcsFile, int $variablePointer, string
 				continue;
 			}
 
+			$previousPointer = TokenHelper::findPreviousEffective($phpcsFile, $i - 1);
+			if ($tokens[$previousPointer]['code'] === T_INLINE_ELSE) {
+				return true;
+			}
+
 			$parenthesisOwnerPointer = $this->findNestedParenthesisWithOwner($phpcsFile, $i);
 			if (
 				$parenthesisOwnerPointer !== null
@@ -656,9 +661,10 @@ private function isPartOfStatementAndWithIncrementOrDecrementOperator(File $phpc
 				[T_STRING_CONCAT, T_ECHO, T_RETURN, T_EXIT, T_PRINT, T_COMMA, T_EMPTY, T_EVAL, T_YIELD],
 				Tokens::$operators,
 				Tokens::$assignmentTokens,
-				Tokens::$booleanOperators
+				Tokens::$booleanOperators,
+				Tokens::$castTokens,
 			),
-			true
+			true,
 		);
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Variables/UselessVariableSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Variables/UselessVariableSniff.php
index 38cce8371..79d27d810 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Variables/UselessVariableSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Variables/UselessVariableSniff.php
@@ -174,8 +174,8 @@ public function process(File $phpcsFile, $returnPointer): void
 		if ($tokens[$assignmentPointer]['code'] === T_EQUAL) {
 			FixerHelper::change($phpcsFile, $previousVariablePointer, $assignmentPointer, 'return');
 		} else {
-			$phpcsFile->fixer->addContentBefore($previousVariablePointer, 'return ');
-			$phpcsFile->fixer->replaceToken($assignmentPointer, $assignmentFixerMapping[$tokens[$assignmentPointer]['code']]);
+			FixerHelper::addBefore($phpcsFile, $previousVariablePointer, 'return ');
+			FixerHelper::replace($phpcsFile, $assignmentPointer, $assignmentFixerMapping[$tokens[$assignmentPointer]['code']]);
 		}
 
 		FixerHelper::removeBetweenIncluding($phpcsFile, $previousVariableSemicolonPointer + 1, $returnSemicolonPointer);
@@ -189,7 +189,7 @@ private function findPreviousVariablePointer(File $phpcsFile, int $pointer, stri
 
 		for ($i = $pointer - 1; $i >= 0; $i--) {
 			if (
-				in_array($tokens[$i]['code'], TokenHelper::$functionTokenCodes, true)
+				in_array($tokens[$i]['code'], TokenHelper::FUNCTION_TOKEN_CODES, true)
 				&& ScopeHelper::isInSameScope($phpcsFile, $tokens[$i]['scope_opener'] + 1, $pointer)
 			) {
 				return null;
@@ -281,7 +281,7 @@ private function findFunctionPointer(File $phpcsFile, int $pointer): ?int
 		$tokens = $phpcsFile->getTokens();
 
 		foreach (array_reverse($tokens[$pointer]['conditions'], true) as $conditionPointer => $conditionTokenCode) {
-			if (in_array($conditionTokenCode, TokenHelper::$functionTokenCodes, true)) {
+			if (in_array($conditionTokenCode, TokenHelper::FUNCTION_TOKEN_CODES, true)) {
 				return $conditionPointer;
 			}
 		}
@@ -348,7 +348,7 @@ private function hasVariableVarAnnotation(File $phpcsFile, int $variablePointer)
 		$docCommentContent = TokenHelper::getContent($phpcsFile, $tokens[$pointerBeforeVariable]['comment_opener'], $pointerBeforeVariable);
 		return preg_match(
 			'~@(?:(?:phpstan|psalm)-)?var\\s+.+\\s+' . preg_quote($tokens[$variablePointer]['content'], '~') . '(?:\\s|$)~',
-			$docCommentContent
+			$docCommentContent,
 		) !== 0;
 	}
 
diff --git a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Whitespaces/DuplicateSpacesSniff.php b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Whitespaces/DuplicateSpacesSniff.php
index 8dbecc506..20635817a 100644
--- a/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Whitespaces/DuplicateSpacesSniff.php
+++ b/app/vendor/slevomat/coding-standard/SlevomatCodingStandard/Sniffs/Whitespaces/DuplicateSpacesSniff.php
@@ -5,16 +5,13 @@
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Sniffs\Sniff;
 use PHP_CodeSniffer\Util\Tokens;
-use SlevomatCodingStandard\Helpers\IndentationHelper;
+use SlevomatCodingStandard\Helpers\FixerHelper;
 use SlevomatCodingStandard\Helpers\ParameterHelper;
 use SlevomatCodingStandard\Helpers\TokenHelper;
 use function in_array;
 use function preg_match_all;
 use function preg_replace;
 use function sprintf;
-use function str_repeat;
-use function str_replace;
-use function strlen;
 use const PREG_OFFSET_CAPTURE;
 use const T_DOC_COMMENT_CLOSE_TAG;
 use const T_DOC_COMMENT_OPEN_TAG;
@@ -31,20 +28,15 @@ class DuplicateSpacesSniff implements Sniff
 
 	public const CODE_DUPLICATE_SPACES = 'DuplicateSpaces';
 
-	/** @var bool */
-	public $ignoreSpacesBeforeAssignment = false;
+	public bool $ignoreSpacesBeforeAssignment = false;
 
-	/** @var bool */
-	public $ignoreSpacesInAnnotation = false;
+	public bool $ignoreSpacesInAnnotation = false;
 
-	/** @var bool */
-	public $ignoreSpacesInComment = false;
+	public bool $ignoreSpacesInComment = false;
 
-	/** @var bool */
-	public $ignoreSpacesInParameters = false;
+	public bool $ignoreSpacesInParameters = false;
 
-	/** @var bool */
-	public $ignoreSpacesInMatch = false;
+	public bool $ignoreSpacesInMatch = false;
 
 	/**
 	 * @return array
@@ -136,24 +128,14 @@ public function process(File $phpcsFile, $whitespacePointer): void
 			return;
 		}
 
-		$tabWidth = $phpcsFile->config->tabWidth;
-
 		$fix = false;
 		foreach ($matches[0] as [$match, $offset]) {
-			$firstPointerOnLine = TokenHelper::findFirstNonWhitespaceOnLine($phpcsFile, $whitespacePointer - 1);
-			$indentation = IndentationHelper::getIndentation($phpcsFile, $firstPointerOnLine);
-			$indentationWithoutTabs = str_replace(
-				IndentationHelper::TAB_INDENT,
-				$tabWidth === 0 ? IndentationHelper::SPACES_INDENT : str_repeat(' ', $tabWidth),
-				$indentation
-			);
-
-			$position = $tokens[$whitespacePointer]['column'] + $offset - strlen($indentation) + strlen($indentationWithoutTabs);
+			$position = $tokens[$whitespacePointer]['column'] + $offset;
 
 			$fixable = $phpcsFile->addFixableError(
 				sprintf('Duplicate spaces at position %d.', $position),
 				$whitespacePointer,
-				self::CODE_DUPLICATE_SPACES
+				self::CODE_DUPLICATE_SPACES,
 			);
 
 			if ($fixable) {
@@ -167,7 +149,7 @@ public function process(File $phpcsFile, $whitespacePointer): void
 
 		$phpcsFile->fixer->beginChangeset();
 
-		$phpcsFile->fixer->replaceToken($whitespacePointer, preg_replace('~ {2,}~', ' ', $content));
+		FixerHelper::replace($phpcsFile, $whitespacePointer, preg_replace('~ {2,}~', ' ', $content));
 
 		$phpcsFile->fixer->endChangeset();
 	}
diff --git a/app/vendor/slevomat/coding-standard/composer.json b/app/vendor/slevomat/coding-standard/composer.json
index 670f865e0..477075737 100644
--- a/app/vendor/slevomat/coding-standard/composer.json
+++ b/app/vendor/slevomat/coding-standard/composer.json
@@ -8,27 +8,24 @@
 	"prefer-stable": true,
 	"config": {
 		"bin-dir": "bin",
-		"platform": {
-			"php": "8.1.0"
-		},
 		"allow-plugins": {
 			"dealerdirect/phpcodesniffer-composer-installer": true
 		}
 	},
 	"require": {
-		"php": "^7.2 || ^8.0",
-		"dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.0",
-		"phpstan/phpdoc-parser": "^1.23.1",
-		"squizlabs/php_codesniffer": "^3.7.1"
+		"php": "^7.4 || ^8.0",
+		"dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.1.2",
+		"phpstan/phpdoc-parser": "^2.2.0",
+		"squizlabs/php_codesniffer": "^3.13.2"
 	},
 	"require-dev": {
-		"phing/phing": "2.17.4",
-		"php-parallel-lint/php-parallel-lint": "1.3.2",
-		"phpstan/phpstan": "1.10.37",
-		"phpstan/phpstan-deprecation-rules": "1.1.4",
-		"phpstan/phpstan-phpunit": "1.3.14",
-		"phpstan/phpstan-strict-rules": "1.5.1",
-		"phpunit/phpunit": "8.5.21|9.6.8|10.3.5"
+		"phing/phing": "3.0.1|3.1.0",
+		"php-parallel-lint/php-parallel-lint": "1.4.0",
+		"phpstan/phpstan": "2.1.19",
+		"phpstan/phpstan-deprecation-rules": "2.0.3",
+		"phpstan/phpstan-phpunit": "2.0.7",
+		"phpstan/phpstan-strict-rules": "2.0.6",
+		"phpunit/phpunit": "9.6.8|10.5.48|11.4.4|11.5.27|12.2.7"
 	},
 	"autoload": {
 		"psr-4": {
diff --git a/app/vendor/slevomat/coding-standard/doc/arrays.md b/app/vendor/slevomat/coding-standard/doc/arrays.md
index 3b4f10f8e..31e4a48a8 100644
--- a/app/vendor/slevomat/coding-standard/doc/arrays.md
+++ b/app/vendor/slevomat/coding-standard/doc/arrays.md
@@ -31,7 +31,7 @@ Checks whitespace in single line array declarations (whitespace between brackets
 Sniff provides the following settings:
 
 * `spacesAroundBrackets`: number of spaces you require to have around array brackets
-* `enableEmptyArrayCheck` (defaults to `false`): enables check for empty arrays
+* `enableEmptyArrayCheck` (default: `false`): enables check for empty arrays
 
 #### SlevomatCodingStandard.Arrays.TrailingArrayComma 🔧
 
diff --git a/app/vendor/slevomat/coding-standard/doc/attributes.md b/app/vendor/slevomat/coding-standard/doc/attributes.md
index ef2e70fac..ef965cf6c 100644
--- a/app/vendor/slevomat/coding-standard/doc/attributes.md
+++ b/app/vendor/slevomat/coding-standard/doc/attributes.md
@@ -6,7 +6,7 @@ Sniff checks lines count between attribute and its target (or target's documenta
 
 Sniff provides the following settings:
 
-* `allowOnSameLine`: allow attribute and its target to be placed on the same line (default value is false)
+* `allowOnSameLine` (default: `false`): allow attribute and its target to be placed on the same line
 * `linesCount`: lines count between attribute and its target
 
 #### SlevomatCodingStandard.Attributes.AttributesOrder 🔧
diff --git a/app/vendor/slevomat/coding-standard/doc/classes.md b/app/vendor/slevomat/coding-standard/doc/classes.md
index 5bbed250b..71cc19fd0 100644
--- a/app/vendor/slevomat/coding-standard/doc/classes.md
+++ b/app/vendor/slevomat/coding-standard/doc/classes.md
@@ -9,14 +9,6 @@ Sniff provides the following settings:
 * `spacesCountBeforeColon`: the number of spaces before `:`.
 * `spacesCountBeforeType`: the number of spaces before type.
 
-#### SlevomatCodingStandard.Classes.ClassLength
-
-Disallows long classes. This sniff provides the following settings:
-
-* `includeComments`: should comments be included in the count (default value is false).
-* `includeWhitespace`: should empty lines be included in the count (default value is false).
-* `maxLinesLength`: specifies max allowed function lines length (default value is 250).
-
 #### SlevomatCodingStandard.Classes.ClassConstantVisibility 🔧
 
 In PHP 7.1+ it's possible to declare [visibility of class constants](https://wiki.php.net/rfc/class_const_visibility). In a similar vein to optional declaration of visibility for properties and methods which is actually required in sane coding standards, this sniff also requires declaring visibility for all class constants.
@@ -30,6 +22,14 @@ const FOO = 1; // visibility missing!
 public const BAR = 2; // correct
 ```
 
+#### SlevomatCodingStandard.Classes.ClassLength
+
+Disallows long classes. This sniff provides the following settings:
+
+* `includeComments` (default: `false`): should comments be included in the count.
+* `includeWhitespace` (default: `false`): should empty lines be included in the count.
+* `maxLinesLength` (default: `250`): specifies max allowed function lines length.
+
 #### SlevomatCodingStandard.Classes.ClassMemberSpacing 🔧
 
 Sniff checks lines count between different class members, e.g. between last property and first method.
@@ -45,18 +45,18 @@ Checks that class/trait/interface members are in the correct order.
 Sniff provides the following settings:
 
 * `groups`: order of groups. Use multiple groups in one `` to not differentiate among them. You can use specific groups or shortcuts.
+* `methodGroups`: custom method groups. Define a custom group for special methods based on their name, annotation, or attribute.
 
 **List of supported groups**:
 uses,
 enum cases,
 public constants, protected constants, private constants,
 public properties, public static properties, protected properties, protected static properties, private properties, private static properties,
-constructor, static constructors, destructor, magic methods,
+constructor, static constructors, destructor, magic methods, invoke method,
 public methods, protected methods, private methods,
 public final methods, public static final methods, protected final methods, protected static final methods,
 public abstract methods, public static abstract methods, protected abstract methods, protected static abstract methods,
-public static methods, protected static methods, private static methods,
-private methods
+public static methods, protected static methods, private static methods
 
 **List of supported shortcuts**:
 constants, properties, static properties, methods, all public methods, all protected methods, all private methods, static methods, final methods, abstract methods
@@ -64,6 +64,12 @@ constants, properties, static properties, methods, all public methods, all prote
 ```xml
 
 	
+		
+			
+			
+			
+		
+
 		
 			
 
@@ -76,10 +82,21 @@ constants, properties, static properties, methods, all public methods, all prote
 			
 			
 
-			
+			
 			
+
+			
+			
+			
+
+			
+			
+
+			
 			
 			
+
+			
 			
 		
 	
@@ -96,6 +113,8 @@ Sniff provides the following settings:
 * `maxLinesCountBeforeWithComment`: maximum number of lines before constant with a documentation comment or attribute
 * `minLinesCountBeforeWithoutComment`: minimum number of lines before constant without a documentation comment or attribute
 * `maxLinesCountBeforeWithoutComment`: maximum number of lines before constant without a documentation comment or attribute
+* `minLinesCountBeforeMultiline` (default: `null`): minimum number of lines before multiline constant
+* `maxLinesCountBeforeMultiline` (default: `null`): maximum number of lines before multiline constant
 
 #### SlevomatCodingStandard.Classes.DisallowConstructorPropertyPromotion
 
@@ -113,10 +132,6 @@ Disallows multi constant definition.
 
 Disallows multi property definition.
 
-#### SlevomatCodingStandard.Classes.DisallowMultiPropertyDefinition 🔧
-
-Disallows multi property definition.
-
 #### SlevomatCodingStandard.Classes.DisallowStringExpressionPropertyFetch 🔧
 
 Disallows string expression property fetch `$object->{'foo'}` when the property name is compatible with identifier access.
@@ -147,7 +162,9 @@ Disallows using public properties.
 
 This sniff provides the following setting:
 
-* `checkPromoted`: will check promoted properties too.
+* `checkPromoted` (default: `false`): will check promoted properties too.
+* `allowReadonly` (default: `false`): will allow readonly properties.
+* `allowNonPublicSet` (default: `true`): will allow properties with `protected(set)` or `private(set)`.
 
 #### SlevomatCodingStandard.Classes.MethodSpacing 🔧
 
@@ -201,6 +218,8 @@ Sniff provides the following settings:
 * `maxLinesCountBeforeWithComment`: maximum number of lines before property with a documentation comment or attribute
 * `minLinesCountBeforeWithoutComment`: minimum number of lines before property without a documentation comment or attribute
 * `maxLinesCountBeforeWithoutComment`: maximum number of lines before property without a documentation comment or attribute
+* `minLinesCountBeforeMultiline` (default: `null`): minimum number of lines before multiline property
+* `maxLinesCountBeforeMultiline` (default: `null`): maximum number of lines before multiline property
 
 #### SlevomatCodingStandard.Classes.RequireAbstractOrFinal 🔧
 
diff --git a/app/vendor/slevomat/coding-standard/doc/complexity.md b/app/vendor/slevomat/coding-standard/doc/complexity.md
index f77bfcfca..83e40caed 100644
--- a/app/vendor/slevomat/coding-standard/doc/complexity.md
+++ b/app/vendor/slevomat/coding-standard/doc/complexity.md
@@ -6,5 +6,5 @@ Enforces maximum [cognitive complexity](https://www.sonarsource.com/docs/Cogniti
 
 Sniff provides the following setting:
 
-* `warningThreshold`: defaults to 6
-* `errorThreshold` : defaults to 6
+* `warningThreshold` (default: `6`)
+* `errorThreshold` (default: `6`)
diff --git a/app/vendor/slevomat/coding-standard/doc/control-structures.md b/app/vendor/slevomat/coding-standard/doc/control-structures.md
index 760aaa586..ee6156c8f 100644
--- a/app/vendor/slevomat/coding-standard/doc/control-structures.md
+++ b/app/vendor/slevomat/coding-standard/doc/control-structures.md
@@ -184,8 +184,8 @@ Ternary operator has to be reformatted to more lines when the line length exceed
 
 Sniff provides the following settings:
 
-* `lineLengthLimit` (defaults to `0`)
-* `minExpressionsLength` (defaults to `null`): when the expressions after `?` are shorter than this length, the ternary operator does not have to be reformatted.
+* `lineLengthLimit` (default: `0`)
+* `minExpressionsLength` (default: `null`): when the expressions after `?` are shorter than this length, the ternary operator does not have to be reformatted.
 
 #### SlevomatCodingStandard.ControlStructures.RequireNullCoalesceEqualOperator 🔧
 
@@ -194,6 +194,7 @@ Requires use of null coalesce equal operator when possible.
 This sniff provides the following setting:
 
 * `enable`: either to enable or not this sniff. By default, it is enabled for PHP versions 7.4 or higher.
+* `checkIfConditions` (default: `false`): will check `if` conditions too.
 
 #### SlevomatCodingStandard.ControlStructures.RequireNullCoalesceOperator 🔧
 
@@ -226,7 +227,7 @@ Requires ternary operator when possible.
 
 Sniff provides the following settings:
 
-* `ignoreMultiLine` (defaults to `false`): ignores multi-line statements.
+* `ignoreMultiLine` (default: `false`): ignores multi-line statements.
 
 #### SlevomatCodingStandard.ControlStructures.DisallowYodaComparison 🔧
 #### SlevomatCodingStandard.ControlStructures.RequireYodaComparison 🔧
@@ -235,7 +236,7 @@ Sniff provides the following settings:
 
 Sniff provides the following settings:
 
-* `alwaysVariableOnRight` (defaults to `false`): moves variables always to right.
+* `alwaysVariableOnRight` (default: `false`): moves variables always to right.
 
 `DisallowYodaComparison` looks for and fixes such comparisons not only in `if` statements but in the whole code.
 
@@ -247,7 +248,7 @@ Reports useless conditions where both branches return `true` or `false`.
 
 Sniff provides the following settings:
 
-* `assumeAllConditionExpressionsAreAlreadyBoolean` (defaults to `false`).
+* `assumeAllConditionExpressionsAreAlreadyBoolean` (default: `false`).
 
 #### SlevomatCodingStandard.ControlStructures.UselessTernaryOperator 🔧
 
@@ -255,4 +256,4 @@ Reports useless ternary operator where both branches return `true` or `false`.
 
 Sniff provides the following settings:
 
-* `assumeAllConditionExpressionsAreAlreadyBoolean` (defaults to `false`).
+* `assumeAllConditionExpressionsAreAlreadyBoolean` (default: `false`).
diff --git a/app/vendor/slevomat/coding-standard/doc/files.md b/app/vendor/slevomat/coding-standard/doc/files.md
index 096c65bc0..fdb70372b 100644
--- a/app/vendor/slevomat/coding-standard/doc/files.md
+++ b/app/vendor/slevomat/coding-standard/doc/files.md
@@ -4,9 +4,9 @@
 
 Disallows long files. This sniff provides the following settings:
 
-* `includeComments`: should comments be included in the count (default value is false).
-* `includeWhitespace`: should empty lines be included in the count (default value is false).
-* `maxLinesLength`: specifies max allowed function lines length (default value is 250).
+* `includeComments` (default: `false`): should comments be included in the count.
+* `includeWhitespace` (default: `false`): should empty lines be included in the count.
+* `maxLinesLength` (default: `250`): specifies max allowed function lines length.
 
 #### SlevomatCodingStandard.Files.LineLength
 
diff --git a/app/vendor/slevomat/coding-standard/doc/functions.md b/app/vendor/slevomat/coding-standard/doc/functions.md
index 2766552c5..ab2677514 100644
--- a/app/vendor/slevomat/coding-standard/doc/functions.md
+++ b/app/vendor/slevomat/coding-standard/doc/functions.md
@@ -23,9 +23,9 @@ Reports empty functions body and requires at least a comment inside.
 
 Disallows long functions. This sniff provides the following setting:
 
-* `includeComments`: should comments be included in the count (default value is false).
-* `includeWhitespace`: should empty lines be included in the count (default value is false).
-* `maxLinesLength`: specifies max allowed function lines length (default value is 20).
+* `includeComments` (default: `false`): should comments be included in the count.
+* `includeWhitespace` (default: `false`): should empty lines be included in the count.
+* `maxLinesLength` (default: `20`): specifies max allowed function lines length.
 
 #### SlevomatCodingStandard.Functions.RequireArrowFunction 🔧
 
@@ -33,7 +33,7 @@ Requires arrow functions.
 
 Sniff provides the following settings:
 
-* `allowNested` (defaults to `true`)
+* `allowNested` (default: `true`)
 * `enable`: either to enable or not this sniff. By default, it is enabled for PHP versions 7.4 or higher.
 
 #### SlevomatCodingStandard.Functions.RequireMultiLineCall 🔧
@@ -51,7 +51,7 @@ Enforces function call to be on a single line.
 Sniff provides the following settings:
 
 * `maxLineLength`: specifies max allowed line length. If call would fit on it, it's enforced. Use 0 value to enforce for all calls, regardless of length.
-* `ignoreWithComplexParameter` (defaults to `true`): ignores calls with arrays, closures, arrow functions and nested calls.
+* `ignoreWithComplexParameter` (default: `true`): ignores calls with arrays, closures, arrow functions and nested calls.
 
 #### SlevomatCodingStandard.Functions.DisallowNamedArguments
 
diff --git a/app/vendor/slevomat/coding-standard/doc/namespaces.md b/app/vendor/slevomat/coding-standard/doc/namespaces.md
index 3c5d6cd69..643d51830 100644
--- a/app/vendor/slevomat/coding-standard/doc/namespaces.md
+++ b/app/vendor/slevomat/coding-standard/doc/namespaces.md
@@ -16,7 +16,7 @@ use LogStandard;
 Sniff provides the following settings:
 
 
-* `psr12Compatible` (defaults to `true`): sets the required order to `classes`, `functions` and `constants`. `false` sets the required order to `classes`, `constants` and `functions`.
+* `psr12Compatible` (default: `true`): sets the required order to `classes`, `functions` and `constants`. `false` sets the required order to `classes`, `constants` and `functions`.
 * `caseSensitive`: compare namespaces case sensitively, which makes this order correct:
 
 ```php
@@ -117,7 +117,7 @@ Requires only one namespace in a file.
 
 Sniff provides the following settings:
 
-* `searchAnnotations` (defaults to `false`): enables searching for mentions in annotations.
+* `searchAnnotations` (default: `false`): enables searching for mentions in annotations.
 * `namespacesRequiredToUse`: if not set, all namespaces are required to be used. When set, only mentioned namespaces are required to be used. Useful in tandem with UseOnlyWhitelistedNamespaces sniff.
 * `allowFullyQualifiedExceptions`, `specialExceptionNames` & `ignoredNames`: allows fully qualified exceptions. Useful in tandem with FullyQualifiedExceptions sniff.
 * `allowFullyQualifiedNameForCollidingClasses`: allow fully qualified name for a class with a colliding use statement.
@@ -129,23 +129,24 @@ Sniff provides the following settings:
 * `allowFallbackGlobalFunctions`: allows using global functions via fallback name without `use` (i.e. `phpversion()`).
 * `allowFallbackGlobalConstants`: allows using global constants via fallback name without `use` (i.e. `PHP_VERSION`).
 * `allowPartialUses`: allows using and referencing whole namespaces.
+* `allowWhenNoNamespace` (default: `true`): force even when there's no namespace in the file.
 
-#### SlevomatCodingStandard.Namespaces.UseFromSameNamespace 🔧
+#### SlevomatCodingStandard.Namespaces.UseDoesNotStartWithBackslash 🔧
 
-Sniff prohibits uses from the same namespace:
+Disallows leading backslash in use statement:
 
 ```php
-namespace Foo;
-
-use Foo\Bar;
+use \Foo\Bar;
 ```
 
-#### SlevomatCodingStandard.Namespaces.UseDoesNotStartWithBackslash 🔧
+#### SlevomatCodingStandard.Namespaces.UseFromSameNamespace 🔧
 
-Disallows leading backslash in use statement:
+Sniff prohibits uses from the same namespace:
 
 ```php
-use \Foo\Bar;
+namespace Foo;
+
+use Foo\Bar;
 ```
 
 #### SlevomatCodingStandard.Namespaces.UseSpacing 🔧
@@ -181,6 +182,6 @@ Looks for unused imports from other namespaces.
 
 Sniff provides the following settings:
 
-* `searchAnnotations` (defaults to `false`): enables searching for class names in annotations.
+* `searchAnnotations` (default: `false`): enables searching for class names in annotations.
 * `ignoredAnnotationNames`: case-sensitive list of annotation names that the sniff should ignore (only the name is ignored, annotation content is still searched). Useful for name collisions like `@testCase` annotation and `TestCase` class.
 * `ignoredAnnotations`: case-sensitive list of annotation names that the sniff ignore completely (both name and content are ignored). Useful for name collisions like `@group Cache` annotation and `Cache` class.
diff --git a/app/vendor/slevomat/coding-standard/doc/php.md b/app/vendor/slevomat/coding-standard/doc/php.md
index e174028cd..43604714e 100644
--- a/app/vendor/slevomat/coding-standard/doc/php.md
+++ b/app/vendor/slevomat/coding-standard/doc/php.md
@@ -46,8 +46,8 @@ Requires assertion via `assert` instead of inline documentation comments.
 
 Sniff provides the following settings:
 
-* `enableIntegerRanges` (defaults to `false`): enables support for `positive-int`, `negative-int` and `int<0, 100>`.
-* `enableAdvancedStringTypes` (defaults to `false`): enables support for `callable-string`, `numeric-string` and `non-empty-string`.
+* `enableIntegerRanges` (default: `false`): enables support for `positive-int`, `negative-int` and `int<0, 100>`.
+* `enableAdvancedStringTypes` (default: `false`): enables support for `callable-string`, `numeric-string` and `non-empty-string`.
 
 #### SlevomatCodingStandard.PHP.RequireNowdoc 🔧
 
@@ -73,7 +73,7 @@ Looks for useless parentheses.
 
 Sniff provides the following settings:
 
-* `ignoreComplexTernaryConditions` (defaults to `false`): ignores complex ternary conditions - condition must contain `&&`, `||` etc. or end of line.
+* `ignoreComplexTernaryConditions` (default: `false`): ignores complex ternary conditions - condition must contain `&&`, `||` etc. or end of line.
 
 #### SlevomatCodingStandard.PHP.UselessSemicolon 🔧
 
diff --git a/app/vendor/slevomat/coding-standard/doc/type-hints.md b/app/vendor/slevomat/coding-standard/doc/type-hints.md
index f52e2b1d3..5b482015c 100644
--- a/app/vendor/slevomat/coding-standard/doc/type-hints.md
+++ b/app/vendor/slevomat/coding-standard/doc/type-hints.md
@@ -1,5 +1,15 @@
 ## Type hints
 
+#### SlevomatCodingStandard.TypeHints.ClassConstantTypeHint 🔧
+
+* Checks for missing typehints in case they can be declared natively.
+* Reports useless `@var` annotation (or whole documentation comment) because the type of constant is always clear.
+
+Sniff provides the following settings:
+
+* `enableNativeTypeHint`: enforces native typehint. It's on by default if you're on PHP 8.3+
+* `fixableNativeTypeHint`: (default: `yes`) allows fixing native type hints. Use `no` to disable fixing, or `private` to fix only private constants (safer for inheritance/interface compatibility).
+
 #### SlevomatCodingStandard.TypeHints.DeclareStrictTypes 🔧
 
 Enforces having `declare(strict_types = 1)` at the top of each PHP file. Allows configuring how many newlines should be between the ` $value) {
diff --git a/app/vendor/squizlabs/php_codesniffer/CHANGELOG.md b/app/vendor/squizlabs/php_codesniffer/CHANGELOG.md
index 511c8eff7..70065bef8 100644
--- a/app/vendor/squizlabs/php_codesniffer/CHANGELOG.md
+++ b/app/vendor/squizlabs/php_codesniffer/CHANGELOG.md
@@ -1,10 +1,873 @@
 # Changelog
+
 The file documents changes to the PHP_CodeSniffer project.
 
 ## [Unreleased]
 
 _Nothing yet._
 
+## [3.13.2] - 2025-06-18
+
+### Changed
+- The documentation for the following sniffs has been improved:
+    - Squiz.Classes.SelfMemberReference
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
+- Various housekeeping, including improvements to the tests and documentation.
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] and [Juliette Reinders Folmer][@jrfnl] for their contributions.
+
+### Fixed
+- Fixed bug [#1135] : Squiz.Functions.FunctionDeclarationArgumentSpacing: typo in new error code `SpacingAfterSetVis\[i\]bility`.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+
+[#1135]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/1135
+
+
+## [3.13.1] - 2025-06-13
+
+### Added
+- Added support for PHP 8.4 properties with asymmetric visibility to File::getMemberProperties() through a new `set_scope` array index in the return value. [#1116]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patches.
+- Added support for PHP 8.4 (constructor promoted) properties with asymmetric visibility to File::getMethodParameters() through new `set_visibility` and `set_visibility_token` array indexes in the return value. [#1116]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patches.
+- Added support for PHP 8.4 asymmetric visibility modifiers to the following sniffs:
+    - Generic.PHP.LowerCaseKeyword [#1117]
+    - PEAR.NamingConventions.ValidVariableName [#1118]
+    - PSR2.Classes.PropertyDeclaration [#1119]
+    - Squiz.Commenting.BlockComment [#1120]
+    - Squiz.Commenting.DocCommentAlignment [#1120]
+    - Squiz.Commenting.VariableComment [#1120]
+    - Squiz.Functions.FunctionDeclarationArgumentSpacing [#1121]
+    - Squiz.Scope.MemberVarScope [#1122]
+    - Squiz.WhiteSpace.MemberVarSpacing [#1123]
+    - Squiz.WhiteSpace.ScopeKeywordSpacing [#1124]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patches.
+
+### Changed
+- The PSR2.Classes.PropertyDeclaration will now check that a set-visibility modifier keyword is placed after a potential general visibility keyword. [#1119]
+    - Errors will be reported via a new `AvizKeywordOrder` error code.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- The Squiz.Functions.FunctionDeclarationArgumentSpacing will now check spacing after a set-visibility modifier keyword. [#1121]
+    - Errors will be reported via a new `SpacingAfterSetVisibility` error code.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- The Squiz.Scope.MemberVarScope will now flag missing "read" visibility, when "write" visibility is set, under a separate error code `AsymReadMissing`. [#1122]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- The documentation for the following sniffs has been improved:
+    - PEAR.Classes.ClassDeclaration
+    - Squiz.WhiteSpace.FunctionOpeningBraceSpace
+    - Thanks to [Brian Dunne][@braindawg] and [Rodrigo Primo][@rodrigoprimo] for the patches.
+- Various housekeeping, including improvements to the tests and documentation.
+    - Thanks to [Dan Wallis][@fredden], [Rodrigo Primo][@rodrigoprimo] and [Juliette Reinders Folmer][@jrfnl] for their contributions.
+
+### Other
+- The latest PHP_CodeSniffer XSD file is now available via the following permalink: . [#1094]
+    Older XSD files can be referenced via permalinks based on their minor: `https://schema.phpcodesniffer.com/#.#/phpcs.xsd`.
+- The GPG signature for the PHAR files has been rotated. The new fingerprint is: D91D86963AF3A29B6520462297B02DD8E5071466.
+
+[#1094]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/1094
+[#1116]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/1116
+[#1117]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/1117
+[#1118]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/1118
+[#1119]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/1119
+[#1120]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/1120
+[#1121]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/1121
+[#1122]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/1122
+[#1123]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/1123
+[#1124]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/1124
+
+
+## [3.13.0] - 2025-05-11
+
+### Added
+- Added support for PHP 8.4 asymmetric visibility modifiers to the tokenizer. [#871]
+    - Thanks to [Daniel Scherzer][@DanielEScherzer] for the patch.
+- Added support for PHP 8.4 `final` properties to the following sniffs:
+    - PSR2.Classes.PropertyDeclaration [#950]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patches.
+
+### Changed
+- Generic.WhiteSpace.LanguageConstructSpacing: will now also check the spacing after the `goto` language construct keyword. [#917]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- The PSR2.Classes.PropertyDeclaration will now check that the `final` modifier keyword is placed before a visibility keyword. [#950]
+    - Errors will be reported via a new `FinalAfterVisibility` error code.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Improved Help information about the `--reports` CLI flag. [#1078]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- The documentation for the following sniffs has been improved:
+    - PSR1.Files.SideEffects
+    - PSR2.ControlStructures.SwitchDeclaration
+    - PSR2.Namespaces.NamespaceDeclaration
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patches.
+- Various housekeeping, including improvements to the tests and documentation.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for their contributions.
+
+### Deprecated
+
+- Nearly everything which was soft deprecated before is now hard deprecated and will show deprecation notices:
+    - This applies to:
+        - All sniffs which will be removed in 4.0. [#888]
+        - The deprecated Generator methods. [#889]
+        - The old array property setting format (via comma separated strings). [#890]
+        - Sniffs not implementing the `PHP_CodeSniffer\Sniffs\Sniff` interface. [#891]
+        - Sniffs not following the naming conventions. [#892]
+        - Standards called Internal. [#893]
+        - Sniffs which don't listen for PHP, like JS/CSS specific sniffs. [#894]
+    - The deprecation notices can be silenced by using the `-q` (=quiet) CLI flag.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patches.
+
+### Fixed
+- Fixed bug [#1040] : Generic.Strings.UnnecessaryHeredoc - false positive for heredocs containing escape sequences.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#1040] : Generic.Strings.UnnecessaryHeredoc - fixer would not clean up escape sequences which aren't necessary in nowdocs.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#1048] : A file under scan would sometimes be updated with partial fixes, even though the file "failed to fix".
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+
+### Other
+**Calling all testers!**
+
+The first beta release for PHP_CodeSniffer 4.0 has been tagged. Please help by testing the beta release and reporting any issues you run into.
+Upgrade guides for both [ruleset maintainers/end-users][wiki-upgrade-guide-users-40], as well as for [sniff developers and integrators][wiki-upgrade-guide-devs-40], have been published to the Wiki to help smooth the transition.
+
+[wiki-upgrade-guide-users-40]: https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki/Version-4.0-User-Upgrade-Guide
+[wiki-upgrade-guide-devs-40]:  https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki/Version-4.0-Developer-Upgrade-Guide
+
+[#871]:  https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/871
+[#888]:  https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/888
+[#889]:  https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/889
+[#890]:  https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/890
+[#891]:  https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/891
+[#892]:  https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/892
+[#893]:  https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/893
+[#894]:  https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/894
+[#917]:  https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/917
+[#950]:  https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/950
+[#1040]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/1040
+[#1048]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/1048
+[#1078]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/1078
+
+## [3.12.2] - 2025-04-13
+
+### Added
+- Added support for PHP 8.4 `final` properties to the following sniffs:
+    - Generic.PHP.LowerCaseConstant [#948]
+    - Generic.PHP.UpperCaseConstant [#948]
+    - Squiz.Commenting.DocCommentAlignment [#951]
+    - Squiz.Commenting.VariableComment [#949]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patches.
+
+### Changed
+- Tokenizer/PHP: a PHP open tag at the very end of a file will now always be tokenized as T_OPEN_TAG, independently of the PHP version. [#937]
+    - Previously, a PHP open tag at the end of a file was not tokenized as an open tag on PHP < 7.4 and the tokenization would depend on the `short_open_tag` setting.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- PEAR.Commenting.FunctionComment: improved message for "blank lines between docblock and declaration" check. [#830]
+- The documentation for the following sniffs has been improved:
+    - Generic.Functions.OpeningFunctionBraceBsdAllman
+    - Generic.Functions.OpeningFunctionBraceKernighanRitchie
+    - Generic.WhiteSpace.LanguageConstructSpacing
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patches.
+- Various housekeeping, including improvements to the tests and documentation.
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] and [Juliette Reinders Folmer][@jrfnl] for their contributions.
+
+### Fixed
+- Fixed bug [#830] : PEAR.Commenting.FunctionComment will no longer remove blank lines within attributes.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#929] : Generic.PHP.ForbiddenFunctions: prevent false positives/negatives for code interlaced with comments.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#934] : Generic.PHP.LowerCaseConstant and Generic.PHP.UpperCaseConstant will now correctly ignore DNF types for properties.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#936] : Squiz.Commenting.FunctionCommentThrowTag: sniff would bow out when function has attributes attached, leading to false negatives.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#940] : Squiz.Commenting.VariableComment: false positive for missing docblock for properties using DNF types.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#944] : Squiz.Commenting.FunctionComment did not support DNF/intersection types in `@param` tags.
+    - Thanks to [Jeffrey Angenent][@devfrey] for the patch.
+- Fixed bug [#945] : Squiz.WhiteSpace.FunctionSpacing would get confused when there are two docblocks above a function declaration.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#947] : Squiz.Commenting.FunctionCommentThrowTag: prevent false positives/negatives for code interlaced with comments.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#951] : Squiz.Commenting.DocCommentAlignment did not examine docblocks for `final` classes.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#955] : Potential race condition, leading to a fatal error, when both the `Diff` + the `Code` reports are requested and caching is on.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#956] : Generic.WhiteSpace.ScopeIndent: undefined array index notice when running in debug mode.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+
+[#830]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/830
+[#929]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/929
+[#934]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/934
+[#936]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/936
+[#937]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/937
+[#940]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/940
+[#944]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/944
+[#945]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/945
+[#947]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/947
+[#948]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/948
+[#949]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/949
+[#951]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/951
+[#955]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/955
+[#956]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/956
+
+## [3.12.1] - 2025-04-04
+
+### Added
+- Documentation for the following sniffs:
+    - Squiz.Commenting.BlockComment
+    - Thanks to [Colin Stewart][@costdev] for the patch.
+
+### Changed
+- Generic.WhiteSpace.HereNowdocIdentifierSpacing: improved error message text.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Various housekeeping, including improvements to the tests and documentation.
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] and [Juliette Reinders Folmer][@jrfnl] for their contributions.
+
+### Deprecated
+- The `Generic.Functions.CallTimePassByReference` sniff. See [#921].
+    - This sniff will be removed in version 4.0.0.
+
+### Fixed
+- Fixed bug [#906] : Fixer: prevent `InvalidArgumentException`s when displaying verbose information.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#907] : Tokenizer/PHP: tokenization of tokens related to union, intersection and DNF types in combination with PHP 8.4 final properties.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#908] : Tokenizer/PHP: tokenization of `?` in nullable types for readonly properties.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#916] : Tokenizer/PHP: `goto` was not recognized as a terminating statement for a case/default in a switch control structure.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+
+### Other
+- PHP_CodeSniffer 4.0 is coming soon! Interested in a sneak peek ? Join the live stream at any time on April 14, 15, 17 or 18.
+    Read the open invitation ([#924]) for all the details.
+
+[#906]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/906
+[#907]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/907
+[#908]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/908
+[#916]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/916
+[#921]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/921
+[#924]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/924
+
+## [3.12.0] - 2025-03-18
+
+### Added
+- Added support for PHP 8.4 `final` properties to File::getMemberProperties() through a new `is_final` array index in the return value. [#834]
+    - Thanks to [Daniel Scherzer][@DanielEScherzer] for the patch.
+- Generators/HTML: each section title now has a unique anchor link, which can be copied when hovering over a title. [#859]
+    - This should make sharing a link to a specific section of the documentation more straight-forward.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Documentation for the following sniffs:
+    - Squiz.Classes.ClassFileName
+    - Squiz.Classes.ValidClassName
+    - Thanks to [Brian Dunne][@braindawg] for the patches.
+
+### Changed
+- PHPCBF: the messaging when no fixable errors are found will now distinguish between "No violations" (at all) versus "No fixable errors". [#806]
+    - Thanks to [Peter Wilson][@peterwilsoncc] for the patch.
+- The `-h` (Help) option now contains a more extensive list of "config" options which can be set. [#809]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Improved error message when invalid sniff codes are supplied to `--sniffs` or `--exclude` command line arguments. [#344]
+    - Thanks to [Dan Wallis][@fredden] for the patch.
+- Improved error message when an invalid generator name is supplied to the `--generator` command line argument. [#709], [#771]
+    - The generator name will now also always be handled case-insensitively, independently of the OS used.
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
+- The user will be shown an informative error message for sniffs missing one of the required methods. [#873]
+    - Previously this would result in a fatal error.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Ruleset processing will now be allowed to run to its conclusion - barring critical errors - before displaying all ruleset errors in one go. [#857]
+    - Previously an error in a ruleset would cause PHPCS to exit immediately and show only one error at a time.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Generators: XML documentation files which don't contain any actual documentation will now silently be ignored. [#755]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Generators: when the `title` attribute is missing, the documentation generation will now fall back to the sniff name as the title. [#820]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Generators: cleaner output based on the elements of the documentation which are available. [#819], [#821]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Generators/HTML: improved display of code tables by using semantic HTML. [#854]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Squiz.Classes.ClassFileName: recommend changing the file name instead of changing the class name. [#845]
+    - This prevents unactionable recommendations due to the file name not translating to a valid PHP symbol name.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Squiz.Functions.FunctionDeclarationArgumentSpacing: incorrect spacing after a comma followed by a promoted property has an improved error message and will now be flagged with the `SpacingBeforePropertyModifier` or `NoSpaceBeforePropertyModifier` error codes. [#792]
+    - This was previously already flagged, but using either the `SpacingBeforeHint` or `NoSpaceBeforeHint` error code, which was misleading.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Squiz.Functions.FunctionDeclarationArgumentSpacing: the sniff will now also check the spacing after property modifiers for promoted properties in constructor methods. [#792]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Squiz.WhiteSpace.ScopeKeywordSpacing: the sniff will now also check the spacing after the `final` and `abstract` modifier keywords. [#604]
+    - Thanks to [Klaus Purer][@klausi] for the patch.
+- The following sniff(s) have received efficiency improvements:
+    - Squiz.WhiteSpace.ScopeKeywordSpacing
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patches.
+- Incorrectly set inline properties (in test case files) will be silently ignored again. [#884]
+    - This removes the `Internal.PropertyDoesNotExist` error code.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- The AbstractMethodUnitTest class will now flag duplicate test case markers in a test case file. [#773]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Various housekeeping, including improvements to the tests and documentation.
+    - Thanks to [Asis Pattisahusiwa][@asispts], [Dan Wallis][@fredden], [Rodrigo Primo][@rodrigoprimo] and [Juliette Reinders Folmer][@jrfnl] for their contributions.
+
+### Deprecated
+All deprecation are slated for removal in PHP_CodeSniffer 4.0.
+
+- Support for sniffs not implementing the PHPCS `Sniff` interface. See [#694].
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Support for including sniffs which don't comply with the PHPCS naming conventions (by referencing the sniff file directly). See [#689].
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Support for external standards named "Internal". See [#799].
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- The following Generator methods are now (soft) deprecated. See [#755]:
+    - `PHP_CodeSniffer\Generators\Text::printTitle()` in favour of `PHP_CodeSniffer\Generators\Text::getFormattedTitle()`
+    - `PHP_CodeSniffer\Generators\Text::printTextBlock()` in favour of `PHP_CodeSniffer\Generators\Text::getFormattedTextBlock()`
+    - `PHP_CodeSniffer\Generators\Text::printCodeComparisonBlock()` in favour of `PHP_CodeSniffer\Generators\Text::getFormattedCodeComparisonBlock()`
+    - `PHP_CodeSniffer\Generators\Markdown::printHeader()` in favour of `PHP_CodeSniffer\Generators\Markdown::getFormattedHeader()`
+    - `PHP_CodeSniffer\Generators\Markdown::printFooter()` in favour of `PHP_CodeSniffer\Generators\Markdown::getFormattedFooter()`
+    - `PHP_CodeSniffer\Generators\Markdown::printTextBlock()` in favour of `PHP_CodeSniffer\Generators\Markdown::getFormattedTextBlock()`
+    - `PHP_CodeSniffer\Generators\Markdown::printCodeComparisonBlock()` in favour of `PHP_CodeSniffer\Generators\Markdown::getFormattedCodeComparisonBlock()`
+    - `PHP_CodeSniffer\Generators\HTML::printHeader()` in favour of `PHP_CodeSniffer\Generators\HTML::getFormattedHeader()`
+    - `PHP_CodeSniffer\Generators\HTML::printToc()` in favour of `PHP_CodeSniffer\Generators\HTML::getFormattedToc()`
+    - `PHP_CodeSniffer\Generators\HTML::printFooter()` in favour of `PHP_CodeSniffer\Generators\HTML::getFormattedFooter()`
+    - `PHP_CodeSniffer\Generators\HTML::printTextBlock()` in favour of `PHP_CodeSniffer\Generators\HTML::getFormattedTextBlock()`
+    - `PHP_CodeSniffer\Generators\HTML::printCodeComparisonBlock()` in favour of `PHP_CodeSniffer\Generators\HTML::getFormattedCodeComparisonBlock()`
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+
+### Fixed
+- Fixed bug [#794] : Generators: prevent fatal error when the XML documentation does not comply with the expected format.
+    - It is recommended to validate XML documentation files against the XSD file: 
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#814] : Generic.NamingConventions.ConstructorName: prevent potential fatal errors during live coding.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#816] : File::getDeclarationName(): prevent incorrect result for unfinished closures during live coding.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#817] : Squiz.Classes.ValidClassName: ignore comments when determining the name to be validated.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#825] : Squiz.Classes.ClassDeclaration: false positives when the next thing after a class was a function with an attribute attached.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#826] : Squiz.WhiteSpace.FunctionSpacing: prevent incorrect some results when attributes are attached to a function.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#827] : PEAR.Functions.FunctionDeclaration: fixer conflict over an unfinished closure during live coding.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#828] : Squiz.WhiteSpace.MemberVarSpacing: allow for `readonly` properties.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#832] : Squiz.WhiteSpace.MemberVarSpacing: prevent potential fixer conflict during live coding.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#833] : Squiz.PHP.EmbeddedPhp: fixer conflict when a PHP open tag for a multi-line snippet is found on the same line as a single-line embedded PHP snippet.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#833] : Squiz.PHP.EmbeddedPhp: incorrect indent calculation in certain specific situations.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#835] : Generic.PHP.DisallowShortOpenTag: don't act on parse errors.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#838] : Squiz.PHP.EmbeddedPhp: no new line before close tag was incorrectly enforced when a preceding OO construct or function had a trailing comment after the close curly.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#840] : Squiz.WhiteSpace.MemberVarSpacing: more accurate reporting on blank lines in the property "pre-amble" (i.e. docblock, attributes).
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#845] : Squiz.Classes.ClassFileName: don't throw an incorrect error for an unfinished OO declaration during live coding.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#865] : Setting an array property to an empty array from an XML ruleset now works correctly.
+    - Previously, the property value would be set to `[0 => '']`.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#866] : Squiz.WhiteSpace.FunctionOpeningBraceSpace: XML docs were not accessible due to an issue with the file name.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+
+### Other
+- A new [wiki page][wiki-about-standards] is available to clarify the difference between a project ruleset and an external standard.
+    - This wiki page also contains detailed information about the naming conventions external standards must comply with.
+- A new [XMLLint validate][xmllint-validate] action runner is available which can be used in CI to validate rulesets for PHP_CodeSniffer against the XSD.
+
+[wiki-about-standards]: https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki/About-Standards-for-PHP_CodeSniffer
+[xmllint-validate]: https://github.com/marketplace/actions/xmllint-validate
+
+[#344]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/344
+[#604]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/604
+[#689]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/689
+[#694]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/694
+[#709]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/709
+[#755]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/755
+[#771]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/771
+[#773]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/773
+[#792]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/792
+[#794]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/794
+[#799]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/799
+[#806]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/806
+[#809]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/809
+[#814]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/814
+[#816]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/816
+[#817]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/817
+[#819]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/819
+[#820]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/820
+[#821]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/821
+[#825]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/825
+[#826]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/826
+[#827]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/827
+[#828]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/828
+[#832]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/832
+[#833]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/833
+[#834]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/834
+[#835]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/835
+[#838]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/838
+[#840]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/840
+[#845]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/845
+[#854]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/854
+[#857]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/857
+[#859]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/859
+[#865]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/865
+[#866]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/866
+[#873]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/873
+[#884]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/884
+
+## [3.11.3] - 2025-01-23
+
+### Changed
+- Generic.ControlStructures.InlineControlStructure no longer unnecessarily listens for T_SWITCH tokens. [#595]
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
+- Squiz.Functions.FunctionDeclarationArgumentSpacing: improvements to error message for `SpaceBeforeComma` error. [#783]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- The following sniff(s) have received efficiency improvements:
+    - Squiz.Functions.FunctionDeclarationArgumentSpacing
+    - Thanks to [Dan Wallis][@fredden] and [Juliette Reinders Folmer][@jrfnl] for the patches.
+- Various housekeeping, including improvements to the tests and documentation.
+    - Thanks to [Michał Bundyra][@michalbundyra], [Rodrigo Primo][@rodrigoprimo] and [Juliette Reinders Folmer][@jrfnl] for their contributions.
+
+### Fixed
+- Fixed bug [#620] : Squiz.Functions.FunctionDeclarationArgumentSpacing: newlines after type will now be handled by the fixer. This also prevents a potential fixer conflict.
+    - Thanks to [Dan Wallis][@fredden] for the patch.
+- Fixed bug [#782] : Tokenizer/PHP: prevent an "Undefined array key" notice during live coding for unfinished arrow functions.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#783] : Squiz.Functions.FunctionDeclarationArgumentSpacing: new line after reference token was not flagged nor fixed.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#783] : Squiz.Functions.FunctionDeclarationArgumentSpacing: new line after variadic token was not flagged nor fixed.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#783] : Squiz.Functions.FunctionDeclarationArgumentSpacing: new line before/after the equal sign for default values was not flagged nor fixed when `equalsSpacing` was set to `0`.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#783] : Squiz.Functions.FunctionDeclarationArgumentSpacing: fixer conflict when a new line is found before/after the equal sign for default values and `equalsSpacing` was set to `1`.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#783] : Squiz.Functions.FunctionDeclarationArgumentSpacing: fixer for spacing before/after equal sign could inadvertently remove comment.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#783] : Squiz.Functions.FunctionDeclarationArgumentSpacing: fixer will now handle comments between the end of a parameter and a comma more cleanly.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#784] : Squiz.WhiteSpace.FunctionSpacing: prevent fixer conflict when a multi-line docblock would start on the same line as the function close curly being examined.
+    - Thanks to [Klaus Purer][@klausi] for the patch
+
+[#595]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/595
+[#620]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/620
+[#782]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/782
+[#783]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/783
+[#784]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/784
+
+## [3.11.2] - 2024-12-11
+
+### Changed
+- Generators/HTML + Markdown: the output will now be empty (no page header/footer) when there are no docs to display. [#687]
+    - This is in line with the Text Generator which already didn't produce output if there are no docs.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Generators/HTML: only display a Table of Contents when there is more than one sniff with documentation. [#697]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Generators/HTML: improved handling of line breaks in `` blocks. [#723]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Generators/Markdown: improved compatibility with the variety of available markdown parsers. [#722]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Generators/Markdown: improved handling of line breaks in `` blocks. [#737]
+    - This prevents additional paragraphs from being displayed as code blocks.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Generic.NamingConventions.UpperCaseConstantName: the exact token containing the non-uppercase constant name will now be identified with more accuracy. [#665]
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
+- Generic.Functions.OpeningFunctionBraceKernighanRitchie: minor improvement to the error message wording. [#736]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Various housekeeping, including improvements to the tests and documentation.
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] and [Juliette Reinders Folmer][@jrfnl] for their contributions.
+
+### Fixed
+- Fixed bug [#527] : Squiz.Arrays.ArrayDeclaration: short lists within a foreach condition should be ignored.
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
+- Fixed bug [#665] : Generic.NamingConventions.UpperCaseConstantName: false positives and false negatives when code uses unconventional spacing and comments when calling `define()`.
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
+- Fixed bug [#665] : Generic.NamingConventions.UpperCaseConstantName: false positive when a constant named `DEFINE` is encountered.
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
+- Fixed bug [#665] : Generic.NamingConventions.UpperCaseConstantName: false positive for attribute class called `define`.
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
+- Fixed bug [#665] : Generic.NamingConventions.UpperCaseConstantName: false positive when handling the instantiation of a class named `define`.
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
+- Fixed bug [#688] : Generators/Markdown could leave error_reporting in an incorrect state.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#698] : Generators/Markdown : link in the documentation footer would not parse as a link.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#738] : Generators/Text: stray blank lines after code sample titles.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#739] : Generators/HTML + Markdown: multi-space whitespace within a code sample title was folded into a single space.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+
+[#527]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/527
+[#665]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/665
+[#687]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/687
+[#688]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/688
+[#697]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/697
+[#698]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/698
+[#722]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/722
+[#723]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/723
+[#736]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/736
+[#737]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/737
+[#738]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/738
+[#739]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/739
+
+## [3.11.1] - 2024-11-16
+
+### Changed
+- Output from the `--generator=...` feature will respect the OS-expected EOL char in more places. [#671]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Various housekeeping, including improvements to the tests and documentation.
+    - Thanks to [Bartosz Dziewoński][@MatmaRex] and [Juliette Reinders Folmer][@jrfnl] for their contributions.
+
+### Fixed
+- Fixed bug [#674] : Generic.WhiteSpace.HereNowdocIdentifierSpacing broken XML documentation
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Fixed bug [#675] : InvalidArgumentException when a ruleset includes a sniff by file name and the included sniff does not comply with the PHPCS naming conventions.
+    - Notwithstanding this fix, it is strongly recommended to ensure custom sniff classes comply with the PHPCS naming conventions.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+
+[#671]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/671
+[#674]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/674
+[#675]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/675
+
+## [3.11.0] - 2024-11-12
+
+### Added
+- Runtime support for PHP 8.4. All known PHP 8.4 deprecation notices have been fixed.
+    - Syntax support for new PHP 8.4 features will follow in a future release.
+    - If you find any PHP 8.4 deprecation notices which were missed, please report them.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patches.
+- Tokenizer support for PHP 8.3 "yield from" expressions with a comment between the keywords. [#529], [#647]
+    - Sniffs explicitly handling T_YIELD_FROM tokens may need updating. The PR description contains example code for use by sniff developers.
+    - Additionally, the following sniff has been updated to support "yield from" expressions with comments:
+        - Generic.WhiteSpace.LanguageConstructSpacing
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- New `Generic.WhiteSpace.HereNowdocIdentifierSpacing` sniff. [#586], [#637]
+    - Forbid whitespace between the `<<<` and the identifier string in heredoc/nowdoc start tokens.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- New `Generic.Strings.UnnecessaryHeredoc` sniff. [#633]
+    - Warns about heredocs without interpolation or expressions in the body text and can auto-fix these to nowdocs.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Documentation for the following sniffs:
+    - Generic.Arrays.ArrayIndent
+    - Squiz.PHP.Heredoc
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] and [Juliette Reinders Folmer][@jrfnl] for the patches.
+
+### Changed
+- The Common::getSniffCode() method will now throw an InvalidArgumentException exception if an invalid `$sniffClass` is passed. [#524], [#625]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Documentation generated using the `--generator=...` feature will now always be presented in natural order based on the sniff name(s). [#668]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Minor improvements to the display of runtime information. [#658]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Squiz.Commenting.PostStatementComment: trailing annotations in PHP files will now be reported under a separate, non-auto-fixable error code `AnnotationFound`. [#560], [#627]
+    - This prevents (tooling related) annotations from taking on a different meaning when moved by the fixer.
+    - The separate error code also allows for selectively excluding it to prevent the sniff from triggering on trailing annotations, while still forbidding other trailing comments.
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
+- Squiz.ControlStructures.ForEachLoopDeclaration: the `SpacingAfterOpen` error code has been replaced by the `SpaceAfterOpen` error code. The latter is a pre-existing code. The former appears to have been a typo. [#582]
+    - Thanks to [Dan Wallis][@fredden] for the patch.
+- The following sniff(s) have received efficiency improvements:
+    - Generic.Classes.DuplicateClassName
+    - Generic.NamingConventions.ConstructorName
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] and [Juliette Reinders Folmer][@jrfnl] for the patches.
+- Various housekeeping, including improvements to the tests and documentation.
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] and [Juliette Reinders Folmer][@jrfnl] for their contributions.
+
+### Fixed
+- Fixed bug [#3808][sq-3808] : Generic.WhiteSpace.ScopeIndent would throw false positive for tab indented multi-token yield from expression.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#630] : The tokenizer could inadvertently transform "normal" parentheses to DNF parentheses, when a function call was preceded by a switch-case / alternative syntax control structure colon.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#645] : On PHP 5.4, if yield was used as the declaration name for a function declared to return by reference, the function name would incorrectly be tokenized as T_YIELD instead of T_STRING.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#647] : Tokenizer not applying tab replacement in single token "yield from" keywords.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#647] : Generic.WhiteSpace.DisallowSpaceIndent did not flag space indentation in multi-line yield from.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#647] : Generic.WhiteSpace.DisallowTabIndent did not flag tabs inside yield from.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#652] : Generic.NamingConventions.ConstructorName: false positives for PHP-4 style calls to PHP-4 style parent constructor when a method with the same name as the parent class was called on another class.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#652] : Generic.NamingConventions.ConstructorName: false negatives for PHP-4 style calls to parent constructor for function calls with whitespace and comments in unconventional places.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#653] : Generic.Classes.DuplicateClassName : the sniff did not skip namespace keywords used as operators, which could lead to false positives.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#653] : Generic.Classes.DuplicateClassName : sniff going into an infinite loop during live coding.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#653] : Generic.Classes.DuplicateClassName : false positives/negatives when a namespace declaration contained whitespace or comments in unconventional places.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#653] : Generic.Classes.DuplicateClassName : namespace for a file going in/out of PHP was not remembered/applied correctly.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+
+[sq-3808]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3808
+[#524]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/524
+[#529]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/529
+[#560]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/560
+[#582]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/582
+[#586]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/586
+[#625]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/625
+[#627]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/627
+[#630]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/630
+[#633]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/633
+[#637]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/637
+[#645]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/645
+[#647]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/647
+[#652]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/652
+[#653]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/653
+[#658]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/658
+[#668]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/668
+
+## [3.10.3] - 2024-09-18
+
+### Changed
+- Various housekeeping, including improvements to the tests and documentation.
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] and [Juliette Reinders Folmer][@jrfnl] for their contributions.
+
+### Fixed
+- Fixed bug [#553] : Squiz.Classes.SelfMemberReference: false negative(s) when namespace operator was encountered between the namespace declaration and the OO declaration.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#579] : AbstractPatternSniff: potential PHP notice during live coding.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#580] : Squiz.Formatting.OperatorBracket: potential PHP notice during live coding.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#581] : PSR12.ControlStructures.ControlStructureSpacing: prevent fixer conflict by correctly handling multiple empty newlines before the first condition in a multi-line control structure.
+    - Thanks to [Dan Wallis][@fredden] for the patch.
+- Fixed bug [#585] : Tokenizer not applying tab replacement in heredoc/nowdoc openers.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#588] : Squiz.PHP.EmbeddedPhp false positive when checking spaces after a PHP short open tag.
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
+- Fixed bug [#597] : Generic.PHP.LowerCaseKeyword did not flag nor fix non-lowercase anonymous class keywords.
+    - Thanks to [Marek Štípek][@maryo] for the patch.
+- Fixed bug [#598] : Squiz.PHP.DisallowMultipleAssignments: false positive on assignments to variable property on object stored in array.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#608] : Squiz.Functions.MultiLineFunctionDeclaration did not take (parameter) attributes into account when checking for one parameter per line.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+
+### Other
+- The provenance of PHAR files associated with a release can now be verified via [GitHub Artifact Attestations][ghattest] using the [GitHub CLI tool][ghcli] with the following command: `gh attestation verify [phpcs|phpcbf].phar -o PHPCSStandards`. [#574]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+
+[#553]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/553
+[#574]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/574
+[#579]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/579
+[#580]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/580
+[#581]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/581
+[#585]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/585
+[#588]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/588
+[#597]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/597
+[#598]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/598
+[#608]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/608
+
+[ghcli]:    https://cli.github.com/
+[ghattest]: https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds
+
+## [3.10.2] - 2024-07-22
+
+### Changed
+- The following sniff(s) have received efficiency improvements:
+    - Generic.Functions.FunctionCallArgumentSpacing
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- The array format of the information passed to the `Reports::generateFileReport()` method is now documented in the Reports interface. [#523]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Various housekeeping, including improvements to the tests and documentation.
+    - Thanks to [Bill Ruddock][@biinari], [Dan Wallis][@fredden], [Klaus Purer][@klausi], [Rodrigo Primo][@rodrigoprimo] and [Juliette Reinders Folmer][@jrfnl] for their contributions.
+
+### Fixed
+- Fixed bug [#513] : Generic.Functions.FunctionCallArgumentSpacing did not ignore the body of a match expressions passed as a function argument, which could lead to false positives.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#533] : Generic.WhiteSpace.DisallowTabIndent: tab indentation for heredoc/nowdoc closers will no longer be auto-fixed to prevent parse errors. The issue will still be reported.
+    - The error code for heredoc/nowdoc indentation using tabs has been made more specific - `TabsUsedHeredocCloser` - to allow for selectively excluding the indentation check for heredoc/nowdoc closers.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#534] : Generic.WhiteSpace.DisallowSpaceIndent did not report on space indentation for PHP 7.3 flexible heredoc/nowdoc closers.
+    - Closers using space indentation will be reported with a dedicated error code: `SpacesUsedHeredocCloser`.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#537] : Squiz.PHP.DisallowMultipleAssignments false positive for list assignments at the start of a new PHP block after an embedded PHP statement.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#551] : Squiz.PHP.DisallowMultipleAssignments prevent false positive for function parameters during live coding.
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
+- Fixed bug [#554] : Generic.CodeAnalysis.UselessOverridingMethod edge case false negative when the call to the parent method would end on a PHP close tag.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#555] : Squiz.Classes.SelfMemberReference edge case false negative when the namespace declaration would end on a PHP close tag.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+
+[#513]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/513
+[#523]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/523
+[#533]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/533
+[#534]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/534
+[#537]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/537
+[#551]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/551
+[#554]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/554
+[#555]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/555
+
+## [3.10.1] - 2024-05-22
+
+### Added
+- Documentation for the following sniffs:
+    - Generic.Commenting.DocComment
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
+
+### Changed
+- The following have received efficiency improvements:
+    - Type handling in the PHP Tokenizer
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Various housekeeping, including improvements to the tests and documentation.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for their contributions.
+
+### Fixed
+- Fixed bug [#110], [#437], [#475] : `File::findStartOfStatement()`: the start of statement/expression determination for tokens in parentheses/short array brackets/others scopes, nested within match expressions, was incorrect in most cases.
+    The trickle down effect of the bug fixes made to the `File::findStartOfStatement()` method, is that the Generic.WhiteSpace.ScopeIndent and the PEAR.WhiteSpace.ScopeIndent sniffs should now be able to correctly determine and fix the indent for match expressions containing nested expressions.
+    These fixes also fix an issue with the `Squiz.Arrays.ArrayDeclaration` sniff and possibly other, unreported bugs.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#504] : The tokenizer could inadvertently mistake the last parameter in a function call using named arguments for a DNF type.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#508] : Tokenizer/PHP: extra hardening against handling parse errors in the type handling layer.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+
+[#110]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/110
+[#437]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/437
+[#475]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/475
+[#504]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/504
+[#508]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/508
+
+## [3.10.0] - 2024-05-20
+
+### Added
+- Tokenizer support for PHP 8.2 Disjunctive Normal Form (DNF) types. [#3731][sq-3731], [#387], [#461]
+    - Includes new `T_TYPE_OPEN_PARENTHESIS` and `T_TYPE_CLOSE_PARENTHESIS` tokens to represent the parentheses in DNF types.
+    - These new tokens, like other parentheses, will have the `parenthesis_opener` and `parenthesis_closer` token array indexes set and the tokens between them will have the `nested_parenthesis` index.
+    - The `File::getMethodProperties()`, `File::getMethodParameters()` and `File::getMemberProperties()` methods now all support DNF types. [#471], [#472], [#473]
+    - Additionally, the following sniff has been updated to support DNF types:
+        - Generic.PHP.LowerCaseType [#478]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patches.
+- Documentation for the following sniffs:
+    - Squiz.WhiteSpace.FunctionClosingBraceSpace
+    - Thanks to [Przemek Hernik][@przemekhernik] for the patch.
+
+### Changed
+- The help screens have received a face-lift for improved usability and readability. [#447]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch and thanks to [Colin Stewart][@costdev], [Gary Jones][@GaryJones] and [@mbomb007] for reviewing.
+- The Squiz.Commenting.ClosingDeclarationComment sniff will now also examine and flag closing comments for traits. [#442]
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
+- The following sniff(s) have efficiency improvements:
+    - Generic.Arrays.ArrayIndent
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
+- The autoloader will now always return a boolean value indicating whether it has loaded a class or not. [#479]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Various housekeeping, including improvements to the tests and documentation.
+    - Thanks to [Dan Wallis][@fredden], [Danny van der Sluijs][@DannyvdSluijs], [Rodrigo Primo][@rodrigoprimo] and [Juliette Reinders Folmer][@jrfnl] for their contributions.
+
+### Fixed
+- Fixed bug [#466] : Generic.Functions.CallTimePassByReference was not flagging call-time pass-by-reference in class instantiations using the self/parent/static keywords.
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
+- Fixed bug [#494] : edge case bug in tokenization of an empty block comment.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#494] : edge case bug in tokenization of an empty single-line DocBlock.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#499] : Generic.ControlStructures.InlineControlStructure now handles statements with a comment between `else` and `if` correctly.
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
+
+[sq-3731]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3731
+[#387]:    https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/387
+[#442]:    https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/442
+[#447]:    https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/447
+[#461]:    https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/461
+[#466]:    https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/466
+[#471]:    https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/471
+[#472]:    https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/472
+[#473]:    https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/473
+[#478]:    https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/478
+[#479]:    https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/479
+[#494]:    https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/494
+[#499]:    https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/499
+
+## [3.9.2] - 2024-04-24
+
+### Changed
+- The Generic.ControlStructures.DisallowYodaConditions sniff no longer listens for the null coalesce operator. [#458]
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
+- Various housekeeping, including improvements to the tests and documentation.
+    - Thanks to [Dan Wallis][@fredden], [Rodrigo Primo][@rodrigoprimo] and [Juliette Reinders Folmer][@jrfnl] for their contributions.
+
+### Fixed
+- Fixed bug [#381] : Squiz.Commenting.ClosingDeclarationComment could throw the wrong error when the close brace being examined is at the very end of a file.
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
+- Fixed bug [#385] : Generic.CodeAnalysis.JumbledIncrementer improved handling of parse errors/live coding.
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
+- Fixed bug [#394] : Generic.Functions.CallTimePassByReference was not flagging call-time pass-by-reference in anonymous class instantiations
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
+- Fixed bug [#420] : PEAR.Functions.FunctionDeclaration could run into a blocking PHP notice while fixing code containing a parse error.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#421] : File::getMethodProperties() small performance improvement & more defensive coding.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#423] : PEAR.WhiteSpace.ScopeClosingBrace would have a fixer conflict with itself when a close tag was preceded by non-empty inline HTML.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#424] : PSR2.Classes.ClassDeclaration using namespace relative interface names in the extends/implements part of a class declaration would lead to a fixer conflict.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#427] : Squiz.Operators.OperatorSpacing would have a fixer conflict with itself when an operator was preceeded by a new line and the previous line ended in a comment.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#430] : Squiz.ControlStructures.ForLoopDeclaration: fixed potential undefined array index notice
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#431] : PSR2.Classes.ClassDeclaration will no longer try to auto-fix multi-line interface implements statements if these are interlaced with comments on their own line. This prevents a potential fixer conflict.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#453] : Arrow function tokenization was broken when the return type was a stand-alone `true` or `false`; or contained `true` or `false` as part of a union type.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+
+### Other
+- [ESLint 9.0] has been released and changes the supported configuration file format.
+    The (deprecated) `Generic.Debug.ESLint` sniff only supports the "old" configuration file formats and when using the sniff to run ESLint, the `ESLINT_USE_FLAT_CONFIG=false` environment variable will need to be set when using ESLint >= 9.0.
+    For more information, see [#436].
+
+
+[ESLint 9.0]: https://eslint.org/blog/2024/04/eslint-v9.0.0-released/#flat-config-is-now-the-default-and-has-some-changes
+
+[#381]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/381
+[#385]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/385
+[#394]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/394
+[#420]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/420
+[#421]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/421
+[#423]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/423
+[#424]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/424
+[#427]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/427
+[#430]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/430
+[#431]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/431
+[#436]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/436
+[#453]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/453
+[#458]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/458
+
+## [3.9.1] - 2024-03-31
+
+### Added
+- Documentation for the following sniffs:
+    - Generic.PHP.RequireStrictTypes
+    - Squiz.WhiteSpace.MemberVarSpacing
+    - Squiz.WhiteSpace.ScopeClosingBrace
+    - Squiz.WhiteSpace.SuperfluousWhitespace
+    - Thanks to [Jay McPartland][@jaymcp] and [Rodrigo Primo][@rodrigoprimo] for the patches.
+
+### Changed
+- The following sniffs have received performance related improvements:
+    - Generic.CodeAnalysis.UselessOverridingMethod
+    - Generic.Files.ByteOrderMark
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patches.
+- Performance improvement for the "Diff" report. Should be most notable for Windows users. [#355]
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- The test suite has received some performance improvements. Should be most notable contributors using Windows. [#351]
+    - External standards with sniff tests using the PHP_CodeSniffer native test framework will also benefit from these changes.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch.
+- Various housekeeping, including improvements to the tests and documentation.
+    - Thanks to [Jay McPartland][@jaymcp], [João Pedro Oliveira][@jpoliveira08], [Rodrigo Primo][@rodrigoprimo] and [Juliette Reinders Folmer][@jrfnl] for their contributions.
+
+### Fixed
+- Fixed bug [#289] : Squiz.WhiteSpace.OperatorSpacing and PSR12.Operators.OperatorSpacing : improved fixer conflict protection by more strenuously avoiding handling operators in declare statements.
+    - Thanks to [Dan Wallis][@fredden] for the patch.
+- Fixed bug [#366] : Generic.CodeAnalysis.UselessOverridingMethod : prevent false negative when the declared method name and the called method name do not use the same case.
+    - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch.
+- Fixed bug [#368] : Squiz.Arrays.ArrayDeclaration fixer did not handle static closures correctly when moving array items to their own line.
+    - Thanks to [Michał Bundyra][@michalbundyra] for the patch.
+- Fixed bug [#404] : Test framework : fixed PHP 8.4 deprecation notice.
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+
+[#289]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/289
+[#351]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/351
+[#355]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/355
+[#366]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/366
+[#368]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/368
+[#404]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/404
+
 ## [3.9.0] - 2024-02-16
 
 ### Added
@@ -54,7 +917,7 @@ _Nothing yet._
     - Thanks to [Dan Wallis][@fredden], [Joachim Noreiko][@joachim-n], [Remi Collet][@remicollet], [Rodrigo Primo][@rodrigoprimo] and [Juliette Reinders Folmer][@jrfnl] for their contributions
 
 ### Deprecated
-- Support for scanning JavaScript and CSS files. See [#2448].
+- Support for scanning JavaScript and CSS files. See [#2448][sq-2448].
     - This also means that all sniffs which are only aimed at JavaScript or CSS files are now deprecated.
     - The Javascript and CSS Tokenizers, all Javascript and CSS specific sniffs, and support for JS and CSS in select sniffs which support multiple file types, will be removed in version 4.0.0.
 - The abstract `PHP_CodeSniffer\Filters\ExactMatch::getBlacklist()` and `PHP_CodeSniffer\Filters\ExactMatch::getWhitelist()` methods are deprecated and will be removed in the 4.0 release. See [#198].
@@ -62,7 +925,7 @@ _Nothing yet._
     - To make Filters extending `ExactMatch` cross-version compatible with both PHP_CodeSniffer 3.9.0+ as well as 4.0+, implement the new `getDisallowedFiles()` and `getAllowedFiles()` methods.
         - When both the `getDisallowedFiles()` and `getAllowedFiles()` methods as well as the `getBlacklist()` and `getWhitelist()` are available, the new methods will take precedence over the old methods.
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- The MySource standard and all sniffs in it. See [#2471].
+- The MySource standard and all sniffs in it. See [#2471][sq-2471].
     - The MySource standard and all sniffs in it will be removed in version 4.0.0.
 - The `Zend.Debug.CodeAnalyzer` sniff. See [#277].
     - This sniff will be removed in version 4.0.0.
@@ -97,8 +960,8 @@ _Nothing yet._
     - For anyone who missed the discussion about this and is interested to be on this list, please feel invited to submit a PR to add yourself.
         The list is located in the `.github` folder.
 
-[#2448]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2448
-[#2471]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2471
+[sq-2448]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2448
+[sq-2471]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2471
 [#27]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/27
 [#127]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/127
 [#196]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/196
@@ -106,7 +969,7 @@ _Nothing yet._
 [#198]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/198
 [#227]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/227
 [#235]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/235
-[#277]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/277
+[#277]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/277
 [#281]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/281
 [#288]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/288
 [#296]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/296
@@ -162,8 +1025,8 @@ _Nothing yet._
     - Thanks to [Rodrigo Primo][@rodrigoprimo] for the patch
 
 [#124]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/124
-[#150]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/150
-[#154]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/154
+[#150]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/150
+[#154]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/154
 [#178]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/178
 [#205]: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/205
 [#211]: https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/211
@@ -182,8 +1045,8 @@ _Nothing yet._
         - **_In contrast to earlier information, the `squizlabs/php_codesniffer` package now points to the new repository and everything will continue to work as before._**
     - PHIVE users may need to clear the PHIVE URL cache.
         - PHIVE users who don't use the package alias, but refer to the package URL, will need to update the URL from `https://squizlabs.github.io/PHP_CodeSniffer/phars/` to `https://phars.phpcodesniffer.com/phars/`.
-    - Users who download the PHAR files using curl or wget, will need to update the download URL from `https://squizlabs.github.io/PHP_CodeSniffer/[phpcs|phpcbf].phar` or `https://github.com/squizlabs/PHP_CodeSnifffer/releases/latest/download/[phpcs|phpcbf].phar` to `https://phars.phpcodesniffer.com/[phpcs|phpcbf].phar`.
-    - For users who install PHP_CodeSniffer via the [setup-php](https://github.com/shivammathur/setup-php/) action runner for GitHub Actions, nothing changes.
+    - Users who download the PHAR files using curl or wget, will need to update the download URL from `https://squizlabs.github.io/PHP_CodeSniffer/[phpcs|phpcbf].phar` or `https://github.com/squizlabs/PHP_CodeSniffer/releases/latest/download/[phpcs|phpcbf].phar` to `https://phars.phpcodesniffer.com/[phpcs|phpcbf].phar`.
+    - For users who install PHP_CodeSniffer via the [Setup-PHP](https://github.com/shivammathur/setup-php/) action runner for GitHub Actions, nothing changes.
     - Users using a git clone will need to update the clone address from `git@github.com:squizlabs/PHP_CodeSniffer.git` to `git@github.com:PHPCSStandards/PHP_CodeSniffer.git`.
         - Contributors will need to fork the new repo and add both the new fork as well as the new repo as remotes to their local git copy of PHP_CodeSniffer.
         - Users who have (valid) open issues or pull requests in the `squizlabs/PHP_CodeSniffer` repository are invited to resubmit these to the `PHPCSStandards/PHP_CodeSniffer` repository.
@@ -231,7 +1094,7 @@ _Nothing yet._
     - Thanks to [Atsushi Okui][@blue32a] for the patch
 - Support for PHPUnit 8 and 9 to the test suite
     - Test suites for external standards which run via the PHPCS native test suite can now run on PHPUnit 4-9 (was 4-7)
-    - If any of these tests use the PHPUnit `setUp()`/`tearDown()` methods or overload the `setUp()` in the `AbstractSniffUnitTest` test case, they will need to be adjusted. See the [PR details for further information](https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/59/commits/26384ebfcc0b1c1651b0e1e40c9b6c8c22881832)
+    - If any of these tests use the PHPUnit `setUp()`/`tearDown()` methods or overload the `setUp()` in the `AbstractSniffUnitTest` test case, they will need to be adjusted. See the [PR details for further information](https://github.com/PHPCSStandards/PHP_CodeSniffer/pull/59/commits/bc302dd977877a22c5e60d42a2f6b7d9e9192dab)
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 
 ### Changed
@@ -244,7 +1107,7 @@ _Nothing yet._
     - Invalid sniff properties set for sniffs via inline annotations will result in an informative `Internal.PropertyDoesNotExist` errror on line 1 of the scanned file, but will not halt the execution of PHPCS
     - For sniff developers, it is strongly recommended for sniffs to explicitly declare any user-adjustable public properties
         - If dynamic properties need to be supported for a sniff, either declare the magic __set()/__get()/__isset()/__unset() methods on the sniff or let the sniff extend stdClass
-        - Note: The #[\AllowDynamicProperties] attribute will have no effect for properties which are being set in rulesets
+        - Note: The `#[\AllowDynamicProperties]` attribute will have no effect for properties which are being set in rulesets
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 - The third parameter for the Ruleset::setSniffProperty() method has been changed to expect an array
     - Sniff developers/integrators of PHPCS may need to make some small adjustments to allow for this change
@@ -303,128 +1166,129 @@ _Nothing yet._
     - Use composer or the PHAR files instead
 
 ### Fixed
-- Fixed bug [#2857] : Squiz/NonExecutableCode: prevent false positives when exit is used in a ternary expression or as default with null coalesce
+- Fixed bug [#2857][sq-2857] : Squiz/NonExecutableCode: prevent false positives when exit is used in a ternary expression or as default with null coalesce
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3386] : PSR1/SideEffects : improved recognition of disable/enable annotations
+- Fixed bug [#3386][sq-3386] : PSR1/SideEffects : improved recognition of disable/enable annotations
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3557] : Squiz.Arrays.ArrayDeclaration will now ignore PHP 7.4 array unpacking when determining whether an array is associative
+- Fixed bug [#3557][sq-3557] : Squiz.Arrays.ArrayDeclaration will now ignore PHP 7.4 array unpacking when determining whether an array is associative
     - Thanks to [Volker Dusch][@edorian] for the patch
-- Fixed bug [#3592] : Squiz/NonExecutableCode: prevent false positives when a PHP 8.0+ inline throw expression is encountered
+- Fixed bug [#3592][sq-3592] : Squiz/NonExecutableCode: prevent false positives when a PHP 8.0+ inline throw expression is encountered
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3715] : Generic/UnusedFunctionParameter: fixed incorrect errorcode for closures/arrow functions nested within extended classes/classes which implement
+- Fixed bug [#3715][sq-3715] : Generic/UnusedFunctionParameter: fixed incorrect errorcode for closures/arrow functions nested within extended classes/classes which implement
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3717] : Squiz.Commenting.FunctionComment: fixed false positive for `InvalidNoReturn` when type is never
+- Fixed bug [#3717][sq-3717] : Squiz.Commenting.FunctionComment: fixed false positive for `InvalidNoReturn` when type is never
     - Thanks to [Choraimy Kroonstuiver][@axlon] for the patch
-- Fixed bug [#3720] : Generic/RequireStrictTypes : will now bow out silently in case of parse errors/live coding instead of throwing false positives/false negatives
+- Fixed bug [#3720][sq-3720] : Generic/RequireStrictTypes : will now bow out silently in case of parse errors/live coding instead of throwing false positives/false negatives
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3720] : Generic/RequireStrictTypes : did not handle multi-directive declare statements
+- Fixed bug [#3720][sq-3720] : Generic/RequireStrictTypes : did not handle multi-directive declare statements
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3722] : Potential "Uninitialized string offset 1" in octal notation backfill
+- Fixed bug [#3722][sq-3722] : Potential "Uninitialized string offset 1" in octal notation backfill
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3736] : PEAR/FunctionDeclaration: prevent fixer removing the close brace (and creating a parse error) when there is no space between the open brace and close brace of a function
+- Fixed bug [#3736][sq-3736] : PEAR/FunctionDeclaration: prevent fixer removing the close brace (and creating a parse error) when there is no space between the open brace and close brace of a function
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3739] : PEAR/FunctionDeclaration: prevent fixer conflict, and potentially creating a parse error, for unconventionally formatted return types
+- Fixed bug [#3739][sq-3739] : PEAR/FunctionDeclaration: prevent fixer conflict, and potentially creating a parse error, for unconventionally formatted return types
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3770] : Squiz/NonExecutableCode: prevent false positives for switching between PHP and HTML
+- Fixed bug [#3770][sq-3770] : Squiz/NonExecutableCode: prevent false positives for switching between PHP and HTML
     - Thanks to [Dan Wallis][@fredden] for the patch
-- Fixed bug [#3773] : Tokenizer/PHP: tokenization of the readonly keyword when used in combination with PHP 8.2 disjunctive normal types
+- Fixed bug [#3773][sq-3773] : Tokenizer/PHP: tokenization of the readonly keyword when used in combination with PHP 8.2 disjunctive normal types
     - Thanks to [Dan Wallis][@fredden] and [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3776] : Generic/JSHint: error when JSHint is not available
+- Fixed bug [#3776][sq-3776] : Generic/JSHint: error when JSHint is not available
     - Thanks to [Dan Wallis][@fredden] for the patch
-- Fixed bug [#3777] : Squiz/NonExecutableCode: slew of bug fixes, mostly related to modern PHP
+- Fixed bug [#3777][sq-3777] : Squiz/NonExecutableCode: slew of bug fixes, mostly related to modern PHP
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3778] : Squiz/LowercasePHPFunctions: bug fix for class names in attributes
+- Fixed bug [#3778][sq-3778] : Squiz/LowercasePHPFunctions: bug fix for class names in attributes
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3779] : Generic/ForbiddenFunctions: bug fix for class names in attributes
+- Fixed bug [#3779][sq-3779] : Generic/ForbiddenFunctions: bug fix for class names in attributes
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3785] : Squiz.Commenting.FunctionComment: potential "Uninitialized string offset 0" when a type contains a duplicate pipe symbol
+- Fixed bug [#3785][sq-3785] : Squiz.Commenting.FunctionComment: potential "Uninitialized string offset 0" when a type contains a duplicate pipe symbol
     - Thanks to [Dan Wallis][@fredden] for the patch
-- Fixed bug [#3787] : PEAR/Squiz/[MultiLine]FunctionDeclaration: allow for PHP 8.1 new in initializers
+- Fixed bug [#3787][sq-3787] : `PEAR/Squiz/[MultiLine]FunctionDeclaration`: allow for PHP 8.1 new in initializers
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3789] : Incorrect tokenization for ternary operator with `match` inside of it
+- Fixed bug [#3789][sq-3789] : Incorrect tokenization for ternary operator with `match` inside of it
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3790] : PSR12/AnonClassDeclaration: prevent fixer creating parse error when there was no space before the open brace
+- Fixed bug [#3790][sq-3790] : PSR12/AnonClassDeclaration: prevent fixer creating parse error when there was no space before the open brace
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3797] : Tokenizer/PHP: more context sensitive keyword fixes
+- Fixed bug [#3797][sq-3797] : Tokenizer/PHP: more context sensitive keyword fixes
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3801] : File::getMethodParameters(): allow for readonly promoted properties without visibility
+- Fixed bug [#3801][sq-3801] : File::getMethodParameters(): allow for readonly promoted properties without visibility
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3805] : Generic/FunctionCallArgumentSpacing: prevent fixer conflict over PHP 7.3+ trailing comma's in function calls
+- Fixed bug [#3805][sq-3805] : Generic/FunctionCallArgumentSpacing: prevent fixer conflict over PHP 7.3+ trailing comma's in function calls
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3806] : Squiz.PHP.InnerFunctions sniff now correctly reports inner functions declared within a closure
+- Fixed bug [#3806][sq-3806] : Squiz.PHP.InnerFunctions sniff now correctly reports inner functions declared within a closure
     - Thanks to [@Daimona] for the patch
-- Fixed bug [#3809] : GitBlame report was broken when passing a basepath
+- Fixed bug [#3809][sq-3809] : GitBlame report was broken when passing a basepath
     - Thanks to [Chris][@datengraben] for the patch
-- Fixed bug [#3813] : Squiz.Commenting.FunctionComment: false positive for parameter name mismatch on parameters annotated as passed by reference
+- Fixed bug [#3813][sq-3813] : Squiz.Commenting.FunctionComment: false positive for parameter name mismatch on parameters annotated as passed by reference
     - Thanks to [Dan Wallis][@fredden] for the patch
-- Fixed bug [#3833] : Generic.PHP.LowerCaseType: fixed potential undefined array index notice
+- Fixed bug [#3833][sq-3833] : Generic.PHP.LowerCaseType: fixed potential undefined array index notice
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3846] : PSR2.Classes.ClassDeclaration.CloseBraceAfterBody : fixer will no longer remove indentation on the close brace line
+- Fixed bug [#3846][sq-3846] : PSR2.Classes.ClassDeclaration.CloseBraceAfterBody : fixer will no longer remove indentation on the close brace line
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3854] : Fatal error when using Gitblame report in combination with `--basepath` and running from project subdirectory
+- Fixed bug [#3854][sq-3854] : Fatal error when using Gitblame report in combination with `--basepath` and running from project subdirectory
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3856] : PSR12.Traits.UseDeclaration was using the wrong error code - SpacingAfterAs - for spacing issues after the `use` keyword
+- Fixed bug [#3856][sq-3856] : PSR12.Traits.UseDeclaration was using the wrong error code - SpacingAfterAs - for spacing issues after the `use` keyword
     - These will now be reported using the SpacingAfterUse error code
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3856] : PSR12.Traits.UseDeclaration did not check spacing after `use` keyword for multi-line trait use statements
+- Fixed bug [#3856][sq-3856] : PSR12.Traits.UseDeclaration did not check spacing after `use` keyword for multi-line trait use statements
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3867] : Tokenizer/PHP: union type and intersection type operators were not correctly tokenized for static properties without explicit visibility
+- Fixed bug [#3867][sq-3867] : Tokenizer/PHP: union type and intersection type operators were not correctly tokenized for static properties without explicit visibility
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3877] : Filter names can be case-sensitive. The -h help text will now display the correct case for the available filters
+- Fixed bug [#3877][sq-3877] : Filter names can be case-sensitive. The -h help text will now display the correct case for the available filters
     - Thanks to [@simonsan] for the patch
-- Fixed bug [#3893] : Generic/DocComment : the SpacingAfterTagGroup fixer could accidentally remove ignore annotations
+- Fixed bug [#3893][sq-3893] : Generic/DocComment : the SpacingAfterTagGroup fixer could accidentally remove ignore annotations
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3898] : Squiz/NonExecutableCode : the sniff could get confused over comments in unexpected places
+- Fixed bug [#3898][sq-3898] : Squiz/NonExecutableCode : the sniff could get confused over comments in unexpected places
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3904] : Squiz/FunctionSpacing : prevent potential fixer conflict
+- Fixed bug [#3904][sq-3904] : Squiz/FunctionSpacing : prevent potential fixer conflict
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3906] : Tokenizer/CSS: bug fix related to the unsupported slash comment syntax
+- Fixed bug [#3906][sq-3906] : Tokenizer/CSS: bug fix related to the unsupported slash comment syntax
     - Thanks to [Dan Wallis][@fredden] for the patch
-- Fixed bug [#3913] : Config did not always correctly store unknown "long" arguments in the `$unknown` property
+- Fixed bug [#3913][sq-3913] : Config did not always correctly store unknown "long" arguments in the `$unknown` property
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 
 Thanks go to [Dan Wallis][@fredden] and [Danny van der Sluijs][@DannyvdSluijs] for reviewing quite a few of the PRs for this release.
 Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo change over.
 
-[#2857]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2857
-[#3386]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3386
-[#3557]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3557
-[#3592]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3592
-[#3715]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3715
-[#3717]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3717
-[#3720]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3720
-[#3722]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3722
-[#3736]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3736
-[#3739]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3739
-[#3770]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3770
-[#3773]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3773
-[#3776]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3776
-[#3777]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3777
-[#3778]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3778
-[#3779]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3779
-[#3785]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3785
-[#3787]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3787
-[#3789]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3789
-[#3790]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3790
-[#3797]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3797
-[#3801]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3801
-[#3805]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3805
-[#3806]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3806
-[#3809]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3809
-[#3813]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3813
-[#3833]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3833
-[#3846]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3846
-[#3854]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3854
-[#3856]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3856
-[#3867]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3867
-[#3877]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3877
-[#3893]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3893
-[#3898]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3898
-[#3904]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3904
-[#3906]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3906
-[#3913]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3913
+[sq-2857]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2857
+[sq-3386]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3386
+[sq-3557]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3557
+[sq-3592]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3592
+[sq-3715]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3715
+[sq-3717]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3717
+[sq-3720]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3720
+[sq-3722]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3722
+[sq-3736]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3736
+[sq-3739]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3739
+[sq-3770]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3770
+[sq-3773]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3773
+[sq-3776]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3776
+[sq-3777]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3777
+[sq-3778]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3778
+[sq-3779]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3779
+[sq-3785]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3785
+[sq-3787]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3787
+[sq-3789]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3789
+[sq-3790]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3790
+[sq-3797]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3797
+[sq-3801]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3801
+[sq-3805]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3805
+[sq-3806]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3806
+[sq-3809]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3809
+[sq-3813]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3813
+[sq-3833]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3833
+[sq-3846]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3846
+[sq-3854]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3854
+[sq-3856]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3856
+[sq-3867]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3867
+[sq-3877]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3877
+[sq-3893]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3893
+[sq-3898]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3898
+[sq-3904]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3904
+[sq-3906]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3906
+[sq-3913]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3913
 
 ## [3.7.2] - 2023-02-23
+
 ### Changed
 - Newer versions of Composer will now suggest installing PHPCS using require-dev instead of require
     - Thanks to [Gary Jones][@GaryJones] for the patch
@@ -436,48 +1300,50 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Squiz.Formatting.OperatorBracket no longer reports false positives in match() structures
 
 ### Fixed
-- Fixed bug [#3616] : Squiz.PHP.DisallowComparisonAssignment false positive for PHP 8 match expression
+- Fixed bug [#3616][sq-3616] : Squiz.PHP.DisallowComparisonAssignment false positive for PHP 8 match expression
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3618] : Generic.WhiteSpace.ArbitraryParenthesesSpacing false positive for return new parent()
+- Fixed bug [#3618][sq-3618] : Generic.WhiteSpace.ArbitraryParenthesesSpacing false positive for return new parent()
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3632] : Short list not tokenized correctly in control structures without braces
+- Fixed bug [#3632][sq-3632] : Short list not tokenized correctly in control structures without braces
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3639] : Tokenizer not applying tab replacement to heredoc/nowdoc closers
+- Fixed bug [#3639][sq-3639] : Tokenizer not applying tab replacement to heredoc/nowdoc closers
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3640] : Generic.WhiteSpace.DisallowTabIndent not reporting errors for PHP 7.3 flexible heredoc/nowdoc syntax
+- Fixed bug [#3640][sq-3640] : Generic.WhiteSpace.DisallowTabIndent not reporting errors for PHP 7.3 flexible heredoc/nowdoc syntax
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3645] : PHPCS can show 0 exit code when running in parallel even if child process has fatal error
+- Fixed bug [#3645][sq-3645] : PHPCS can show 0 exit code when running in parallel even if child process has fatal error
     - Thanks to [Alex Panshin][@enl] for the patch
-- Fixed bug [#3653] : False positives for match() in OperatorSpacingSniff
+- Fixed bug [#3653][sq-3653] : False positives for match() in OperatorSpacingSniff
     - Thanks to [Jaroslav Hanslík][@kukulich] for the patch
-- Fixed bug [#3666] : PEAR.Functions.FunctionCallSignature incorrect indent fix when checking mixed HTML/PHP files
-- Fixed bug [#3668] : PSR12.Classes.ClassInstantiation.MissingParentheses false positive when instantiating parent classes
+- Fixed bug [#3666][sq-3666] : PEAR.Functions.FunctionCallSignature incorrect indent fix when checking mixed HTML/PHP files
+- Fixed bug [#3668][sq-3668] : PSR12.Classes.ClassInstantiation.MissingParentheses false positive when instantiating parent classes
     - Similar issues also fixed in Generic.Functions.FunctionCallArgumentSpacing and Squiz.Formatting.OperatorBracket
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3672] : Incorrect ScopeIndent.IncorrectExact report for match inside array literal
-- Fixed bug [#3694] : Generic.WhiteSpace.SpreadOperatorSpacingAfter does not ignore spread operator in PHP 8.1 first class   callables
+- Fixed bug [#3672][sq-3672] : Incorrect ScopeIndent.IncorrectExact report for match inside array literal
+- Fixed bug [#3694][sq-3694] : Generic.WhiteSpace.SpreadOperatorSpacingAfter does not ignore spread operator in PHP 8.1 first class   callables
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 
-[#3616]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3616
-[#3618]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3618
-[#3632]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3632
-[#3639]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3639
-[#3640]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3640
-[#3645]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3645
-[#3653]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3653
-[#3666]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3666
-[#3668]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3668
-[#3672]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3672
-[#3694]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3694 
+[sq-3616]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3616
+[sq-3618]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3618
+[sq-3632]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3632
+[sq-3639]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3639
+[sq-3640]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3640
+[sq-3645]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3645
+[sq-3653]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3653
+[sq-3666]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3666
+[sq-3668]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3668
+[sq-3672]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3672
+[sq-3694]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3694
 
 ## [3.7.1] - 2022-06-18
+
 ### Fixed
-- Fixed bug [#3609] : Methods/constants with name empty/isset/unset are always reported as error
+- Fixed bug [#3609][sq-3609] : Methods/constants with name empty/isset/unset are always reported as error
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 
-[#3609]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3609
+[sq-3609]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3609
 
 ## [3.7.0] - 2022-06-13
+
 ### Added
 - Added support for PHP 8.1 explicit octal notation
     - This new syntax has been backfilled for PHP versions less than 8.1
@@ -521,74 +1387,76 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Jaroslav Hanslík][@kukulich] for the patch
 
 ### Fixed
-- Fixed bug [#3502] : A match statement within an array produces Squiz.Arrays.ArrayDeclaration.NoKeySpecified
-- Fixed bug [#3503] : Squiz.Commenting.FunctionComment.ThrowsNoFullStop false positive when one line @throw
-- Fixed bug [#3505] : The nullsafe operator is not counted in Generic.Metrics.CyclomaticComplexity
+- Fixed bug [#3502][sq-3502] : A match statement within an array produces Squiz.Arrays.ArrayDeclaration.NoKeySpecified
+- Fixed bug [#3503][sq-3503] : Squiz.Commenting.FunctionComment.ThrowsNoFullStop false positive when one line @throw
+- Fixed bug [#3505][sq-3505] : The nullsafe operator is not counted in Generic.Metrics.CyclomaticComplexity
     - Thanks to [Mark Baker][@MarkBaker] for the patch
-- Fixed bug [#3526] : PSR12.Properties.ConstantVisibility false positive when using public final const syntax
+- Fixed bug [#3526][sq-3526] : PSR12.Properties.ConstantVisibility false positive when using public final const syntax
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3530] : Line indented incorrectly false positive when using match-expression inside switch case
-- Fixed bug [#3534] : Name of typed enum tokenized as T_GOTO_LABEL
+- Fixed bug [#3530][sq-3530] : Line indented incorrectly false positive when using match-expression inside switch case
+- Fixed bug [#3534][sq-3534] : Name of typed enum tokenized as T_GOTO_LABEL
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3546] : Tokenizer/PHP: bug fix - parent/static keywords in class instantiations
+- Fixed bug [#3546][sq-3546] : Tokenizer/PHP: bug fix - parent/static keywords in class instantiations
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3550] : False positive from PSR2.ControlStructures.SwitchDeclaration.TerminatingComment when using trailing   comment
+- Fixed bug [#3550][sq-3550] : False positive from PSR2.ControlStructures.SwitchDeclaration.TerminatingComment when using trailing   comment
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3575]: Squiz.Scope.MethodScope misses visibility keyword on previous line
+- Fixed bug [#3575][sq-3575] :  Squiz.Scope.MethodScope misses visibility keyword on previous line
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3604]: Tokenizer/PHP: bug fix for double quoted strings using ${
+- Fixed bug [#3604][sq-3604] :  Tokenizer/PHP: bug fix for double quoted strings using ${
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 
-[#3502]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3502
-[#3503]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3503
-[#3505]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3505
-[#3526]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3526
-[#3530]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3530
-[#3534]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3534
-[#3546]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3546
-[#3550]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3550
-[#3575]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3575
-[#3604]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3604
+[sq-3502]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3502
+[sq-3503]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3503
+[sq-3505]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3505
+[sq-3526]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3526
+[sq-3530]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3530
+[sq-3534]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3534
+[sq-3546]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3546
+[sq-3550]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3550
+[sq-3575]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3575
+[sq-3604]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3604
 
 ## [3.6.2] - 2021-12-13
+
 ### Changed
 - Processing large code bases that use tab indenting inside comments and strings will now be faster
     - Thanks to [Thiemo Kreuz][@thiemowmde] for the patch
 
 ### Fixed
-- Fixed bug [#3388] : phpcs does not work when run from WSL drives
+- Fixed bug [#3388][sq-3388] : phpcs does not work when run from WSL drives
     - Thanks to [Juliette Reinders Folmer][@jrfnl] and [Graham Wharton][@gwharton] for the patch
-- Fixed bug [#3422] : Squiz.WhiteSpace.ScopeClosingBrace fixer removes HTML content when fixing closing brace alignment
+- Fixed bug [#3422][sq-3422] : Squiz.WhiteSpace.ScopeClosingBrace fixer removes HTML content when fixing closing brace alignment
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3437] : PSR12 does not forbid blank lines at the start of the class body
+- Fixed bug [#3437][sq-3437] : PSR12 does not forbid blank lines at the start of the class body
     - Added new PSR12.Classes.OpeningBraceSpace sniff to enforce this
-- Fixed bug [#3440] : Squiz.WhiteSpace.MemberVarSpacing false positives when attributes used without docblock
+- Fixed bug [#3440][sq-3440] : Squiz.WhiteSpace.MemberVarSpacing false positives when attributes used without docblock
     - Thanks to [Vadim Borodavko][@javer] for the patch
-- Fixed bug [#3448] : PHP 8.1 deprecation notice while generating running time value
+- Fixed bug [#3448][sq-3448] : PHP 8.1 deprecation notice while generating running time value
     - Thanks to [Juliette Reinders Folmer][@jrfnl] and [Andy Postnikov][@andypost] for the patch
-- Fixed bug [#3456] : PSR12.Classes.ClassInstantiation.MissingParentheses false positive using attributes on anonymous class
+- Fixed bug [#3456][sq-3456] : PSR12.Classes.ClassInstantiation.MissingParentheses false positive using attributes on anonymous class
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3460] : Generic.Formatting.MultipleStatementAlignment false positive on closure with parameters
+- Fixed bug [#3460][sq-3460] : Generic.Formatting.MultipleStatementAlignment false positive on closure with parameters
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3468] : do/while loops are double-counted in Generic.Metrics.CyclomaticComplexity
+- Fixed bug [#3468][sq-3468] : do/while loops are double-counted in Generic.Metrics.CyclomaticComplexity
     - Thanks to [Mark Baker][@MarkBaker] for the patch
-- Fixed bug [#3469] : Ternary Operator and Null Coalescing Operator are not counted in Generic.Metrics.CyclomaticComplexity
+- Fixed bug [#3469][sq-3469] : Ternary Operator and Null Coalescing Operator are not counted in Generic.Metrics.CyclomaticComplexity
     - Thanks to [Mark Baker][@MarkBaker] for the patch
-- Fixed bug [#3472] : PHP 8 match() expression is not counted in Generic.Metrics.CyclomaticComplexity
+- Fixed bug [#3472][sq-3472] : PHP 8 match() expression is not counted in Generic.Metrics.CyclomaticComplexity
     - Thanks to [Mark Baker][@MarkBaker] for the patch
 
-[#3388]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3388
-[#3422]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3422
-[#3437]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3437
-[#3440]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3440
-[#3448]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3448
-[#3456]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3456
-[#3460]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3460
-[#3468]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3468
-[#3469]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3469
-[#3472]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3472
+[sq-3388]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3388
+[sq-3422]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3422
+[sq-3437]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3437
+[sq-3440]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3440
+[sq-3448]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3448
+[sq-3456]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3456
+[sq-3460]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3460
+[sq-3468]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3468
+[sq-3469]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3469
+[sq-3472]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3472
 
 ## [3.6.1] - 2021-10-11
+
 ### Changed
 - PHPCS annotations can now be specified using hash-style comments
     - Previously, only slash-style and block-style comments could be used to do things like disable errors
@@ -626,69 +1494,70 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Squiz.Commenting.VariableComment
     - Squiz.WhiteSpace.MemberVarSpacing
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3294] : Bug in attribute tokenization when content contains PHP end token or attribute closer on new line
+- Fixed bug [#3294][sq-3294] : Bug in attribute tokenization when content contains PHP end token or attribute closer on new line
     - Thanks to [Alessandro Chitolina][@alekitto] for the patch
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the tests
-- Fixed bug [#3296] : PSR2.ControlStructures.SwitchDeclaration takes phpcs:ignore as content of case body
-- Fixed bug [#3297] : PSR2.ControlStructures.SwitchDeclaration.TerminatingComment does not handle try/finally blocks
+- Fixed bug [#3296][sq-3296] : PSR2.ControlStructures.SwitchDeclaration takes phpcs:ignore as content of case body
+- Fixed bug [#3297][sq-3297] : PSR2.ControlStructures.SwitchDeclaration.TerminatingComment does not handle try/finally blocks
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3302] : PHP 8.0 | Tokenizer/PHP: bugfix for union types using namespace operator
+- Fixed bug [#3302][sq-3302] : PHP 8.0 | Tokenizer/PHP: bugfix for union types using namespace operator
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3303] : findStartOfStatement() doesn't work with T_OPEN_TAG_WITH_ECHO
-- Fixed bug [#3316] : Arrow function not tokenized correctly when using null in union type
-- Fixed bug [#3317] : Problem with how phpcs handles ignored files when running in parallel
+- Fixed bug [#3303][sq-3303] : findStartOfStatement() doesn't work with T_OPEN_TAG_WITH_ECHO
+- Fixed bug [#3316][sq-3316] : Arrow function not tokenized correctly when using null in union type
+- Fixed bug [#3317][sq-3317] : Problem with how phpcs handles ignored files when running in parallel
     - Thanks to [Emil Andersson][@emil-nasso] for the patch
-- Fixed bug [#3324] : PHPCS hangs processing some nested arrow functions inside a function call
-- Fixed bug [#3326] : Generic.Formatting.MultipleStatementAlignment error with const DEFAULT
+- Fixed bug [#3324][sq-3324] : PHPCS hangs processing some nested arrow functions inside a function call
+- Fixed bug [#3326][sq-3326] : Generic.Formatting.MultipleStatementAlignment error with const DEFAULT
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3333] : Squiz.Objects.ObjectInstantiation: null coalesce operators are not recognized as assignment
+- Fixed bug [#3333][sq-3333] : Squiz.Objects.ObjectInstantiation: null coalesce operators are not recognized as assignment
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3340] : Ensure interface and trait names are always tokenized as T_STRING
+- Fixed bug [#3340][sq-3340] : Ensure interface and trait names are always tokenized as T_STRING
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3342] : PSR12/Squiz/PEAR standards all error on promoted properties with docblocks
+- Fixed bug [#3342][sq-3342] : PSR12/Squiz/PEAR standards all error on promoted properties with docblocks
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3345] : IF statement with no braces and double catch turned into syntax error by auto-fixer
+- Fixed bug [#3345][sq-3345] : IF statement with no braces and double catch turned into syntax error by auto-fixer
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3352] : PSR2.ControlStructures.SwitchDeclaration can remove comments on the same line as the case statement while fixing
+- Fixed bug [#3352][sq-3352] : PSR2.ControlStructures.SwitchDeclaration can remove comments on the same line as the case statement while fixing
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3357] : Generic.Functions.OpeningFunctionBraceBsdAllman removes return type when additional lines are present
+- Fixed bug [#3357][sq-3357] : Generic.Functions.OpeningFunctionBraceBsdAllman removes return type when additional lines are present
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3362] : Generic.WhiteSpace.ScopeIndent false positive for arrow functions inside arrays
-- Fixed bug [#3384] : Squiz.Commenting.FileComment.SpacingAfterComment false positive on empty file
-- Fixed bug [#3394] : Fix PHP 8.1 auto_detect_line_endings deprecation notice
-- Fixed bug [#3400] : PHP 8.1: prevent deprecation notices about missing return types
+- Fixed bug [#3362][sq-3362] : Generic.WhiteSpace.ScopeIndent false positive for arrow functions inside arrays
+- Fixed bug [#3384][sq-3384] : Squiz.Commenting.FileComment.SpacingAfterComment false positive on empty file
+- Fixed bug [#3394][sq-3394] : Fix PHP 8.1 auto_detect_line_endings deprecation notice
+- Fixed bug [#3400][sq-3400] : PHP 8.1: prevent deprecation notices about missing return types
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3424] : PHPCS fails when using PHP 8 Constructor property promotion with attributes
+- Fixed bug [#3424][sq-3424] : PHPCS fails when using PHP 8 Constructor property promotion with attributes
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3425] : PHP 8.1 | Runner::processChildProcs(): fix passing null to non-nullable bug
+- Fixed bug [#3425][sq-3425] : PHP 8.1 | Runner::processChildProcs(): fix passing null to non-nullable bug
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3445] : Nullable parameter after attribute incorrectly tokenized as ternary operator
+- Fixed bug [#3445][sq-3445] : Nullable parameter after attribute incorrectly tokenized as ternary operator
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 
-[#3294]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3294
-[#3296]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3296
-[#3297]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3297
-[#3302]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3302
-[#3303]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3303
-[#3316]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3316
-[#3317]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3317
-[#3324]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3324
-[#3326]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3326
-[#3333]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3333
-[#3340]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3340
-[#3342]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3342
-[#3345]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3345
-[#3352]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3352
-[#3357]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3357
-[#3362]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3362
-[#3384]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3384
-[#3394]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3394
-[#3400]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3400
-[#3424]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3424
-[#3425]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3425
-[#3445]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3445
+[sq-3294]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3294
+[sq-3296]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3296
+[sq-3297]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3297
+[sq-3302]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3302
+[sq-3303]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3303
+[sq-3316]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3316
+[sq-3317]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3317
+[sq-3324]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3324
+[sq-3326]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3326
+[sq-3333]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3333
+[sq-3340]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3340
+[sq-3342]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3342
+[sq-3345]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3345
+[sq-3352]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3352
+[sq-3357]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3357
+[sq-3362]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3362
+[sq-3384]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3384
+[sq-3394]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3394
+[sq-3400]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3400
+[sq-3424]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3424
+[sq-3425]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3425
+[sq-3445]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3445
 
 ## [3.6.0] - 2021-04-09
+
 ### Added
 - Added support for PHP 8.0 union types
     - A new T_TYPE_UNION token is available to represent the pipe character
@@ -784,7 +1653,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - The default remains at "private", so all methods are checked
     - Thanks to [Vincent Langlet][@VincentLanglet] for the patch
 - PEAR.Commenting.FunctionComment and Squiz.Commenting.FunctionComment sniffs can now ignore return tags in any method
-    - Previously, only __construct and __destruct were ignored
+    - Previously, only `__construct()` and `__destruct()` were ignored
     - Set the list of method names to ignore in the "specialMethods" sniff property
     - The default remains at "__construct" and "__destruct" only
     - Thanks to [Vincent Langlet][@VincentLanglet] for the patch
@@ -814,61 +1683,63 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Sniff no longer errors for assignments on first line of closure
     - Sniff no longer errors for assignments after a goto label
     - Thanks to [Jaroslav Hanslík][@kukulich] for the patch
-- Fixed bug [#2913] : Generic.WhiteSpace.ScopeIndent false positive when opening and closing tag on same line inside conditional
-- Fixed bug [#2992] : Enabling caching using a ruleset produces invalid cache files when using --sniffs and --exclude CLI args
-- Fixed bug [#3003] : Squiz.Formatting.OperatorBracket autofix incorrect when assignment used with null coalescing operator
-- Fixed bug [#3145] : Autoloading of sniff fails when multiple classes declared in same file
-- Fixed bug [#3157] : PSR2.ControlStructures.SwitchDeclaration.BreakIndent false positive when case keyword is not indented
-- Fixed bug [#3163] : Undefined index error with pre-commit hook using husky on PHP 7.4
+- Fixed bug [#2913][sq-2913] : Generic.WhiteSpace.ScopeIndent false positive when opening and closing tag on same line inside conditional
+- Fixed bug [#2992][sq-2992] : Enabling caching using a ruleset produces invalid cache files when using --sniffs and --exclude CLI args
+- Fixed bug [#3003][sq-3003] : Squiz.Formatting.OperatorBracket autofix incorrect when assignment used with null coalescing operator
+- Fixed bug [#3145][sq-3145] : Autoloading of sniff fails when multiple classes declared in same file
+- Fixed bug [#3157][sq-3157] : PSR2.ControlStructures.SwitchDeclaration.BreakIndent false positive when case keyword is not indented
+- Fixed bug [#3163][sq-3163] : Undefined index error with pre-commit hook using husky on PHP 7.4
     - Thanks to [Ismo Vuorinen][@ivuorinen] for the patch
-- Fixed bug [#3165] : Squiz.PHP.DisallowComparisonAssignment false positive when comparison inside closure
-- Fixed bug [#3167] : Generic.WhiteSpace.ScopeIndent false positive when using PHP 8.0 constructor property promotion
-- Fixed bug [#3170] : Squiz.WhiteSpace.OperatorSpacing false positive when using negation with string concat
+- Fixed bug [#3165][sq-3165] : Squiz.PHP.DisallowComparisonAssignment false positive when comparison inside closure
+- Fixed bug [#3167][sq-3167] : Generic.WhiteSpace.ScopeIndent false positive when using PHP 8.0 constructor property promotion
+- Fixed bug [#3170][sq-3170] : Squiz.WhiteSpace.OperatorSpacing false positive when using negation with string concat
     - This also fixes the same issue in the PSR12.Operators.OperatorSpacing sniff
-- Fixed bug [#3177] : Incorrect tokenization of GOTO statements in mixed PHP/HTML files
+- Fixed bug [#3177][sq-3177] : Incorrect tokenization of GOTO statements in mixed PHP/HTML files
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3184] : PSR2.Namespace.NamespaceDeclaration false positive on namespace operator
+- Fixed bug [#3184][sq-3184] : PSR2.Namespace.NamespaceDeclaration false positive on namespace operator
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3188] : Squiz.WhiteSpace.ScopeKeywordSpacing false positive for static return type
+- Fixed bug [#3188][sq-3188] : Squiz.WhiteSpace.ScopeKeywordSpacing false positive for static return type
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3192] : findStartOfStatement doesn't work correctly inside switch
+- Fixed bug [#3192][sq-3192] : findStartOfStatement doesn't work correctly inside switch
     - Thanks to [Vincent Langlet][@VincentLanglet] for the patch
-- Fixed bug [#3195] : Generic.WhiteSpace.ScopeIndent confusing message when combination of tabs and spaces found
-- Fixed bug [#3197] : Squiz.NamingConventions.ValidVariableName does not use correct error code for all member vars
-- Fixed bug [#3219] : Generic.Formatting.MultipleStatementAlignment false positive for empty anonymous classes and closures
-- Fixed bug [#3258] : Squiz.Formatting.OperatorBracket duplicate error messages for unary minus
-    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3273] : Squiz.Functions.FunctionDeclarationArgumentSpacing reports line break as 0 spaces between parenthesis
-- Fixed bug [#3277] : Nullable static return typehint causes whitespace error
-- Fixed bug [#3284] : Unused parameter false positive when using array index in arrow function
-
-[#2913]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2913
-[#2992]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2992
-[#3003]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3003
-[#3145]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3145
-[#3157]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3157
-[#3163]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3163
-[#3165]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3165
-[#3167]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3167
-[#3170]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3170
-[#3177]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3177
-[#3184]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3184
-[#3188]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3188
-[#3192]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3192
-[#3195]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3195
-[#3197]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3197
-[#3219]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3219
-[#3258]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3258
-[#3273]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3273
-[#3277]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3277
-[#3284]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3284
+- Fixed bug [#3195][sq-3195] : Generic.WhiteSpace.ScopeIndent confusing message when combination of tabs and spaces found
+- Fixed bug [#3197][sq-3197] : Squiz.NamingConventions.ValidVariableName does not use correct error code for all member vars
+- Fixed bug [#3219][sq-3219] : Generic.Formatting.MultipleStatementAlignment false positive for empty anonymous classes and closures
+- Fixed bug [#3258][sq-3258] : Squiz.Formatting.OperatorBracket duplicate error messages for unary minus
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#3273][sq-3273] : Squiz.Functions.FunctionDeclarationArgumentSpacing reports line break as 0 spaces between parenthesis
+- Fixed bug [#3277][sq-3277] : Nullable static return typehint causes whitespace error
+- Fixed bug [#3284][sq-3284] : Unused parameter false positive when using array index in arrow function
+
+[sq-2913]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2913
+[sq-2992]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2992
+[sq-3003]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3003
+[sq-3145]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3145
+[sq-3157]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3157
+[sq-3163]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3163
+[sq-3165]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3165
+[sq-3167]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3167
+[sq-3170]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3170
+[sq-3177]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3177
+[sq-3184]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3184
+[sq-3188]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3188
+[sq-3192]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3192
+[sq-3195]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3195
+[sq-3197]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3197
+[sq-3219]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3219
+[sq-3258]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3258
+[sq-3273]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3273
+[sq-3277]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3277
+[sq-3284]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3284
 
 ## [3.5.8] - 2020-10-23
+
 ### Removed
 - Reverted a change to the way include/exclude patterns are processed for STDIN content
     - This change is not backwards compatible and will be re-introduced in version 3.6.0
 
 ## [3.5.7] - 2020-10-23
+
 ### Added
 - The PHP 8.0 T_NULLSAFE_OBJECT_OPERATOR token has been made available for older versions
     - Existing sniffs that check for T_OBJECT_OPERATOR have been modified to apply the same rules for the nullsafe object operator
@@ -894,59 +1765,60 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 ### Fixed
 - Fixed Squiz.Formatting.OperatorBracket false positive when exiting with a negative number
 - Fixed Squiz.PHP.DisallowComparisonAssignment false positive for methods called on an object
-- Fixed bug [#2882] : Generic.Arrays.ArrayIndent can request close brace indent to be less than the statement indent level
-- Fixed bug [#2883] : Generic.WhiteSpace.ScopeIndent.Incorrect issue after NOWDOC
-- Fixed bug [#2975] : Undefined offset in PSR12.Functions.ReturnTypeDeclaration when checking function return type inside ternary
-- Fixed bug [#2988] : Undefined offset in Squiz.Strings.ConcatenationSpacing during live coding
+- Fixed bug [#2882][sq-2882] : Generic.Arrays.ArrayIndent can request close brace indent to be less than the statement indent level
+- Fixed bug [#2883][sq-2883] : Generic.WhiteSpace.ScopeIndent.Incorrect issue after NOWDOC
+- Fixed bug [#2975][sq-2975] : Undefined offset in PSR12.Functions.ReturnTypeDeclaration when checking function return type inside ternary
+- Fixed bug [#2988][sq-2988] : Undefined offset in Squiz.Strings.ConcatenationSpacing during live coding
     - Thanks to [Thiemo Kreuz][@thiemowmde] for the patch
-- Fixed bug [#2989] : Incorrect auto-fixing in Generic.ControlStructures.InlineControlStructure during live coding
+- Fixed bug [#2989][sq-2989] : Incorrect auto-fixing in Generic.ControlStructures.InlineControlStructure during live coding
     - Thanks to [Thiemo Kreuz][@thiemowmde] for the patch
-- Fixed bug [#3007] : Directory exclude pattern improperly excludes directories with names that start the same
+- Fixed bug [#3007][sq-3007] : Directory exclude pattern improperly excludes directories with names that start the same
     - Thanks to [Steve Talbot][@SteveTalbot] for the patch
-- Fixed bug [#3043] : Squiz.WhiteSpace.OperatorSpacing false positive for negation in arrow function
+- Fixed bug [#3043][sq-3043] : Squiz.WhiteSpace.OperatorSpacing false positive for negation in arrow function
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3049] : Incorrect error with arrow function and parameter passed as reference
+- Fixed bug [#3049][sq-3049] : Incorrect error with arrow function and parameter passed as reference
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3053] : PSR2 incorrect fix when multiple use statements on same line do not have whitespace between them
-- Fixed bug [#3058] : Progress gets unaligned when 100% happens at the end of the available dots
-- Fixed bug [#3059] : Squiz.Arrays.ArrayDeclaration false positive when using type casting
+- Fixed bug [#3053][sq-3053] : PSR2 incorrect fix when multiple use statements on same line do not have whitespace between them
+- Fixed bug [#3058][sq-3058] : Progress gets unaligned when 100% happens at the end of the available dots
+- Fixed bug [#3059][sq-3059] : Squiz.Arrays.ArrayDeclaration false positive when using type casting
     - Thanks to [Sergei Morozov][@morozov] for the patch
-- Fixed bug [#3060] : Squiz.Arrays.ArrayDeclaration false positive for static functions
+- Fixed bug [#3060][sq-3060] : Squiz.Arrays.ArrayDeclaration false positive for static functions
     - Thanks to [Sergei Morozov][@morozov] for the patch
-- Fixed bug [#3065] : Should not fix Squiz.Arrays.ArrayDeclaration.SpaceBeforeComma if comment between element and comma
+- Fixed bug [#3065][sq-3065] : Should not fix Squiz.Arrays.ArrayDeclaration.SpaceBeforeComma if comment between element and comma
     - Thanks to [Sergei Morozov][@morozov] for the patch
-- Fixed bug [#3066] : No support for namespace operator used in type declarations
+- Fixed bug [#3066][sq-3066] : No support for namespace operator used in type declarations
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3075] : PSR12.ControlStructures.BooleanOperatorPlacement false positive when operator is the only content on line
-- Fixed bug [#3099] : Squiz.WhiteSpace.OperatorSpacing false positive when exiting with negative number
+- Fixed bug [#3075][sq-3075] : PSR12.ControlStructures.BooleanOperatorPlacement false positive when operator is the only content on line
+- Fixed bug [#3099][sq-3099] : Squiz.WhiteSpace.OperatorSpacing false positive when exiting with negative number
     - Thanks to [Sergei Morozov][@morozov] for the patch
-- Fixed bug [#3102] : PSR12.Squiz.OperatorSpacing false positive for default values of arrow functions
-    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#3124] : PSR-12 not reporting error for empty lines with only whitespace
-- Fixed bug [#3135] : Ignore annotations are broken on PHP 8.0
-    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-
-[#2882]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2882
-[#2883]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2883
-[#2975]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2975
-[#2988]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2988
-[#2989]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2989
-[#3007]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3007
-[#3043]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3043
-[#3049]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3049
-[#3053]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3053
-[#3058]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3058
-[#3059]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3059
-[#3060]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3060
-[#3065]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3065
-[#3066]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3066
-[#3075]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3075
-[#3099]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3099
-[#3102]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3102
-[#3124]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3124
-[#3135]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3135
+- Fixed bug [#3102][sq-3102] : PSR12.Squiz.OperatorSpacing false positive for default values of arrow functions
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#3124][sq-3124] : PSR-12 not reporting error for empty lines with only whitespace
+- Fixed bug [#3135][sq-3135] : Ignore annotations are broken on PHP 8.0
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+
+[sq-2882]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2882
+[sq-2883]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2883
+[sq-2975]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2975
+[sq-2988]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2988
+[sq-2989]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2989
+[sq-3007]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3007
+[sq-3043]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3043
+[sq-3049]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3049
+[sq-3053]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3053
+[sq-3058]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3058
+[sq-3059]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3059
+[sq-3060]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3060
+[sq-3065]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3065
+[sq-3066]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3066
+[sq-3075]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3075
+[sq-3099]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3099
+[sq-3102]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3102
+[sq-3124]: https://github.com/squizlabs/PHP_CodeSniffer/issues/3124
+[sq-3135]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3135
 
 ## [3.5.6] - 2020-08-10
+
 ### Added
 - Added support for PHP 8.0 magic constant dereferencing
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
@@ -969,29 +1841,30 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Michał Bundyra][@michalbundyra] for the patch
 
 ### Fixed
-- Fixed bug [#2877] : PEAR.Functions.FunctionCallSignature false positive for array of functions
+- Fixed bug [#2877][sq-2877] : PEAR.Functions.FunctionCallSignature false positive for array of functions
     - Thanks to [Vincent Langlet][@VincentLanglet] for the patch
-- Fixed bug [#2888] : PSR12.Files.FileHeader blank line error with multiple namespaces in one file
-- Fixed bug [#2926] : phpcs hangs when using arrow functions that return heredoc
-- Fixed bug [#2943] : Redundant semicolon added to a file when fixing PSR2.Files.ClosingTag.NotAllowed
-- Fixed bug [#2967] : Markdown generator does not output headings correctly
+- Fixed bug [#2888][sq-2888] : PSR12.Files.FileHeader blank line error with multiple namespaces in one file
+- Fixed bug [#2926][sq-2926] : phpcs hangs when using arrow functions that return heredoc
+- Fixed bug [#2943][sq-2943] : Redundant semicolon added to a file when fixing PSR2.Files.ClosingTag.NotAllowed
+- Fixed bug [#2967][sq-2967] : Markdown generator does not output headings correctly
     - Thanks to [Petr Bugyík][@o5] for the patch
-- Fixed bug [#2977] : File::isReference() does not detect return by reference for closures
+- Fixed bug [#2977][sq-2977] : File::isReference() does not detect return by reference for closures
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug [#2994] : Generic.Formatting.DisallowMultipleStatements false positive for FOR loop with no body
-- Fixed bug [#3033] : Error generated during tokenizing of goto statements on PHP 8
+- Fixed bug [#2994][sq-2994] : Generic.Formatting.DisallowMultipleStatements false positive for FOR loop with no body
+- Fixed bug [#3033][sq-3033] : Error generated during tokenizing of goto statements on PHP 8
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 
-[#2877]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2877
-[#2888]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2888
-[#2926]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2926
-[#2943]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2943
-[#2967]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2967
-[#2977]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2977
-[#2994]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2994
-[#3033]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3033
+[sq-2877]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2877
+[sq-2888]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2888
+[sq-2926]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2926
+[sq-2943]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2943
+[sq-2967]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2967
+[sq-2977]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2977
+[sq-2994]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2994
+[sq-3033]: https://github.com/squizlabs/PHP_CodeSniffer/pull/3033
 
 ## [3.5.5] - 2020-04-17
+
 ### Changed
 - The T_FN backfill now works more reliably so T_FN tokens only ever represent real arrow functions
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
@@ -1001,25 +1874,40 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 ### Fixed
 - Error wording in PEAR.Functions.FunctionCallSignature now always uses "parenthesis" instead of sometimes using "bracket"
     - Thanks to [Vincent Langlet][@VincentLanglet] for the patch
-- Fixed bug #2787 : Squiz.PHP.DisallowMultipleAssignments not ignoring typed property declarations
+- Fixed bug [#2787][sq-2787] : Squiz.PHP.DisallowMultipleAssignments not ignoring typed property declarations
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2810 : PHPCBF fails to fix file with empty statement at start on control structure
-- Fixed bug #2812 : Squiz.Arrays.ArrayDeclaration not detecting some arrays with multiple arguments on the same line
+- Fixed bug [#2810][sq-2810] : PHPCBF fails to fix file with empty statement at start on control structure
+- Fixed bug [#2812][sq-2812] : Squiz.Arrays.ArrayDeclaration not detecting some arrays with multiple arguments on the same line
     - Thanks to [Jakub Chábek][@grongor] for the patch
-- Fixed bug #2826 : Generic.WhiteSpace.ArbitraryParenthesesSpacing doesn't detect issues for statements directly after a   control structure
+- Fixed bug [#2826][sq-2826] : Generic.WhiteSpace.ArbitraryParenthesesSpacing doesn't detect issues for statements directly after a control structure
     - Thanks to [Vincent Langlet][@VincentLanglet] for the patch
-- Fixed bug #2848 : PSR12.Files.FileHeader false positive for file with mixed PHP and HTML and no file header
-- Fixed bug #2849 : Generic.WhiteSpace.ScopeIndent false positive with arrow function inside array
-- Fixed bug #2850 : Generic.PHP.LowerCaseKeyword complains __HALT_COMPILER is uppercase
-- Fixed bug #2853 : Undefined variable error when using Info report
-    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2865 : Double arrow tokenized as T_STRING when placed after function named "fn"
-- Fixed bug #2867 : Incorrect scope matching when arrow function used inside IF condition
-- Fixed bug #2868 : phpcs:ignore annotation doesnt work inside a docblock
-- Fixed bug #2878 : PSR12.Files.FileHeader conflicts with Generic.Files.LineEndings
-- Fixed bug #2895 : PSR2.Methods.FunctionCallSignature.MultipleArguments false positive with arrow function argument
+- Fixed bug [#2848][sq-2848] : PSR12.Files.FileHeader false positive for file with mixed PHP and HTML and no file header
+- Fixed bug [#2849][sq-2849] : Generic.WhiteSpace.ScopeIndent false positive with arrow function inside array
+- Fixed bug [#2850][sq-2850] : Generic.PHP.LowerCaseKeyword complains __HALT_COMPILER is uppercase
+- Fixed bug [#2853][sq-2853] : Undefined variable error when using Info report
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#2865][sq-2865] : Double arrow tokenized as T_STRING when placed after function named "fn"
+- Fixed bug [#2867][sq-2867] : Incorrect scope matching when arrow function used inside IF condition
+- Fixed bug [#2868][sq-2868] : phpcs:ignore annotation doesn't work inside a docblock
+- Fixed bug [#2878][sq-2878] : PSR12.Files.FileHeader conflicts with Generic.Files.LineEndings
+- Fixed bug [#2895][sq-2895] : PSR2.Methods.FunctionCallSignature.MultipleArguments false positive with arrow function argument
+
+[sq-2787]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2787
+[sq-2810]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2810
+[sq-2812]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2812
+[sq-2826]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2826
+[sq-2848]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2848
+[sq-2849]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2849
+[sq-2850]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2850
+[sq-2853]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2853
+[sq-2865]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2865
+[sq-2867]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2867
+[sq-2868]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2868
+[sq-2878]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2878
+[sq-2895]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2895
 
 ## [3.5.4] - 2020-01-31
+
 ### Changed
 - The PHP 7.4 numeric separator backfill now works correctly for more float formats
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
@@ -1033,7 +1921,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Previously it required these to have curly braces, but there were no statements to enclose in them
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 - PSR12.ControlStructures.BooleanOperatorPlacement can now be configured to enforce a specific operator position
-    - By default, the sniff ensures that operators are all at the begining or end of lines, but not a mix of both
+    - By default, the sniff ensures that operators are all at the beginning or end of lines, but not a mix of both
     - Set the allowOnly property to "first" to enforce all boolean operators to be at the start of a line
     - Set the allowOnly property to "last" to enforce all boolean operators to be at the end of a line
     - Thanks to [Vincent Langlet][@VincentLanglet] for the patch
@@ -1045,46 +1933,66 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Squiz.PHP.InnerFunctions now handles multiple nested anon classes correctly
 
 ### Fixed
-- Fixed bug #2497 : Sniff properties not set when referencing a sniff using relative paths or non-native slashes
+- Fixed bug [#2497][sq-2497] : Sniff properties not set when referencing a sniff using relative paths or non-native slashes
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2657 : Squiz.WhiteSpace.FunctionSpacing can remove spaces between comment and first/last method during auto-fixing
+- Fixed bug [#2657][sq-2657] : Squiz.WhiteSpace.FunctionSpacing can remove spaces between comment and first/last method during auto-fixing
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2688 : Case statements not tokenized correctly when switch is contained within ternary
-- Fixed bug #2698 : PHPCS throws errors determining auto report width when shell_exec is disabled
+- Fixed bug [#2688][sq-2688] : Case statements not tokenized correctly when switch is contained within ternary
+- Fixed bug [#2698][sq-2698] : PHPCS throws errors determining auto report width when shell_exec is disabled
     - Thanks to [Matthew Peveler][@MasterOdin] for the patch
-- Fixed bug #2730 : PSR12.ControlStructures.ControlStructureSpacing does not ignore comments between conditions
+- Fixed bug [#2730][sq-2730] : PSR12.ControlStructures.ControlStructureSpacing does not ignore comments between conditions
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2732 : PSR12.Files.FileHeader misidentifies file header in mixed content file
-- Fixed bug #2745 : AbstractArraySniff wrong indices when mixed coalesce and ternary values
+- Fixed bug [#2732][sq-2732] : PSR12.Files.FileHeader misidentifies file header in mixed content file
+- Fixed bug [#2745][sq-2745] : AbstractArraySniff wrong indices when mixed coalesce and ternary values
     - Thanks to [Michał Bundyra][@michalbundyra] for the patch
-- Fixed bug #2748 : Wrong end of statement for fn closures
+- Fixed bug [#2748][sq-2748] : Wrong end of statement for fn closures
     - Thanks to [Michał Bundyra][@michalbundyra] for the patch
-- Fixed bug #2751 : Autoload relative paths first to avoid confusion with files from the global include path
+- Fixed bug [#2751][sq-2751] : Autoload relative paths first to avoid confusion with files from the global include path
     - Thanks to [Klaus Purer][@klausi] for the patch
-- Fixed bug #2763 : PSR12 standard reports errors for multi-line FOR definitions
-- Fixed bug #2768 : Generic.Files.LineLength false positive for non-breakable strings at exactly the soft limit
+- Fixed bug [#2763][sq-2763] : PSR12 standard reports errors for multi-line FOR definitions
+- Fixed bug [#2768][sq-2768] : Generic.Files.LineLength false positive for non-breakable strings at exactly the soft limit
     - Thanks to [Alex Miles][@ghostal] for the patch
-- Fixed bug #2773 : PSR2.Methods.FunctionCallSignature false positive when arrow function has array return type
-- Fixed bug #2790 : PSR12.Traits.UseDeclaration ignores block comments
+- Fixed bug [#2773][sq-2773] : PSR2.Methods.FunctionCallSignature false positive when arrow function has array return type
+- Fixed bug [#2790][sq-2790] : PSR12.Traits.UseDeclaration ignores block comments
     - Thanks to [Vincent Langlet][@VincentLanglet] for the patch
-- Fixed bug #2791 : PSR12.Functions.NullableTypeDeclaration false positive when ternary operator used with instanceof
-    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2802 : Can't specify a report file path using the tilde shortcut
-- Fixed bug #2804 : PHP4-style typed properties not tokenized correctly
-    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2805 : Undefined Offset notice during live coding of arrow functions
-    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2843 : Tokenizer does not support alternative syntax for declare statements
-    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#2791][sq-2791] : PSR12.Functions.NullableTypeDeclaration false positive when ternary operator used with instanceof
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#2802][sq-2802] : Can't specify a report file path using the tilde shortcut
+- Fixed bug [#2804][sq-2804] : PHP4-style typed properties not tokenized correctly
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#2805][sq-2805] : Undefined Offset notice during live coding of arrow functions
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#2843][sq-2843] : Tokenizer does not support alternative syntax for declare statements
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+
+[sq-2497]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2497
+[sq-2657]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2657
+[sq-2688]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2688
+[sq-2698]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2698
+[sq-2730]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2730
+[sq-2732]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2732
+[sq-2745]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2745
+[sq-2748]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2748
+[sq-2751]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2751
+[sq-2763]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2763
+[sq-2768]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2768
+[sq-2773]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2773
+[sq-2790]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2790
+[sq-2791]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2791
+[sq-2802]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2802
+[sq-2804]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2804
+[sq-2805]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2805
+[sq-2843]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2843
 
 ## [3.5.3] - 2019-12-04
+
 ### Changed
 - The PHP 7.4 T_FN token has been made available for older versions
     - T_FN represents the fn string used for arrow functions
     - The double arrow becomes the scope opener, and uses a new T_FN_ARROW token type
     - The token after the statement (normally a semicolon) becomes the scope closer
     - The token is also associated with the opening and closing parenthesis of the statement
-    - Any functions named "fn" will cause have a T_FN token for the function name, but have no scope information
+    - Any functions named "fn" will have a T_FN token for the function name, but have no scope information
     - Thanks to [Michał Bundyra][@michalbundyra] for the help with this change
 - PHP 7.4 numeric separators are now tokenized in the same way when using older PHP versions
     - Previously, a number like 1_000 would tokenize as T_LNUMBER (1), T_STRING (_000)
@@ -1120,24 +2028,35 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Michał Bundyra][@michalbundyra] for the patch
 
 ### Fixed
-- Fixed bug #2586 : Generic.WhiteSpace.ScopeIndent false positives when indenting open tags at a non tab-stop
-- Fixed bug #2638 : Squiz.CSS.DuplicateClassDefinitionSniff sees comments as part of the class name
+- Fixed bug [#2586][sq-2586] : Generic.WhiteSpace.ScopeIndent false positives when indenting open tags at a non tab-stop
+- Fixed bug [#2638][sq-2638] : Squiz.CSS.DuplicateClassDefinitionSniff sees comments as part of the class name
     - Thanks to [Raphael Horber][@rhorber] for the patch
-- Fixed bug #2640 : Squiz.WhiteSpace.OperatorSpacing false positives for some negation operators
+- Fixed bug [#2640][sq-2640] : Squiz.WhiteSpace.OperatorSpacing false positives for some negation operators
     - Thanks to [Jakub Chábek][@grongor] and [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2674 : Squiz.Functions.FunctionDeclarationArgumentSpacing prints wrong argument name in error message
-- Fixed bug #2676 : PSR12.Files.FileHeader locks up when file ends with multiple inline comments
-- Fixed bug #2678 : PSR12.Classes.AnonClassDeclaration incorrectly enforcing that closing brace be on a line by itself
-- Fixed bug #2685 : File::getMethodParameters() setting typeHintEndToken for vars with no type hint
+- Fixed bug [#2674][sq-2674] : Squiz.Functions.FunctionDeclarationArgumentSpacing prints wrong argument name in error message
+- Fixed bug [#2676][sq-2676] : PSR12.Files.FileHeader locks up when file ends with multiple inline comments
+- Fixed bug [#2678][sq-2678] : PSR12.Classes.AnonClassDeclaration incorrectly enforcing that closing brace be on a line by itself
+- Fixed bug [#2685][sq-2685] : File::getMethodParameters() setting typeHintEndToken for vars with no type hint
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2694 : AbstractArraySniff produces invalid indices when using ternary operator
+- Fixed bug [#2694][sq-2694] : AbstractArraySniff produces invalid indices when using ternary operator
     - Thanks to [Michał Bundyra][@michalbundyra] for the patch
-- Fixed bug #2702 : Generic.WhiteSpace.ScopeIndent false positive when using ternary operator with short arrays
+- Fixed bug [#2702][sq-2702] : Generic.WhiteSpace.ScopeIndent false positive when using ternary operator with short arrays
+
+[sq-2586]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2586
+[sq-2638]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2638
+[sq-2640]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2640
+[sq-2674]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2674
+[sq-2676]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2676
+[sq-2678]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2678
+[sq-2685]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2685
+[sq-2694]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2694
+[sq-2702]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2702
 
 ## [3.5.2] - 2019-10-28
+
 ### Changed
 - Generic.ControlStructures.DisallowYodaConditions now returns less false positives
-    - False positives were being returned for array comparisions, or when performing some function calls
+    - False positives were being returned for array comparisons, or when performing some function calls
 - Squiz.WhiteSpace.SemicolonSpacing.Incorrect error message now escapes newlines and tabs
     - Provides a clearer error message as whitespace is now visible
     - Also allows for better output for report types such as CSV and XML
@@ -1146,15 +2065,23 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Craig Duncan][@duncan3dc] for the patch
 
 ### Fixed
-- Fixed bug #2654 : Incorrect indentation for arguments of multiline function calls
-- Fixed bug #2656 : Squiz.WhiteSpace.MemberVarSpacing removes comments before first member var during auto fixing
+- Fixed bug [#2654][sq-2654] : Incorrect indentation for arguments of multiline function calls
+- Fixed bug [#2656][sq-2656] : Squiz.WhiteSpace.MemberVarSpacing removes comments before first member var during auto fixing
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2663 : Generic.NamingConventions.ConstructorName complains about old constructor in interfaces
-- Fixed bug #2664 : PSR12.Files.OpenTag incorrectly identifies PHP file with only an opening tag
-- Fixed bug #2665 : PSR12.Files.ImportStatement should not apply to traits
-- Fixed bug #2673 : PSR12.Traits.UseDeclaration does not allow comments or blank lines between use statements
+- Fixed bug [#2663][sq-2663] : Generic.NamingConventions.ConstructorName complains about old constructor in interfaces
+- Fixed bug [#2664][sq-2664] : PSR12.Files.OpenTag incorrectly identifies PHP file with only an opening tag
+- Fixed bug [#2665][sq-2665] : PSR12.Files.ImportStatement should not apply to traits
+- Fixed bug [#2673][sq-2673] : PSR12.Traits.UseDeclaration does not allow comments or blank lines between use statements
+
+[sq-2654]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2654
+[sq-2656]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2656
+[sq-2663]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2663
+[sq-2664]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2664
+[sq-2665]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2665
+[sq-2673]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2673
 
 ## [3.5.1] - 2019-10-17
+
 ### Changed
 - Very very verbose diff report output has slightly changed to improve readability
     - Output is printed when running PHPCS with the --report=diff and -vvv command line arguments
@@ -1164,28 +2091,42 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - This check has been missing from these standards, but has now been implemented
     - When using the PEAR standard, the error code is PEAR.Functions.FunctionCallSignature.FirstArgumentPosition
     - When using PSR2 or PSR12, the error code is PSR2.Methods.FunctionCallSignature.FirstArgumentPosition
-- PSR12.ControlStructures.BooleanOperatorPlacement no longer complains when multiple expression appears on the same line
-    - Previously, boolean operators were enforce to appear at the start or end of lines only
+- PSR12.ControlStructures.BooleanOperatorPlacement no longer complains when multiple expressions appear on the same line
+    - Previously, boolean operators were enforced to appear at the start or end of lines only
     - Boolean operators can now appear in the middle of the line
 - PSR12.Files.FileHeader no longer ignores comments preceding a use, namespace, or declare statement
 - PSR12.Files.FileHeader now allows a hashbang line at the top of the file
 
 ### Fixed
-- Fixed bug #2506 : PSR2 standard can't auto fix multi-line function call inside a string concat statement
-- Fixed bug #2530 : PEAR.Commenting.FunctionComment does not support intersection types in comments
-- Fixed bug #2615 : Constant visibility false positive on non-class constants
-- Fixed bug #2616 : PSR12.Files.FileHeader false positive when file only contains docblock
-- Fixed bug #2619 : PSR12.Files.FileHeader locks up when inline comment is the last content in a file
-- Fixed bug #2621 : PSR12.Classes.AnonClassDeclaration.CloseBraceSameLine false positive for anon class passed as function argument
+- Fixed bug [#2506][sq-2506] : PSR2 standard can't auto fix multi-line function call inside a string concat statement
+- Fixed bug [#2530][sq-2530] : PEAR.Commenting.FunctionComment does not support intersection types in comments
+- Fixed bug [#2615][sq-2615] : Constant visibility false positive on non-class constants
+- Fixed bug [#2616][sq-2616] : PSR12.Files.FileHeader false positive when file only contains docblock
+- Fixed bug [#2619][sq-2619] : PSR12.Files.FileHeader locks up when inline comment is the last content in a file
+- Fixed bug [#2621][sq-2621] : PSR12.Classes.AnonClassDeclaration.CloseBraceSameLine false positive for anon class passed as function argument
     - Thanks to [Martins Sipenko][@martinssipenko] for the patch
-- Fixed bug #2623 : PSR12.ControlStructures.ControlStructureSpacing not ignoring indentation inside multi-line string arguments
-- Fixed bug #2624 : PSR12.Traits.UseDeclaration doesnt apply the correct indent during auto fixing
-- Fixed bug #2626 : PSR12.Files.FileHeader detects @var annotations as file docblocks
-- Fixed bug #2628 : PSR12.Traits.UseDeclaration does not allow comments above a USE declaration
-- Fixed bug #2632 : Incorrect indentation of lines starting with "static" inside closures
-- Fixed bug #2641 : PSR12.Functions.NullableTypeDeclaration false positive when using new static()
+- Fixed bug [#2623][sq-2623] : PSR12.ControlStructures.ControlStructureSpacing not ignoring indentation inside multi-line string arguments
+- Fixed bug [#2624][sq-2624] : PSR12.Traits.UseDeclaration doesnt apply the correct indent during auto fixing
+- Fixed bug [#2626][sq-2626] : PSR12.Files.FileHeader detects @var annotations as file docblocks
+- Fixed bug [#2628][sq-2628] : PSR12.Traits.UseDeclaration does not allow comments above a USE declaration
+- Fixed bug [#2632][sq-2632] : Incorrect indentation of lines starting with "static" inside closures
+- Fixed bug [#2641][sq-2641] : PSR12.Functions.NullableTypeDeclaration false positive when using new static()
+
+[sq-2506]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2506
+[sq-2530]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2530
+[sq-2615]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2615
+[sq-2616]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2616
+[sq-2619]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2619
+[sq-2621]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2621
+[sq-2623]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2623
+[sq-2624]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2624
+[sq-2626]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2626
+[sq-2628]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2628
+[sq-2632]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2632
+[sq-2641]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2641
 
 ## [3.5.0] - 2019-09-27
+
 ### Changed
 - The included PSR12 standard is now complete and ready to use
     - Check your code using PSR-12 by running PHPCS with --standard=PSR12
@@ -1209,11 +2150,11 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 - The tokenizer now correctly identifies inline control structures in more cases
 - All helper methods inside the File class now throw RuntimeException instead of TokenizerException
-    - Some tokenizer methods were also throwing RuntimeExpection but now correctly throw TokenizerException
+    - Some tokenizer methods were also throwing RuntimeException but now correctly throw TokenizerException
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 - The File::getMethodParameters() method now returns more information, and supports closure USE groups
     - If a type hint is specified, the position of the last token in the hint will be set in a "type_hint_end_token" array index
-    - If a default is specified, the position of the first token in the default value will be set in a "default_token" array   index
+    - If a default is specified, the position of the first token in the default value will be set in a "default_token" array index
     - If a default is specified, the position of the equals sign will be set in a "default_equal_token" array index
     - If the param is not the last, the position of the comma will be set in a "comma_token" array index
     - If the param is passed by reference, the position of the reference operator will be set in a "reference_token" array index
@@ -1256,7 +2197,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Added PSR12.Files.ImportStatement sniff
     - Enforces the formatting of import statements within a file
 - Added PSR12.Files.OpenTag sniff
-    - Enforces that the open tag is on a line by itself when used at the start of a php-only file
+    - Enforces that the open tag is on a line by itself when used at the start of a PHP-only file
 - Added PSR12.Functions.ReturnTypeDeclaration sniff
     - Enforces the formatting of return type declarations in functions and closures
 - Added PSR12.Properties.ConstantVisibility sniff
@@ -1273,9 +2214,9 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Use the Squiz.WhiteSpace.OperatorSpacing sniff to enforce spacing around assignment operators
         - Note that this sniff checks spacing around all assignment operators, not just inside function calls
     - The Generic.Functions.FunctionCallArgumentSpacing.NoSpaceBeforeEquals error has been removed
-        - use Squiz.WhiteSpace.OperatorSpacing.NoSpaceBefore instead
+        - Use Squiz.WhiteSpace.OperatorSpacing.NoSpaceBefore instead
     - The Generic.Functions.FunctionCallArgumentSpacing.NoSpaceAfterEquals error has been removed
-        - use Squiz.WhiteSpace.OperatorSpacing.NoSpaceAfter instead
+        - Use Squiz.WhiteSpace.OperatorSpacing.NoSpaceAfter instead
     - This also changes the PEAR/PSR2/PSR12 standards so they no longer check assignment operators inside function calls
         - They were previously checking these operators when they should not have
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
@@ -1303,7 +2244,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Squiz.Operators.IncrementDecrementUsage now suggests pre-increment of variables instead of post-increment
     - This change does not enforce pre-increment over post-increment; only the suggestion has changed
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Squiz.PHP.DisallowMultipleAssignments now has a second error code for when assignments are found inside control structure   conditions
+- Squiz.PHP.DisallowMultipleAssignments now has a second error code for when assignments are found inside control structure conditions
     - The new error code is Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure
     - All other multiple assignment cases use the existing error code Squiz.PHP.DisallowMultipleAssignments.Found
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
@@ -1321,60 +2262,95 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Jakub Chábek][@grongor] for the patch
 
 ### Fixed
-- Fixed bug #2391 : Sniff-specific ignore rules inside rulesets are filtering out too many files
+- Fixed bug [#2391][sq-2391] : Sniff-specific ignore rules inside rulesets are filtering out too many files
     - Thanks to [Juliette Reinders Folmer][@jrfnl] and [Willington Vega][@wvega] for the patch
-- Fixed bug #2478 : FunctionCommentThrowTag.WrongNumber when exception is thrown once but built conditionally
-- Fixed bug #2479 : Generic.WhiteSpace.ScopeIndent error when using array destructing with exact indent checking
-- Fixed bug #2498 : Squiz.Arrays.ArrayDeclaration.MultiLineNotAllowed autofix breaks heredoc
-- Fixed bug #2502 : Generic.WhiteSpace.ScopeIndent false positives with nested switch indentation and case fall-through
-- Fixed bug #2504 : Generic.WhiteSpace.ScopeIndent false positives with nested arrays and nowdoc string
-- Fixed bug #2511 : PSR2 standard not checking if closing paren of single-line function declaration is on new line
-- Fixed bug #2512 : Squiz.PHP.NonExecutableCode does not support alternate SWITCH control structure
+- Fixed bug [#2478][sq-2478] : FunctionCommentThrowTag.WrongNumber when exception is thrown once but built conditionally
+- Fixed bug [#2479][sq-2479] : Generic.WhiteSpace.ScopeIndent error when using array destructing with exact indent checking
+- Fixed bug [#2498][sq-2498] : Squiz.Arrays.ArrayDeclaration.MultiLineNotAllowed autofix breaks heredoc
+- Fixed bug [#2502][sq-2502] : Generic.WhiteSpace.ScopeIndent false positives with nested switch indentation and case fall-through
+- Fixed bug [#2504][sq-2504] : Generic.WhiteSpace.ScopeIndent false positives with nested arrays and nowdoc string
+- Fixed bug [#2511][sq-2511] : PSR2 standard not checking if closing paren of single-line function declaration is on new line
+- Fixed bug [#2512][sq-2512] : Squiz.PHP.NonExecutableCode does not support alternate SWITCH control structure
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2522 : Text generator throws error when code sample line is too long
+- Fixed bug [#2522][sq-2522] : Text generator throws error when code sample line is too long
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2526 : XML report format has bad syntax on Windows
+- Fixed bug [#2526][sq-2526] : XML report format has bad syntax on Windows
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2529 : Generic.Formatting.MultipleStatementAlignment wrong error for assign in string concat
-- Fixed bug #2534 : Unresolvable installed_paths can lead to open_basedir errors
+- Fixed bug [#2529][sq-2529] : Generic.Formatting.MultipleStatementAlignment wrong error for assign in string concat
+- Fixed bug [#2534][sq-2534] : Unresolvable installed_paths can lead to open_basedir errors
     - Thanks to [Oliver Nowak][@ndm2] for the patch
-- Fixed bug #2541 : Text doc generator does not allow for multi-line rule explanations
+- Fixed bug [#2541][sq-2541] : Text doc generator does not allow for multi-line rule explanations
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2549 : Searching for a phpcs.xml file can throw warnings due to open_basedir restrictions
+- Fixed bug [#2549][sq-2549] : Searching for a phpcs.xml file can throw warnings due to open_basedir restrictions
     - Thanks to [Matthew Peveler][@MasterOdin] for the patch
-- Fixed bug #2558 : PHP 7.4 throwing offset syntax with curly braces is deprecated message
+- Fixed bug [#2558][sq-2558] : PHP 7.4 throwing offset syntax with curly braces is deprecated message
     - Thanks to [Matthew Peveler][@MasterOdin] for the patch
-- Fixed bug #2561 : PHP 7.4 compatibility fix / implode argument order
-    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2562 : Inline WHILE triggers SpaceBeforeSemicolon incorrectly
-    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2565 : Generic.ControlStructures.InlineControlStructure confused by mixed short/long tags
-    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2566 : Author tag email validation doesn't support all TLDs
-    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2575 : Custom error messages don't have data replaced when cache is enabled
-- Fixed bug #2601 : Squiz.WhiteSpace.FunctionSpacing incorrect fix when spacing is 0
-- Fixed bug #2608 : PSR2 throws errors for use statements when multiple namespaces are defined in a file
+- Fixed bug [#2561][sq-2561] : PHP 7.4 compatibility fix / implode argument order
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#2562][sq-2562] : Inline WHILE triggers SpaceBeforeSemicolon incorrectly
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#2565][sq-2565] : Generic.ControlStructures.InlineControlStructure confused by mixed short/long tags
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#2566][sq-2566] : Author tag email validation doesn't support all TLDs
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#2575][sq-2575] : Custom error messages don't have data replaced when cache is enabled
+- Fixed bug [#2601][sq-2601] : Squiz.WhiteSpace.FunctionSpacing incorrect fix when spacing is 0
+- Fixed bug [#2608][sq-2608] : PSR2 throws errors for use statements when multiple namespaces are defined in a file
+
+[sq-2391]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2391
+[sq-2478]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2478
+[sq-2479]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2479
+[sq-2498]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2498
+[sq-2502]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2502
+[sq-2504]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2504
+[sq-2511]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2511
+[sq-2512]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2512
+[sq-2522]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2522
+[sq-2526]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2526
+[sq-2529]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2529
+[sq-2534]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2534
+[sq-2541]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2541
+[sq-2549]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2549
+[sq-2558]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2558
+[sq-2561]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2561
+[sq-2562]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2562
+[sq-2565]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2565
+[sq-2566]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2566
+[sq-2575]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2575
+[sq-2601]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2601
+[sq-2608]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2608
 
 ## [3.4.2] - 2019-04-11
+
 ### Changed
 - Squiz.Arrays.ArrayDeclaration now has improved handling of syntax errors
 
 ### Fixed
 - Fixed an issue where the PCRE JIT on PHP 7.3 caused PHPCS to die when using the parallel option
     - PHPCS now disables the PCRE JIT before running
-- Fixed bug #2368 : MySource.PHP.AjaxNullComparison throws error when first function has no doc comment
-- Fixed bug #2414 : Indention false positive in switch/case/if combination
-- Fixed bug #2423 : Squiz.Formatting.OperatorBracket.MissingBrackets error with static
-- Fixed bug #2450 : Indentation false positive when closure containing nested IF conditions used as function argument
-- Fixed bug #2452 : LowercasePHPFunctions sniff failing on "new \File()"
-- Fixed bug #2453 : Squiz.CSS.SemicolonSpacingSniff false positive when style name proceeded by an asterisk
-    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2464 : Fixer conflict between Generic.WhiteSpace.ScopeIndent and Squiz.WhiteSpace.ScopeClosingBrace when class   indented 1 space
-- Fixed bug #2465 : Excluding a sniff by path is not working
-- Fixed bug #2467 : PHP open/close tags inside CSS files are replaced with internal PHPCS token strings when auto fixing
+- Fixed bug [#2368][sq-2368] : MySource.PHP.AjaxNullComparison throws error when first function has no doc comment
+- Fixed bug [#2414][sq-2414] : Indention false positive in switch/case/if combination
+- Fixed bug [#2423][sq-2423] : Squiz.Formatting.OperatorBracket.MissingBrackets error with static
+- Fixed bug [#2450][sq-2450] : Indentation false positive when closure containing nested IF conditions used as function argument
+- Fixed bug [#2452][sq-2452] : LowercasePHPFunctions sniff failing on "new \File()"
+- Fixed bug [#2453][sq-2453] : Squiz.CSS.SemicolonSpacingSniff false positive when style name proceeded by an asterisk
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#2464][sq-2464] : Fixer conflict between Generic.WhiteSpace.ScopeIndent and Squiz.WhiteSpace.ScopeClosingBrace when class indented 1 space
+- Fixed bug [#2465][sq-2465] : Excluding a sniff by path is not working
+- Fixed bug [#2467][sq-2467] : PHP open/close tags inside CSS files are replaced with internal PHPCS token strings when auto fixing
+
+[sq-2368]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2368
+[sq-2414]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2414
+[sq-2423]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2423
+[sq-2450]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2450
+[sq-2452]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2452
+[sq-2453]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2453
+[sq-2464]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2464
+[sq-2465]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2465
+[sq-2467]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2467
 
 ## [3.4.1] - 2019-03-19
+
 ### Changed
 - The PEAR installable version of PHPCS was missing some files, which have been re-included in this release
     - The code report was not previously available for PEAR installs
@@ -1400,16 +2376,16 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 - Generic.Files.LineEndings no longer adds superfluous new line at the end of JS and CSS files
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Generic.Formatting.DisallowMultipleStatements no longer tries fix lines containing phpcs:ignore statements
+- Generic.Formatting.DisallowMultipleStatements no longer tries to fix lines containing phpcs:ignore statements
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 - Generic.Functions.FunctionCallArgumentSpacing now has improved performance and anonymous class support
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 - Generic.WhiteSpace.ScopeIndent now respects changes to the "exact" property using phpcs:set mid-way through a file
-    - This allows you change the "exact" rule for only some parts of a file
+    - This allows you to change the "exact" rule for only some parts of a file
 - Generic.WhiteSpace.ScopeIndent now disables exact indent checking inside all arrays
     - Previously, this was only done when using long array syntax, but it now works for short array syntax as well
 - PEAR.Classes.ClassDeclaration now has improved handling of PHPCS annotations and tab indents
-- PSR12.Classes.ClassInstantiation has changed it's error code from MissingParenthesis to MissingParentheses
+- PSR12.Classes.ClassInstantiation has changed its error code from MissingParenthesis to MissingParentheses
 - PSR12.Keywords.ShortFormTypeKeywords now ignores all spacing inside type casts during both checking and fixing
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 - Squiz.Classes.LowercaseClassKeywords now examines the class keyword for anonymous classes
@@ -1443,24 +2419,33 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 - Squiz.WhiteSpace.SuperfluousWhitespace no longer throws errors for spacing between functions and properties in anon classes
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Zend.Files.ClosingTag no longer adds a semi-colon during fixing of a file that only contains a comment
+- Zend.Files.ClosingTag no longer adds a semicolon during fixing of a file that only contains a comment
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 - Zend.NamingConventions.ValidVariableName now supports variables inside anonymous classes correctly
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 
 ### Fixed
-- Fixed bug #2298 : PSR2.Classes.ClassDeclaration allows extended class on new line
+- Fixed bug [#2298][sq-2298] : PSR2.Classes.ClassDeclaration allows extended class on new line
     - Thanks to [Michał Bundyra][@michalbundyra] for the patch
-- Fixed bug #2337 : Generic.WhiteSpace.ScopeIndent incorrect error when multi-line function call starts on same line as open   tag
-- Fixed bug #2348 : Cache not invalidated when changing a ruleset included by another
-- Fixed bug #2376 : Using __halt_compiler() breaks Generic.PHP.ForbiddenFunctions unless it's last in the function list
+- Fixed bug [#2337][sq-2337] : Generic.WhiteSpace.ScopeIndent incorrect error when multi-line function call starts on same line as open tag
+- Fixed bug [#2348][sq-2348] : Cache not invalidated when changing a ruleset included by another
+- Fixed bug [#2376][sq-2376] : Using __halt_compiler() breaks Generic.PHP.ForbiddenFunctions unless it's last in the function list
     - Thanks to [Sijun Zhu][@Billz95] for the patch
-- Fixed bug #2393 : The gitmodified filter will infinitely loop when encountering deleted file paths
+- Fixed bug [#2393][sq-2393] : The gitmodified filter will infinitely loop when encountering deleted file paths
     - Thanks to [Lucas Manzke][@lmanzke] for the patch
-- Fixed bug #2396 : Generic.WhiteSpace.ScopeIndent incorrect error when multi-line IF condition mixed with HTML
-- Fixed bug #2431 : Use function/const not tokenized as T_STRING when preceded by comment
+- Fixed bug [#2396][sq-2396] : Generic.WhiteSpace.ScopeIndent incorrect error when multi-line IF condition mixed with HTML
+- Fixed bug [#2431][sq-2431] : Use function/const not tokenized as T_STRING when preceded by comment
+
+[sq-2298]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2298
+[sq-2337]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2337
+[sq-2348]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2348
+[sq-2376]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2376
+[sq-2393]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2393
+[sq-2396]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2396
+[sq-2431]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2431
 
 ## [3.4.0] - 2018-12-20
+
 ### Deprecated
 - The Generic.Formatting.NoSpaceAfterCast sniff has been deprecated and will be removed in version 4
     - The functionality of this sniff is now available in the Generic.Formatting.SpaceAfterCast sniff
@@ -1483,8 +2468,8 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - This change also converts '(binary)' from T_STRING_CAST to T_BINARY_CAST
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the help with this patch
 - Array properties set inside a ruleset.xml file can now extend a previous value instead of always overwriting it
-    - e.g., if you include a ruleset that defines forbidden functions, can you now add to that list instead of having to   redefine it
-    - To use this feature, add extends="true" to the property tag
+    - e.g., if you include a ruleset that defines forbidden functions, can you now add to that list instead of having to redefine it
+    - To use this feature, add extend="true" to the property tag
         - e.g., property name="forbiddenFunctionNames" type="array" extend="true"
     - Thanks to [Michael Moravec][@Majkl578] for the patch
 - If $XDG_CACHE_HOME is set and points to a valid directory, it will be used for caching instead of the system temp directory
@@ -1527,7 +2512,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
         - Squiz.Scope.MethodScope
         - Squiz.Scope.StaticThisUsage
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Generic.CodeAnalysis.UnusedFunctionParameter now only skips functions with empty bodies when the class implements an   interface
+- Generic.CodeAnalysis.UnusedFunctionParameter now only skips functions with empty bodies when the class implements an interface
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 - Generic.CodeAnalysis.UnusedFunctionParameter now has additional error codes to indicate where unused params were found
     - The new error code prefixes are:
@@ -1600,49 +2585,68 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 
 ### Fixed
-- Fixed bug #2109 : Generic.Functions.CallTimePassByReference false positive for bitwise and used in function argument
-- Fixed bug #2165 : Conflict between Squiz.Arrays.ArrayDeclaration and ScopeIndent sniffs when heredoc used in array
-- Fixed bug #2167 : Generic.WhiteSpace.ScopeIndent shows invalid error when scope opener indented inside inline HTML
-- Fixed bug #2178 : Generic.NamingConventions.ConstructorName matches methods in anon classes with same name as containing   class
+- Fixed bug [#2109][sq-2109] : Generic.Functions.CallTimePassByReference false positive for bitwise and used in function argument
+- Fixed bug [#2165][sq-2165] : Conflict between Squiz.Arrays.ArrayDeclaration and ScopeIndent sniffs when heredoc used in array
+- Fixed bug [#2167][sq-2167] : Generic.WhiteSpace.ScopeIndent shows invalid error when scope opener indented inside inline HTML
+- Fixed bug [#2178][sq-2178] : Generic.NamingConventions.ConstructorName matches methods in anon classes with same name as containing class
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2190 : PEAR.Functions.FunctionCallSignature incorrect error when encountering trailing PHPCS annotation
+- Fixed bug [#2190][sq-2190] : PEAR.Functions.FunctionCallSignature incorrect error when encountering trailing PHPCS annotation
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2194 : Generic.Whitespace.LanguageConstructSpacing should not be checking namespace operators
+- Fixed bug [#2194][sq-2194] : Generic.Whitespace.LanguageConstructSpacing should not be checking namespace operators
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2202 : Squiz.WhiteSpace.OperatorSpacing throws error for negative index when using curly braces for string   access
+- Fixed bug [#2202][sq-2202] : Squiz.WhiteSpace.OperatorSpacing throws error for negative index when using curly braces for string access
     - Same issue fixed in Squiz.Formatting.OperatorBracket
     - Thanks to [Andreas Buchenrieder][@anbuc] for the patch
-- Fixed bug #2210 : Generic.NamingConventions.CamelCapsFunctionName not ignoring SoapClient __getCookies() method
+- Fixed bug [#2210][sq-2210] : Generic.NamingConventions.CamelCapsFunctionName not ignoring SoapClient __getCookies() method
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2211 : PSR2.Methods.MethodDeclaration gets confused over comments between modifier keywords
+- Fixed bug [#2211][sq-2211] : PSR2.Methods.MethodDeclaration gets confused over comments between modifier keywords
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2212 : FUNCTION and CONST in use groups being tokenised as T_FUNCTION and T_CONST
+- Fixed bug [#2212][sq-2212] : FUNCTION and CONST in use groups being tokenized as T_FUNCTION and T_CONST
     - Thanks to [Chris Wilkinson][@thewilkybarkid] for the patch
-- Fixed bug #2214 : File::getMemberProperties() is recognizing method params as properties
+- Fixed bug [#2214][sq-2214] : File::getMemberProperties() is recognizing method params as properties
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2236 : Memory info measurement unit is Mb but probably should be MB
-- Fixed bug #2246 : CSS tokenizer does not tokenize class names correctly when they contain the string NEW
+- Fixed bug [#2236][sq-2236] : Memory info measurement unit is Mb but probably should be MB
+- Fixed bug [#2246][sq-2246] : CSS tokenizer does not tokenize class names correctly when they contain the string NEW
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2278 : Squiz.Operators.ComparisonOperatorUsage false positive when inline IF contained in parentheses
+- Fixed bug [#2278][sq-2278] : Squiz.Operators.ComparisonOperatorUsage false positive when inline IF contained in parentheses
     - Thanks to [Arnout Boks][@aboks] for the patch
-- Fixed bug #2284 : Squiz.Functions.FunctionDeclarationArgumentSpacing removing type hint during fixing
+- Fixed bug [#2284][sq-2284] : Squiz.Functions.FunctionDeclarationArgumentSpacing removing type hint during fixing
     - Thanks to [Michał Bundyra][@michalbundyra] for the patch
-- Fixed bug #2297 : Anonymous class not tokenized correctly when used as argument to another anon class
+- Fixed bug [#2297][sq-2297] : Anonymous class not tokenized correctly when used as argument to another anon class
     - Thanks to [Michał Bundyra][@michalbundyra] for the patch
 
+[sq-2109]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2109
+[sq-2165]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2165
+[sq-2167]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2167
+[sq-2178]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2178
+[sq-2190]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2190
+[sq-2194]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2194
+[sq-2202]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2202
+[sq-2210]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2210
+[sq-2211]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2211
+[sq-2212]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2212
+[sq-2214]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2214
+[sq-2236]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2236
+[sq-2246]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2246
+[sq-2278]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2278
+[sq-2284]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2284
+[sq-2297]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2297
+
 ## [2.9.2] - 2018-11-08
+
 ### Changed
 - PHPCS should now run under PHP 7.3 without deprecation warnings
     - Thanks to [Nick Wilde][@NickDickinsonWilde] for the patch
 
 ### Fixed
-- Fixed bug #1496 : Squiz.Strings.DoubleQuoteUsage not unescaping dollar sign when fixing
+- Fixed bug [#1496][sq-1496] : Squiz.Strings.DoubleQuoteUsage not unescaping dollar sign when fixing
     - Thanks to [Michał Bundyra][@michalbundyra] for the patch
-- Fixed bug #1549 : Squiz.PHP.EmbeddedPhp fixer conflict with // comment before PHP close tag
+- Fixed bug [#1549][sq-1549] : Squiz.PHP.EmbeddedPhp fixer conflict with // comment before PHP close tag
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #1890 : Incorrect Squiz.WhiteSpace.ControlStructureSpacing.NoLineAfterClose error between catch and finally statements
+- Fixed bug [#1890][sq-1890] : Incorrect Squiz.WhiteSpace.ControlStructureSpacing.NoLineAfterClose error between catch and finally statements
 
 ## [3.3.2] - 2018-09-24
+
 ### Changed
 - Fixed a problem where the report cache was not being cleared when the sniffs inside a standard were updated
 - The info report (--report=info) now has improved formatting for metrics that span multiple lines
@@ -1664,22 +2668,34 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 ### Fixed
 - Fixed a problem where referencing a relative file path in a ruleset XML file could add unnecessary sniff exclusions
     - This didn't actually exclude anything, but caused verbose output to list strange exclusion rules
-- Fixed bug #2110 : Squiz.WhiteSpace.FunctionSpacing is removing indents from the start of functions when fixing
+- Fixed bug [#2110][sq-2110] : Squiz.WhiteSpace.FunctionSpacing is removing indents from the start of functions when fixing
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2115 : Squiz.Commenting.VariableComment not checking var types when the @var line contains a comment
-- Fixed bug #2120 : Tokenizer fails to match T_INLINE_ELSE when used after function call containing closure
-- Fixed bug #2121 : Squiz.PHP.DisallowMultipleAssignments false positive in while loop conditions
+- Fixed bug [#2115][sq-2115] : Squiz.Commenting.VariableComment not checking var types when the @var line contains a comment
+- Fixed bug [#2120][sq-2120] : Tokenizer fails to match T_INLINE_ELSE when used after function call containing closure
+- Fixed bug [#2121][sq-2121] : Squiz.PHP.DisallowMultipleAssignments false positive in while loop conditions
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2127 : File::findExtendedClassName() doesn't support nested classes
+- Fixed bug [#2127][sq-2127] : File::findExtendedClassName() doesn't support nested classes
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2138 : Tokenizer detects wrong token for php ::class feature with spaces
-- Fixed bug #2143 : PSR2.Namespaces.UseDeclaration does not properly fix "use function" and "use const" statements
+- Fixed bug [#2138][sq-2138] : Tokenizer detects wrong token for PHP ::class feature with spaces
+- Fixed bug [#2143][sq-2143] : PSR2.Namespaces.UseDeclaration does not properly fix "use function" and "use const" statements
     - Thanks to [Chris Wilkinson][@thewilkybarkid] for the patch
-- Fixed bug #2144 : Squiz.Arrays.ArrayDeclaration does incorrect align calculation in array with cyrillic keys
-- Fixed bug #2146 : Zend.Files.ClosingTag removes closing tag from end of file without inserting a semicolon
-- Fixed bug #2151 : XML schema not updated with the new array property syntax
+- Fixed bug [#2144][sq-2144] : Squiz.Arrays.ArrayDeclaration does incorrect align calculation in array with cyrillic keys
+- Fixed bug [#2146][sq-2146] : Zend.Files.ClosingTag removes closing tag from end of file without inserting a semicolon
+- Fixed bug [#2151][sq-2151] : XML schema not updated with the new array property syntax
+
+[sq-2110]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2110
+[sq-2115]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2115
+[sq-2120]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2120
+[sq-2121]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2121
+[sq-2127]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2127
+[sq-2138]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2138
+[sq-2143]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2143
+[sq-2144]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2144
+[sq-2146]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2146
+[sq-2151]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2151
 
 ## [3.3.1] - 2018-07-27
+
 ### Removed
 - Support for HHVM has been dropped due to recent unfixed bugs and HHVM refocus on Hack only
     - Thanks to [Walt Sorensen][@photodude] and [Juliette Reinders Folmer][@jrfnl] for helping to remove all HHVM exceptions from the core
@@ -1701,7 +2717,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 - Generic.PHP.Syntax will now use PHP_BINARY instead of trying to discover the executable path
     - This ensures that the sniff will always syntax check files using the PHP version that PHPCS is running under
-    - Setting the php_path config var will still override this value as normal
+    - Setting the `php_path` config var will still override this value as normal
     - Thanks to [Willem Stuursma-Ruwen][@willemstuursma] for the patch
 - PSR2.Namespaces.UseDeclaration now supports commas at the end of group use declarations
     - Also improves checking and fixing for use statements containing parse errors
@@ -1732,17 +2748,27 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 
 ### Fixed
-- Fixed bug #2029 : Squiz.Scope.MemberVarScope throws fatal error when a property is found in an interface
-    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2047 : PSR12.Classes.ClassInstantiation false positive when instantiating class from array index
-- Fixed bug #2048 : GenericFormatting.MultipleStatementAlignment false positive when assigning values inside an array
-- Fixed bug #2053 : PSR12.Classes.ClassInstantiation incorrectly fix when using member vars and some variable formats
-- Fixed bug #2065 : Generic.ControlStructures.InlineControlStructure fixing fails when inline control structure contains closure
-- Fixed bug #2072 : Squiz.Arrays.ArrayDeclaration throws NoComma error when array value is a shorthand IF statement
-- Fixed bug #2082 : File with "defined() or define()" syntax triggers PSR1.Files.SideEffects.FoundWithSymbols
-- Fixed bug #2095 : PSR2.Namespaces.NamespaceDeclaration does not handle namespaces defined over multiple lines
+- Fixed bug [#2029][sq-2029] : Squiz.Scope.MemberVarScope throws fatal error when a property is found in an interface
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#2047][sq-2047] : PSR12.Classes.ClassInstantiation false positive when instantiating class from array index
+- Fixed bug [#2048][sq-2048] : GenericFormatting.MultipleStatementAlignment false positive when assigning values inside an array
+- Fixed bug [#2053][sq-2053] : PSR12.Classes.ClassInstantiation incorrectly fix when using member vars and some variable formats
+- Fixed bug [#2065][sq-2065] : Generic.ControlStructures.InlineControlStructure fixing fails when inline control structure contains closure
+- Fixed bug [#2072][sq-2072] : Squiz.Arrays.ArrayDeclaration throws NoComma error when array value is a shorthand IF statement
+- Fixed bug [#2082][sq-2082] : File with "defined() or define()" syntax triggers PSR1.Files.SideEffects.FoundWithSymbols
+- Fixed bug [#2095][sq-2095] : PSR2.Namespaces.NamespaceDeclaration does not handle namespaces defined over multiple lines
+
+[sq-2029]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2029
+[sq-2047]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2047
+[sq-2048]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2048
+[sq-2053]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2053
+[sq-2065]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2065
+[sq-2072]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2072
+[sq-2082]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2082
+[sq-2095]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2095
 
 ## [3.3.0] - 2018-06-07
+
 ### Deprecated
 - The Squiz.WhiteSpace.LanguageConstructSpacing sniff has been deprecated and will be removed in version 4
     - The sniff has been moved to the Generic standard, with a new code of Generic.WhiteSpace.LanguageConstructSpacing
@@ -1809,8 +2835,8 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - A new "Closure opening brace placement" metric now shows information for closures
 - Multi-line T_YIELD_FROM statements are now replicated properly for older PHP versions
 - The PSR2 standard no longer produces 2 error messages when the AS keyword in a foreach loop is not lowercase
-- Specifying a path to a non-existent dir when using the --report-[reportType]=/path/to/report CLI option no longer throws an exception
-    - This now prints a readable error message, as it does when using --report-file
+- Specifying a path to a non-existent dir when using the `--report-[reportType]=/path/to/report` CLI option no longer throws an exception
+    - This now prints a readable error message, as it does when using `--report-file`
 - The File::getMethodParamaters() method now includes a type_hint_token array index in the return value
     - Provides the position in the token stack of the first token in the type hint
 - The File::getMethodProperties() method now includes a return_type_token array index in the return value
@@ -1914,44 +2940,69 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - If not set, the sniff will use whatever value is set for the existing 'spacing' property
 
 ### Fixed
-- Fixed bug #1863 : File::findEndOfStatement() not working when passed a scope opener
-- Fixed bug #1876 : PSR2.Namespaces.UseDeclaration not giving error for use statements before the namespace declaration
+- Fixed bug [#1863][sq-1863] : File::findEndOfStatement() not working when passed a scope opener
+- Fixed bug [#1876][sq-1876] : PSR2.Namespaces.UseDeclaration not giving error for use statements before the namespace declaration
     - Adds a new PSR2.Namespaces.UseDeclaration.UseBeforeNamespace error message
-- Fixed bug #1881 : Generic.Arrays.ArrayIndent is indenting sub-arrays incorrectly when comma not used after the last value
-- Fixed bug #1882 : Conditional with missing braces confused by indirect variables
-- Fixed bug #1915 : JS tokenizer fails to tokenize regular expression proceeded by boolean not operator
-- Fixed bug #1920 : Directory exclude pattern improperly excludes files with names that start the same
+- Fixed bug [#1881][sq-1881] : Generic.Arrays.ArrayIndent is indenting sub-arrays incorrectly when comma not used after the last value
+- Fixed bug [#1882][sq-1882] : Conditional with missing braces confused by indirect variables
+- Fixed bug [#1915][sq-1915] : JS tokenizer fails to tokenize regular expression proceeded by boolean not operator
+- Fixed bug [#1920][sq-1920] : Directory exclude pattern improperly excludes files with names that start the same
     - Thanks to [Jeff Puckett][@jpuck] for the patch
-- Fixed bug #1922 : Equal sign alignment check broken when list syntax used before assignment operator
-- Fixed bug #1925 : Generic.Formatting.MultipleStatementAlignment skipping assignments within closures
-- Fixed bug #1931 : Generic opening brace placement sniffs do not correctly support function return types
-- Fixed bug #1932 : Generic.ControlStructures.InlineControlStructure fixer moves new PHPCS annotations
-- Fixed bug #1938 : Generic opening brace placement sniffs incorrectly move PHPCS annotations
+- Fixed bug [#1922][sq-1922] : Equal sign alignment check broken when list syntax used before assignment operator
+- Fixed bug [#1925][sq-1925] : Generic.Formatting.MultipleStatementAlignment skipping assignments within closures
+- Fixed bug [#1931][sq-1931] : Generic opening brace placement sniffs do not correctly support function return types
+- Fixed bug [#1932][sq-1932] : Generic.ControlStructures.InlineControlStructure fixer moves new PHPCS annotations
+- Fixed bug [#1938][sq-1938] : Generic opening brace placement sniffs incorrectly move PHPCS annotations
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #1939 : phpcs:set annotations do not cause the line they are on to be ignored
+- Fixed bug [#1939][sq-1939] : phpcs:set annotations do not cause the line they are on to be ignored
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #1949 : Squiz.PHP.DisallowMultipleAssignments false positive when using namespaces with static assignments
-- Fixed bug #1959 : SquizMultiLineFunctionDeclaration error when param has trailing comment
+- Fixed bug [#1949][sq-1949] : Squiz.PHP.DisallowMultipleAssignments false positive when using namespaces with static assignments
+- Fixed bug [#1959][sq-1959] : SquizMultiLineFunctionDeclaration error when param has trailing comment
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #1963 : Squiz.Scope.MemberVarScope does not work for multiline member declaration
+- Fixed bug [#1963][sq-1963] : Squiz.Scope.MemberVarScope does not work for multiline member declaration
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #1971 : Short array list syntax not correctly tokenized if short array is the first content in a file
-- Fixed bug #1979 : Tokenizer does not change heredoc to nowdoc token if the start tag contains spaces
-- Fixed bug #1982 : Squiz.Arrays.ArrayDeclaration fixer sometimes puts a comma in front of the last array value
-- Fixed bug #1993 : PSR1/PSR2 not reporting or fixing short open tags
-- Fixed bug #1996 : Custom report paths don't work on case-sensitive filesystems
-- Fixed bug #2006 : Squiz.Functions.FunctionDeclarationArgumentSpacing fixer removes comment between parens when no args
+- Fixed bug [#1971][sq-1971] : Short array list syntax not correctly tokenized if short array is the first content in a file
+- Fixed bug [#1979][sq-1979] : Tokenizer does not change heredoc to nowdoc token if the start tag contains spaces
+- Fixed bug [#1982][sq-1982] : Squiz.Arrays.ArrayDeclaration fixer sometimes puts a comma in front of the last array value
+- Fixed bug [#1993][sq-1993] : PSR1/PSR2 not reporting or fixing short open tags
+- Fixed bug [#1996][sq-1996] : Custom report paths don't work on case-sensitive filesystems
+- Fixed bug [#2006][sq-2006] : Squiz.Functions.FunctionDeclarationArgumentSpacing fixer removes comment between parens when no args
     - The SpacingAfterOpenHint error message has been removed
-        - It is replaced by the the existing SpacingAfterOpen message
+        - It is replaced by the existing SpacingAfterOpen message
     - The error message format for the SpacingAfterOpen and SpacingBeforeClose messages has been changed
         - These used to contain 3 pieces of data, but now only contain 2
     - If you have customised the error messages of this sniff, please review your ruleset after upgrading
-- Fixed bug #2018 : Generic.Formatting.MultipleStatementAlignment does see PHP close tag as end of statement block
-    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #2027 : PEAR.NamingConventions.ValidFunctionName error when function name includes double underscore
-    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#2018][sq-2018] : Generic.Formatting.MultipleStatementAlignment does see PHP close tag as end of statement block
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#2027][sq-2027] : PEAR.NamingConventions.ValidFunctionName error when function name includes double underscore
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+
+[sq-1863]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1863
+[sq-1876]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1876
+[sq-1881]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1881
+[sq-1882]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1882
+[sq-1915]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1915
+[sq-1920]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1920
+[sq-1922]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1922
+[sq-1925]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1925
+[sq-1931]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1931
+[sq-1932]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1932
+[sq-1938]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1938
+[sq-1939]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1939
+[sq-1949]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1949
+[sq-1959]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1959
+[sq-1963]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1963
+[sq-1971]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1971
+[sq-1979]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1979
+[sq-1982]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1982
+[sq-1993]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1993
+[sq-1996]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1996
+[sq-2006]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2006
+[sq-2018]: https://github.com/squizlabs/PHP_CodeSniffer/pull/2018
+[sq-2027]: https://github.com/squizlabs/PHP_CodeSniffer/issues/2027
 
 ## [3.2.3] - 2018-02-21
+
 ### Changed
 - The new phpcs: comment syntax can now be prefixed with an at symbol ( @phpcs: )
     - This restores the behaviour of the previous syntax where these comments are ignored by doc generators
@@ -1989,30 +3040,44 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 
 ### Fixed
 - Fixed test suite compatibility with PHPUnit 7
-- Fixed bug #1793 : PSR2 forcing exact indent for function call opening statements
-- Fixed bug #1803 : Squiz.WhiteSpace.ScopeKeywordSpacing removes member var name while fixing if no space after scope keyword
-- Fixed bug #1817 : Blank line not enforced after control structure if comment on same line as closing brace
-- Fixed bug #1827 : A phpcs:enable comment is not tokenized correctly if it is outside a phpcs:disable block
-    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #1828 : Squiz.WhiteSpace.SuperfluousWhiteSpace ignoreBlankLines property ignores whitespace after single line comments
-    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #1840 : When a comment has too many asterisks, phpcbf gives FAILED TO FIX error
-- Fixed bug #1867 : Cant use phpcs:ignore where the next line is HTML
-- Fixed bug #1870 : Invalid warning in multiple assignments alignment with closure or anon class
-- Fixed bug #1890 : Incorrect Squiz.WhiteSpace.ControlStructureSpacing.NoLineAfterClose error between catch and finally statements
-- Fixed bug #1891 : Comment on last USE statement causes false positive for PSR2.Namespaces.UseDeclaration.SpaceAfterLastUse
+- Fixed bug [#1793][sq-1793] : PSR2 forcing exact indent for function call opening statements
+- Fixed bug [#1803][sq-1803] : Squiz.WhiteSpace.ScopeKeywordSpacing removes member var name while fixing if no space after scope keyword
+- Fixed bug [#1817][sq-1817] : Blank line not enforced after control structure if comment on same line as closing brace
+- Fixed bug [#1827][sq-1827] : A phpcs:enable comment is not tokenized correctly if it is outside a phpcs:disable block
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#1828][sq-1828] : Squiz.WhiteSpace.SuperfluousWhiteSpace ignoreBlankLines property ignores whitespace after single line comments
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#1840][sq-1840] : When a comment has too many asterisks, phpcbf gives FAILED TO FIX error
+- Fixed bug [#1867][sq-1867] : Can't use phpcs:ignore where the next line is HTML
+- Fixed bug [#1870][sq-1870] : Invalid warning in multiple assignments alignment with closure or anon class
+- Fixed bug [#1890][sq-1890] : Incorrect Squiz.WhiteSpace.ControlStructureSpacing.NoLineAfterClose error between catch and finally statements
+- Fixed bug [#1891][sq-1891] : Comment on last USE statement causes false positive for PSR2.Namespaces.UseDeclaration.SpaceAfterLastUse
     - Thanks to [Matt Coleman][@iammattcoleman], [Daniel Hensby][@dhensby], and [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #1901 : Fixed PHPCS annotations in multi-line tab-indented comments + not ignoring whole line for phpcs:set
+- Fixed bug [#1901][sq-1901] : Fixed PHPCS annotations in multi-line tab-indented comments + not ignoring whole line for phpcs:set
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 
+[sq-1793]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1793
+[sq-1803]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1803
+[sq-1817]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1817
+[sq-1827]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1827
+[sq-1828]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1828
+[sq-1840]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1840
+[sq-1867]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1867
+[sq-1870]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1870
+[sq-1890]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1890
+[sq-1891]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1891
+[sq-1901]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1901
+
 ## [3.2.2] - 2017-12-20
+
 ### Changed
 - Disabled STDIN detection on Windows
     - This fixes a problem with IDE plugins (e.g., PHPStorm) hanging on Windows
 
 ## [3.2.1] - 2017-12-18
+
 ### Changed
-- Empty diffs are no longer followed by a newline character (request #1781)
+- Empty diffs are no longer followed by a newline character (request [#1781][sq-1781])
 - Generic.Functions.OpeningFunctionBraceKernighanRitchie no longer complains when the open brace is followed by a close tag
     - This makes the sniff more useful when used in templates
     - Thanks to [Joseph Zidell][@josephzidell] for the patch
@@ -2020,9 +3085,13 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 ### Fixed
 - Fixed problems with some scripts and plugins waiting for STDIN
     - This was a notable problem with IDE plugins (e.g., PHPStorm) and build systems
-- Fixed bug #1782 : Incorrect detection of operator in ternary + anonymous function
+- Fixed bug [#1782][sq-1782] : Incorrect detection of operator in ternary + anonymous function
+
+[sq-1781]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1781
+[sq-1782]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1782
 
 ## [3.2.0] - 2017-12-13
+
 ### Deprecated
 - This release deprecates the @codingStandards comment syntax used for sending commands to PHP_CodeSniffer
     - The existing syntax will continue to work in all version 3 releases, but will be removed in version 4
@@ -2043,7 +3112,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
         - phpcs:set has the token T_PHPCS_SET
 
 ### Changed
-- The phpcs:disable and phpcs:ignore comments can now selectively ignore specific sniffs (request #604)
+- The phpcs:disable and phpcs:ignore comments can now selectively ignore specific sniffs (request [#604][sq-604])
     - E.g., phpcs:disable Generic.Commenting.Todo.Found for a specific message
     - E.g., phpcs:disable Generic.Commenting.Todo for a whole sniff
     - E.g., phpcs:disable Generic.Commenting for a whole category of sniffs
@@ -2065,7 +3134,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 - Added phpcs.xsd to allow validation of ruleset XML files
     - Thanks to [Renaat De Muynck][@renaatdemuynck] for the contribution
-- File paths specified using --stdin-path can now point to fake file locations (request #1488)
+- File paths specified using --stdin-path can now point to fake file locations (request [#1488][sq-1488])
     - Previously, STDIN files using fake file paths were excluded from checking
 - Setting an empty basepath (--basepath=) on the CLI will now clear a basepath set directly in a ruleset
     - Thanks to [Xaver Loppenstedt][@xalopp] for the patch
@@ -2126,65 +3195,98 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 
 ### Fixed
-- Fixed bug #1462 : Error processing cyrillic strings in Tokenizer
-- Fixed bug #1573 : Squiz.WhiteSpace.LanguageConstructSpacing does not properly check for tabs and newlines
+- Fixed bug [#1462][sq-1462] : Error processing cyrillic strings in Tokenizer
+- Fixed bug [#1573][sq-1573] : Squiz.WhiteSpace.LanguageConstructSpacing does not properly check for tabs and newlines
     - Thanks to [Michał Bundyra][@michalbundyra] for the patch
-- Fixed bug #1590 : InlineControlStructure CBF issue while adding braces to an if thats returning a nested function
-- Fixed bug #1718 : Unclosed strings at EOF sometimes tokenized as T_WHITESPACE by the JS tokenizer
-- Fixed bug #1731 : Directory exclusions do not work as expected when a single file name is passed to phpcs
-- Fixed bug #1737 : Squiz.CSS.EmptyStyleDefinition sees comment as style definition and fails to report error
-- Fixed bug #1746 : Very large reports can sometimes become garbled when using the parallel option
-- Fixed bug #1747 : Squiz.Scope.StaticThisUsage incorrectly looking inside closures
-- Fixed bug #1757 : Unknown type hint "object" in Squiz.Commenting.FunctionComment
-- Fixed bug #1758 : PHPCS gets stuck creating file list when processing circular symlinks
-- Fixed bug #1761 : Generic.WhiteSpace.ScopeIndent error on multi-line function call with static closure argument
-- Fixed bug #1762 : Generic.WhiteSpace.Disallow[Space/Tab]Indent not inspecting content before open tag
-    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #1769 : Custom "define" function triggers a warning about declaring new symbols
-- Fixed bug #1776 : Squiz.Scope.StaticThisUsage incorrectly looking inside anon classes
-- Fixed bug #1777 : Generic.WhiteSpace.ScopeIndent incorrect indent errors when self called function proceeded by comment
+- Fixed bug [#1590][sq-1590] : InlineControlStructure CBF issue while adding braces to an if that's returning a nested function
+- Fixed bug [#1718][sq-1718] : Unclosed strings at EOF sometimes tokenized as T_WHITESPACE by the JS tokenizer
+- Fixed bug [#1731][sq-1731] : Directory exclusions do not work as expected when a single file name is passed to phpcs
+- Fixed bug [#1737][sq-1737] : Squiz.CSS.EmptyStyleDefinition sees comment as style definition and fails to report error
+- Fixed bug [#1746][sq-1746] : Very large reports can sometimes become garbled when using the parallel option
+- Fixed bug [#1747][sq-1747] : Squiz.Scope.StaticThisUsage incorrectly looking inside closures
+- Fixed bug [#1757][sq-1757] : Unknown type hint "object" in Squiz.Commenting.FunctionComment
+- Fixed bug [#1758][sq-1758] : PHPCS gets stuck creating file list when processing circular symlinks
+- Fixed bug [#1761][sq-1761] : Generic.WhiteSpace.ScopeIndent error on multi-line function call with static closure argument
+- Fixed bug [#1762][sq-1762] : `Generic.WhiteSpace.Disallow[Space/Tab]Indent` not inspecting content before open tag
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#1769][sq-1769] : Custom "define" function triggers a warning about declaring new symbols
+- Fixed bug [#1776][sq-1776] : Squiz.Scope.StaticThisUsage incorrectly looking inside anon classes
+- Fixed bug [#1777][sq-1777] : Generic.WhiteSpace.ScopeIndent incorrect indent errors when self called function proceeded by comment
+
+[sq-604]: https://github.com/squizlabs/PHP_CodeSniffer/issues/604
+[sq-1462]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1462
+[sq-1488]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1488
+[sq-1573]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1573
+[sq-1590]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1590
+[sq-1718]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1718
+[sq-1731]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1731
+[sq-1737]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1737
+[sq-1746]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1746
+[sq-1747]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1747
+[sq-1757]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1757
+[sq-1758]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1758
+[sq-1761]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1761
+[sq-1762]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1762
+[sq-1769]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1769
+[sq-1776]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1776
+[sq-1777]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1777
 
 ## [3.1.1] - 2017-10-17
+
 ### Changed
 - Restored preference of non-dist files over dist files for phpcs.xml and phpcs.xml.dist
     - The order that the files are searched is now: .phpcs.xml, phpcs.xml, .phpcs.xml.dist, phpcs.xml.dist
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 - Progress output now correctly shows skipped files
-- Progress output now shows 100% when the file list has finished processing (request #1697)
+- Progress output now shows 100% when the file list has finished processing (request [#1697][sq-1697])
 - Stopped some IDEs complaining about testing class aliases
     - Thanks to [Vytautas Stankus][@svycka] for the patch
 - Squiz.Commenting.InlineComment incorrectly identified comment blocks in some cases, muting some errors
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 
 ### Fixed
-- Fixed bug #1512 : PEAR.Functions.FunctionCallSignature enforces spaces when no arguments if required spaces is not 0
-- Fixed bug #1522 : Squiz Arrays.ArrayDeclaration and Strings.ConcatenationSpacing fixers causing parse errors with here/  nowdocs
-- Fixed bug #1570 : Squiz.Arrays.ArrayDeclaration fixer removes comments between array keyword and open parentheses
-- Fixed bug #1604 : File::isReference has problems with some bitwise operators and class property references
-    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #1645 : Squiz.Commenting.InlineComment will fail to fix comments at the end of the file
-    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #1656 : Using the --sniffs argument has a problem with case sensitivity
-- Fixed bug #1657 : Uninitialized string offset: 0 when sniffing CSS
-- Fixed bug #1669 : Temporary expression proceeded by curly brace is detected as function call
-- Fixed bug #1681 : Huge arrays are super slow to scan with Squiz.Arrays.ArrayDeclaration sniff
-- Fixed bug #1694 : Squiz.Arrays.ArrayBracketSpacing is removing some comments during fixing
-    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #1702 : Generic.WhiteSpaceDisallowSpaceIndent fixer bug when line only contains superfluous whitespace
+- Fixed bug [#1512][sq-1512] : PEAR.Functions.FunctionCallSignature enforces spaces when no arguments if required spaces is not 0
+- Fixed bug [#1522][sq-1522] : Squiz Arrays.ArrayDeclaration and Strings.ConcatenationSpacing fixers causing parse errors with here/nowdocs
+- Fixed bug [#1570][sq-1570] : Squiz.Arrays.ArrayDeclaration fixer removes comments between array keyword and open parentheses
+- Fixed bug [#1604][sq-1604] : File::isReference has problems with some bitwise operators and class property references
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#1645][sq-1645] : Squiz.Commenting.InlineComment will fail to fix comments at the end of the file
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#1656][sq-1656] : Using the --sniffs argument has a problem with case sensitivity
+- Fixed bug [#1657][sq-1657] : Uninitialized string offset: 0 when sniffing CSS
+- Fixed bug [#1669][sq-1669] : Temporary expression proceeded by curly brace is detected as function call
+- Fixed bug [#1681][sq-1681] : Huge arrays are super slow to scan with Squiz.Arrays.ArrayDeclaration sniff
+- Fixed bug [#1694][sq-1694] : Squiz.Arrays.ArrayBracketSpacing is removing some comments during fixing
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#1702][sq-1702] : Generic.WhiteSpaceDisallowSpaceIndent fixer bug when line only contains superfluous whitespace
+
+[sq-1512]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1512
+[sq-1522]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1522
+[sq-1570]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1570
+[sq-1604]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1604
+[sq-1645]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1645
+[sq-1656]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1656
+[sq-1657]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1657
+[sq-1669]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1669
+[sq-1681]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1681
+[sq-1694]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1694
+[sq-1697]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1697
+[sq-1702]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1702
 
 ## [3.1.0] - 2017-09-20
+
 ### Changed
 - This release includes a change to support newer versions of PHPUnit (versions 4, 5, and 6 are now supported)
     - The custom PHP_CodeSniffer test runner now requires a bootstrap file
     - Developers with custom standards using the PHP_CodeSniffer test runner will need to do one of the following:
-      - run your unit tests from the PHP_CodeSniffer root dir so the bootstrap file is included
-      - specify the PHP_CodeSniffer bootstrap file on the command line: phpunit --bootstrap=/path/to/phpcs/tests/bootstrap.php
-      - require the PHP_CodeSniffer bootstrap file from your own bootstrap file
+        - run your unit tests from the PHP_CodeSniffer root dir so the bootstrap file is included
+        - specify the PHP_CodeSniffer bootstrap file on the command line: `phpunit --bootstrap=/path/to/phpcs/tests/bootstrap.php`
+        - require the PHP_CodeSniffer bootstrap file from your own bootstrap file
     - If you don't run PHP_CodeSniffer unit tests, this change will not affect you
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 - A phpcs.xml or phpcs.xml.dist file now takes precedence over the default_standard config setting
     - Thanks to [Björn Fischer][@Fischer-Bjoern] for the patch
-- Both phpcs.xml and phpcs.xml.dist files can now be prefixed with a dot (request #1566)
+- Both phpcs.xml and phpcs.xml.dist files can now be prefixed with a dot (request [#1566][sq-1566])
     - The order that the files are searched is: .phpcs.xml, .phpcs.xml.dist, phpcs.xml, phpcs.xml.dist
 - The autoloader will now search for files during unit tests runs from the same locations as during normal phpcs runs
     - Allows for easier unit testing of custom standards that use helper classes or custom namespaces
@@ -2206,7 +3308,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Added Generic.Files.OneObjectStructurePerFile sniff to ensure there is a single class/interface/trait per file
     - Thanks to [Mponos George][@gmponos] for the contribution
 - Function call sniffs now check variable function names and self/static object creation
-    - Specific sniffs are Generic.Functions.FunctionCallArgumentSpacing, PEAR.Functions.FunctionCallSignature, and   PSR2.Methods.FunctionCallSignature
+    - Specific sniffs are Generic.Functions.FunctionCallArgumentSpacing, PEAR.Functions.FunctionCallSignature, and PSR2.Methods.FunctionCallSignature
     - Thanks to [Michał Bundyra][@michalbundyra] for the patch
 - Generic.Files.LineLength can now be configured to ignore all comment lines, no matter their length
     - Set the ignoreComments property to TRUE (default is FALSE) in your ruleset.xml file to enable this
@@ -2235,22 +3337,34 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Martin Hujer][@mhujer] for the patch
 
 ### Fixed
-- Fixed bug #1550 : Squiz.Commenting.FunctionComment false positive when function contains closure
-- Fixed bug #1577 : Generic.InlineControlStructureSniff breaks with a comment between body and condition in do while loops
-- Fixed bug #1581 : Sniffs not loaded when one-standard directories are being registered in installed_paths
-- Fixed bug #1591 : Autoloader failing to load arbitrary files when installed_paths only set via a custom ruleset
-- Fixed bug #1605 : Squiz.WhiteSpace.OperatorSpacing false positive on unary minus after comment
-    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #1615 : Uncaught RuntimeException when phpcbf fails to fix files
-- Fixed bug #1637 : Generic.WhiteSpaceScopeIndent closure argument indenting incorrect with multi-line strings
-- Fixed bug #1638 : Squiz.WhiteSpace.ScopeClosingBrace closure argument indenting incorrect with multi-line strings
-- Fixed bug #1640 : Squiz.Strings.DoubleQuoteUsage replaces tabs with spaces when fixing
-    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#1550][sq-1550] : Squiz.Commenting.FunctionComment false positive when function contains closure
+- Fixed bug [#1577][sq-1577] : Generic.InlineControlStructureSniff breaks with a comment between body and condition in do while loops
+- Fixed bug [#1581][sq-1581] : Sniffs not loaded when one-standard directories are being registered in installed_paths
+- Fixed bug [#1591][sq-1591] : Autoloader failing to load arbitrary files when installed_paths only set via a custom ruleset
+- Fixed bug [#1605][sq-1605] : Squiz.WhiteSpace.OperatorSpacing false positive on unary minus after comment
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#1615][sq-1615] : Uncaught RuntimeException when phpcbf fails to fix files
+- Fixed bug [#1637][sq-1637] : Generic.WhiteSpaceScopeIndent closure argument indenting incorrect with multi-line strings
+- Fixed bug [#1638][sq-1638] : Squiz.WhiteSpace.ScopeClosingBrace closure argument indenting incorrect with multi-line strings
+- Fixed bug [#1640][sq-1640] : Squiz.Strings.DoubleQuoteUsage replaces tabs with spaces when fixing
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+
+[sq-1550]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1550
+[sq-1566]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1566
+[sq-1577]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1577
+[sq-1581]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1581
+[sq-1591]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1591
+[sq-1605]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1605
+[sq-1615]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1615
+[sq-1637]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1637
+[sq-1638]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1638
+[sq-1640]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1640
 
 ## [3.0.2] - 2017-07-18
+
 ### Changed
 - The code report now gracefully handles tokenizer exceptions
-- The phpcs and phpcbf scripts and now the only places that exit() in the code
+- The phpcs and phpcbf scripts are now the only places that exit() in the code
     - This allows for easier usage of core PHPCS functions from external scripts
     - If you are calling Runner::runPHPCS() or Runner::runPHPCBF() directly, you will get back the full range of exit codes
     - If not, catch the new DeepExitException to get the error message ($e->getMessage()) and exit code ($e->getCode());
@@ -2265,22 +3379,34 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 ### Fixed
 - Fixed a problem where the source report was not printing the correct number of errors found
 - Fixed a problem where the --cache=/path/to/cachefile CLI argument was not working
-- Fixed bug #1465 : Generic.WhiteSpace.ScopeIndent reports incorrect errors when indenting double arrows in short arrays
-- Fixed bug #1478 : Indentation in fallthrough CASE that contains a closure
-- Fixed bug #1497 : Fatal error if composer prepend-autoloader is set to false
+- Fixed bug [#1465][sq-1465] : Generic.WhiteSpace.ScopeIndent reports incorrect errors when indenting double arrows in short arrays
+- Fixed bug [#1478][sq-1478] : Indentation in fallthrough CASE that contains a closure
+- Fixed bug [#1497][sq-1497] : Fatal error if composer prepend-autoloader is set to false
     - Thanks to [Kunal Mehta][@legoktm] for the patch
-- Fixed bug #1503 : Alternative control structure syntax not always recognized as scoped
-- Fixed bug #1523 : Fatal error when using the --suffix argument
+- Fixed bug [#1503][sq-1503] : Alternative control structure syntax not always recognized as scoped
+- Fixed bug [#1523][sq-1523] : Fatal error when using the --suffix argument
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #1526 : Use of basepath setting can stop PHPCBF being able to write fixed files
-- Fixed bug #1530 : Generic.WhiteSpace.ScopeIndent can increase indent too much for lines within code blocks
-- Fixed bug #1547 : Wrong token type for backslash in use function
+- Fixed bug [#1526][sq-1526] : Use of basepath setting can stop PHPCBF being able to write fixed files
+- Fixed bug [#1530][sq-1530] : Generic.WhiteSpace.ScopeIndent can increase indent too much for lines within code blocks
+- Fixed bug [#1547][sq-1547] : Wrong token type for backslash in use function
     - Thanks to [Michał Bundyra][@michalbundyra] for the patch
-- Fixed bug #1549 : Squiz.PHP.EmbeddedPhp fixer conflict with // comment before PHP close tag
+- Fixed bug [#1549][sq-1549] : Squiz.PHP.EmbeddedPhp fixer conflict with // comment before PHP close tag
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #1560 : Squiz.Commenting.FunctionComment fatal error when fixing additional param comment lines that have no indent
+- Fixed bug [#1560][sq-1560] : Squiz.Commenting.FunctionComment fatal error when fixing additional param comment lines that have no indent
+
+[sq-1465]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1465
+[sq-1478]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1478
+[sq-1497]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1497
+[sq-1503]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1503
+[sq-1523]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1523
+[sq-1526]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1526
+[sq-1530]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1530
+[sq-1547]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1547
+[sq-1549]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1549
+[sq-1560]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1560
 
 ## [3.0.1] - 2017-06-14
+
 ### Security
 - This release contains a fix for a security advisory related to the improper handling of a shell command
     - A properly crafted filename would allow for arbitrary code execution when using the --filter=gitmodified command line option
@@ -2297,7 +3423,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - PHPCS now stops looking for a phpcs.xml file as soon as one is found, favoring the closest one to the current dir
 - Added missing help text for the --stdin-path CLI option to --help
 - Re-added missing help text for the --file-list and --bootstrap CLI options to --help
-- Runner::runPHPCS() and Runner::runPHPCBF() now return an exit code instead of exiting directly (request #1484)
+- Runner::runPHPCS() and Runner::runPHPCBF() now return an exit code instead of exiting directly (request [#1484][sq-1484])
 - The Squiz standard now enforces short array syntax by default
 - The autoloader is now working correctly with classes created with class_alias()
 - The autoloader will now search for files inside all directories in the installed_paths config var
@@ -2318,34 +3444,50 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 ### Fixed
 - Fixed a problem where excluding a message from a custom standard's own sniff would exclude the whole sniff
     - This caused some PSR2 errors to be under-reported
-- Fixed bug #1442 : T_NULLABLE detection not working for nullable parameters and return type hints in some cases
-- Fixed bug #1447 : Running the unit tests with a phpunit config file breaks the test suite
+- Fixed bug [#1442][sq-1442] : T_NULLABLE detection not working for nullable parameters and return type hints in some cases
+- Fixed bug [#1447][sq-1447] : Running the unit tests with a PHPUnit config file breaks the test suite
     - Unknown arguments were not being handled correctly, but are now stored in $config->unknown
-- Fixed bug #1449 : Generic.Classes.OpeningBraceSameLine doesn't detect comment before opening brace
+- Fixed bug [#1449][sq-1449] : Generic.Classes.OpeningBraceSameLine doesn't detect comment before opening brace
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #1450 : Coding standard located under an installed_path with the same directory name throws an error
+- Fixed bug [#1450][sq-1450] : Coding standard located under an installed_path with the same directory name throws an error
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #1451 : Sniff exclusions/restrictions dont work with custom sniffs unless they use the PHP_CodeSniffer NS
-- Fixed bug #1454 : Squiz.WhiteSpace.OperatorSpacing is not checking spacing on either side of a short ternary operator
+- Fixed bug [#1451][sq-1451] : Sniff exclusions/restrictions don't work with custom sniffs unless they use the PHP_CodeSniffer NS
+- Fixed bug [#1454][sq-1454] : Squiz.WhiteSpace.OperatorSpacing is not checking spacing on either side of a short ternary operator
     - Thanks to [Mponos George][@gmponos] for the patch
-- Fixed bug #1495 : Setting an invalid installed path breaks all commands
-- Fixed bug #1496 : Squiz.Strings.DoubleQuoteUsage not unescaping dollar sign when fixing
+- Fixed bug [#1495][sq-1495] : Setting an invalid installed path breaks all commands
+- Fixed bug [#1496][sq-1496] : Squiz.Strings.DoubleQuoteUsage not unescaping dollar sign when fixing
     - Thanks to [Michał Bundyra][@michalbundyra] for the patch
-- Fixed bug #1501 : Interactive mode is broken
-- Fixed bug #1504 : PSR2.Namespaces.UseDeclaration hangs fixing use statement with no trailing code
+- Fixed bug [#1501][sq-1501] : Interactive mode is broken
+- Fixed bug [#1504][sq-1504] : PSR2.Namespaces.UseDeclaration hangs fixing use statement with no trailing code
+
+[sq-1447]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1447
+[sq-1449]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1449
+[sq-1450]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1450
+[sq-1451]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1451
+[sq-1454]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1454
+[sq-1484]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1484
+[sq-1495]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1495
+[sq-1496]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1496
+[sq-1501]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1501
+[sq-1504]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1504
 
 ## [2.9.1] - 2017-05-22
+
 ### Fixed
-- Fixed bug #1442 : T_NULLABLE detection not working for nullable parameters and return type hints in some cases
-- Fixed bug #1448 : Generic.Classes.OpeningBraceSameLine doesn't detect comment before opening brace
+- Fixed bug [#1442][sq-1442] : T_NULLABLE detection not working for nullable parameters and return type hints in some cases
+- Fixed bug [#1448][sq-1448] : Generic.Classes.OpeningBraceSameLine doesn't detect comment before opening brace
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 
+[sq-1442]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1442
+[sq-1448]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1448
+
 ## [3.0.0] - 2017-05-04
+
 ### Changed
-- Added an --ignore-annotations command line argument to ignore all @codingStandards annotations in code comments (request #811)
+- Added an --ignore-annotations command line argument to ignore all @codingStandards annotations in code comments (request [#811][sq-811])
 - This allows you to force errors to be shown that would otherwise be ignored by code comments
-    - Also stop files being able to change sniff properties mid way through processing
-- An error is now reported if no sniffs were registered to be run (request #1129)
+    - Also stop files being able to change sniff properties midway through processing
+- An error is now reported if no sniffs were registered to be run (request [#1129][sq-1129])
 - The autoloader will now search for files inside the directory of any loaded coding standard
     - This allows autoloading of any file inside a custom coding standard without manually requiring them
     - Ensure your namespace begins with your coding standard's directory name and follows PSR-4
@@ -2360,10 +3502,15 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Includes all changes from the 2.9.0 release
 
 ### Fixed
-- Fixed bug #834 : PSR2.ControlStructures.SwitchDeclaration does not handle if branches with returns
+- Fixed bug [#834][sq-834] : PSR2.ControlStructures.SwitchDeclaration does not handle if branches with returns
     - Thanks to [Fabian Wiget][@fabacino] for the patch
 
+[sq-811]: https://github.com/squizlabs/PHP_CodeSniffer/issues/811
+[sq-834]: https://github.com/squizlabs/PHP_CodeSniffer/issues/834
+[sq-1129]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1129
+
 ## [3.0.0RC4] - 2017-03-02
+
 ### Security
 - This release contains a fix for a security advisory related to the improper handling of shell commands
     - Uses of shell_exec() and exec() were not escaping filenames and configuration settings in most cases
@@ -2393,20 +3540,24 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Includes all changes from the 2.8.1 release
 
 ### Fixed
-- Fixed bug #1333 : The new autoloader breaks some frameworks with custom autoloaders
-- Fixed bug #1334 : Undefined offset when explaining standard with custom sniffs
+- Fixed bug [#1333][sq-1333] : The new autoloader breaks some frameworks with custom autoloaders
+- Fixed bug [#1334][sq-1334] : Undefined offset when explaining standard with custom sniffs
+
+[sq-1333]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1333
+[sq-1334]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1334
 
 ## [3.0.0RC3] - 2017-02-02
+
 ### Changed
 - Added support for ES6 class declarations
     - Previously, these class were tokenized as JS objects but are now tokenized as normal T_CLASS structures
 - Added support for ES6 method declarations, where the "function" keyword is not used
-    - Previously, these methods were tokenized as JS objects (fixes bug #1251)
+    - Previously, these methods were tokenized as JS objects (fixes bug [#1251][sq-1251])
     - The name of the ES6 method is now assigned the T_FUNCTION keyword and treated like a normal function
-    - Custom sniffs that support JS and listen for T_FUNCTION tokens can't assume the token represents the word   "function"
+    - Custom sniffs that support JS and listen for T_FUNCTION tokens can't assume the token represents the word "function"
     - Check the contents of the token first, or use $phpcsFile->getDeclarationName($stackPtr) if you just want its name
     - There is no change for custom sniffs that only check PHP code
-- PHPCBF exit codes have been changed so they are now more useful (request #1270)
+- PHPCBF exit codes have been changed so they are now more useful (request [#1270][sq-1270])
     - Exit code 0 is now used to indicate that no fixable errors were found, and so nothing was fixed
     - Exit code 1 is now used to indicate that all fixable errors were fixed correctly
     - Exit code 2 is now used to indicate that PHPCBF failed to fix some of the fixable errors it found
@@ -2418,26 +3569,37 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Fixed an issue where excluding a file using a @codingStandardsIgnoreFile comment would produce errors
     - For PHPCS, it would show empty files being processed
     - For PHPCBF, it would produce a PHP error
-- Fixed bug #1233 : Can't set config data inside ruleset.xml file
-- Fixed bug #1241 : CodeSniffer.conf not working with 3.x PHAR file
+- Fixed bug [#1233][sq-1233] : Can't set config data inside ruleset.xml file
+- Fixed bug [#1241][sq-1241] : CodeSniffer.conf not working with 3.x PHAR file
+
+[sq-1233]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1233
+[sq-1241]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1241
+[sq-1251]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1251
+[sq-1270]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1270
 
 ## [3.0.0RC2] - 2016-11-30
+
 ### Changed
 - Made the Runner class easier to use with wrapper scripts
-- Full usage information is no longer printed when a usage error is encountered (request #1186)
+- Full usage information is no longer printed when a usage error is encountered (request [#1186][sq-1186])
     - Makes it a lot easier to find and read the error message that was printed
 - Includes all changes from the 2.7.1 release
 
 ### Fixed
 - Fixed an undefined var name error that could be produced while running PHPCBF
-- Fixed bug #1167 : 3.0.0RC1 PHAR does not work with PEAR standard
-- Fixed bug #1208 : Excluding files doesn't work when using STDIN with a filename specified
+- Fixed bug [#1167][sq-1167] : 3.0.0RC1 PHAR does not work with PEAR standard
+- Fixed bug [#1208][sq-1208] : Excluding files doesn't work when using STDIN with a filename specified
+
+[sq-1167]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1167
+[sq-1186]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1186
+[sq-1208]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1208
 
 ## [3.0.0RC1] - 2016-09-02
+
 ### Changed
 - Progress output now shows E and W in green when a file has fixable errors or warnings
     - Only supported if colors are enabled
-- PHPCBF no longer produces verbose output by default (request #699)
+- PHPCBF no longer produces verbose output by default (request [#699][sq-699])
     - Use the -v command line argument to show verbose fixing output
     - Use the -q command line argument to disable verbose information if enabled by default
 - PHPBF now prints a summary report after fixing files
@@ -2452,37 +3614,40 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 ### Fixed
 - Fixed shell error appearing on some systems when trying to find executable paths
 
+[sq-699]: https://github.com/squizlabs/PHP_CodeSniffer/issues/699
+
 ## [3.0.0a1] - 2016-07-20
+
 ### Changed
 - Min PHP version increased from 5.1.2 to 5.4.0
-- Added optional caching of results between runs (request #530)
+- Added optional caching of results between runs (request [#530][sq-530])
     - Enable the cache by using the --cache command line argument
     - If you want the cache file written somewhere specific, use --cache=/path/to/cacheFile
     - Use the command "phpcs --config-set cache true" to turn caching on by default
     - Use the --no-cache command line argument to disable caching if it is being turned on automatically
-- Add support for checking file in parallel (request #421)
+- Add support for checking file in parallel (request [#421][sq-421])
     - Tell PHPCS how many files to check at once using the --parallel command line argument
     - To check 100 files at once, using --parallel=100
     - To disable parallel checking if it is being turned on automatically, use --parallel=1
     - Requires PHP to be compiled with the PCNTL package
-- The default encoding has been changed from iso-8859-1 to utf-8 (request #760)
+- The default encoding has been changed from iso-8859-1 to utf-8 (request [#760][sq-760])
     - The --encoding command line argument still works, but you no longer have to set it to process files as utf-8
     - If encoding is being set to utf-8 in a ruleset or on the CLI, it can be safely removed
     - If the iconv PHP extension is not installed, standard non-multibyte aware functions will be used
-- Added a new "code" report type to show a code snippet for each error (request #419)
+- Added a new "code" report type to show a code snippet for each error (request [#419][sq-419])
     - The line containing the error is printed, along with 2 lines above and below it to show context
     - The location of the errors is underlined in the code snippet if you also use --colors
     - Use --report=code to generate this report
 - Added support for custom filtering of the file list
     - Developers can write their own filter classes to perform custom filtering of the list before the run starts
-    - Use the command line arg --filter=/path/to/filter.php to specify a filter to use
+    - Use the command line arg `--filter=/path/to/filter.php` to specify a filter to use
     - Extend \PHP_CodeSniffer\Filters\Filter to also support the core PHPCS extension and path filtering
     - Extend \PHP_CodeSniffer\Filters\ExactMatch to get the core filtering and the ability to use blacklists and whitelists
     - The included \PHP_CodeSniffer\Filters\GitModified filter is a good example of an ExactMatch filter
 - Added support for only checking files that have been locally modified or added in a git repo
     - Use --filter=gitmodified to check these files
     - You still need to give PHPCS a list of files or directories in which to check
-- Added automatic discovery of executable paths (request #571)
+- Added automatic discovery of executable paths (request [#571][sq-571])
     - Thanks to [Sergei Morozov][@morozov] for the patch
 - You must now pass "-" on the command line to have PHPCS wait for STDIN
     - E.g., phpcs --standard=PSR2 -
@@ -2492,14 +3657,14 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - This should stop bugs inside sniffs causing infinite loops
     - Also stops invalid reports being produced as errors don't print to the screen directly
 - Sniff codes are no longer optional
-    - If a sniff throws and error or a warning, it must specify an internal code for that message
+    - If a sniff throws an error or a warning, it must specify an internal code for that message
 - The installed_paths config setting can now point directly to a standard
     - Previously, it had to always point to the directory in which the standard lives
 - Multiple reports can now be specified using the --report command line argument
     - Report types are separated by commas
     - E.g., --report=full,summary,info
     - Previously, you had to use one argument for each report such as --report=full --report=summary --report=info
-- You can now set the severity, message type, and exclude patterns for and entire sniff, category, or standard
+- You can now set the severity, message type, and exclude patterns for an entire sniff, category, or standard
     - Previously, this was only available for a single message
 - You can now include a single sniff code in a ruleset instead of having to include an entire sniff
     - Including a sniff code will automatically exclude all other messages from that sniff
@@ -2507,17 +3672,17 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - PHPCBF no longer uses patch
     - Files are now always overwritten
     - The --no-patch option has been removed
-- Added a --basepath option to strip a directory from the front of file paths in output (request #470)
+- Added a --basepath option to strip a directory from the front of file paths in output (request [#470][sq-470])
     - The basepath is absolute or relative to the current directory
     - E.g., to output paths relative to current dir in reports, use --basepath=.
-- Ignore rules are now checked when using STDIN (request #733)
-- Added an include-pattern tag to rulesets to include a sniff for specific files and folders only (request #656)
+- Ignore rules are now checked when using STDIN (request [#733][sq-733])
+- Added an include-pattern tag to rulesets to include a sniff for specific files and folders only (request [#656][sq-656])
     - This is the exact opposite of the exclude-pattern tag
     - This option is only usable within sniffs, not globally like exclude-patterns are
 - Added a new -m option to stop error messages from being recorded, which saves a lot of memory
     - PHPCBF always uses this setting to reduce memory as it never outputs error messages
     - Setting the $recordErrors member var inside custom report classes is no longer supported (use -m instead)
-- Exit code 2 is now used to indicate fixable errors were found (request #930)
+- Exit code 2 is now used to indicate fixable errors were found (request [#930][sq-930])
     - Exit code 3 is now used for general script execution errors
     - Exit code 1 is used to indicate that coding standard errors were found, but none are fixable
     - Exit code 0 is unchanged and continues to mean no coding standard errors found
@@ -2529,7 +3694,18 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - The included SVN pre-commit hook has been removed
     - Hooks for version control systems will no longer be maintained within the PHPCS project
 
+[sq-419]: https://github.com/squizlabs/PHP_CodeSniffer/issues/419
+[sq-421]: https://github.com/squizlabs/PHP_CodeSniffer/issues/421
+[sq-470]: https://github.com/squizlabs/PHP_CodeSniffer/issues/470
+[sq-530]: https://github.com/squizlabs/PHP_CodeSniffer/issues/530
+[sq-571]: https://github.com/squizlabs/PHP_CodeSniffer/pull/571
+[sq-656]: https://github.com/squizlabs/PHP_CodeSniffer/issues/656
+[sq-733]: https://github.com/squizlabs/PHP_CodeSniffer/issues/733
+[sq-760]: https://github.com/squizlabs/PHP_CodeSniffer/issues/760
+[sq-930]: https://github.com/squizlabs/PHP_CodeSniffer/issues/930
+
 ## [2.9.0] - 2017-05-04
+
 ### Changed
 - Added Generic.Debug.ESLint sniff to run ESLint over JS files and report errors
     - Set eslint path using: phpcs --config-set eslint_path /path/to/eslint
@@ -2545,7 +3721,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 - PEAR.Commenting.ClassComment now supports checking of traits as well as classes and interfaces
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Squiz.Commenting.FunctionCommentThrowTag now supports re-throwing exceptions (request #946)
+- Squiz.Commenting.FunctionCommentThrowTag now supports re-throwing exceptions (request [#946][sq-946])
     - Thanks to [Samuel Levy][@samlev] for the patch
 - Squiz.PHP.DisallowMultipleAssignments now ignores PHP4-style member var assignments
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
@@ -2556,22 +3732,36 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Added missing error codes for a couple of sniffs so they can now be customised as normal
 
 ### Fixed
-- Fixed bug #1266 : PEAR.WhiteSpace.ScopeClosingBrace can throw an error while fixing mixed PHP/HTML
-- Fixed bug #1364 : Yield From values are not recognised as returned values in Squiz FunctionComment sniff
-- Fixed bug #1373 : Error in tab expansion results in white-space of incorrect size
+- Fixed bug [#1266][sq-1266] : PEAR.WhiteSpace.ScopeClosingBrace can throw an error while fixing mixed PHP/HTML
+- Fixed bug [#1364][sq-1364] : Yield From values are not recognised as returned values in Squiz FunctionComment sniff
+- Fixed bug [#1373][sq-1373] : Error in tab expansion results in white-space of incorrect size
     - Thanks to [Mark Clements][@MarkMaldaba] for the patch
-- Fixed bug #1381 : Tokenizer: dereferencing incorrectly identified as short array
-- Fixed bug #1387 : Squiz.ControlStructures.ControlSignature does not handle alt syntax when checking space after closing   brace
-- Fixed bug #1392 : Scope indent calculated incorrectly when using array destructuring
-- Fixed bug #1394 : integer type hints appearing as TypeHintMissing instead of ScalarTypeHintMissing
+- Fixed bug [#1381][sq-1381] : Tokenizer: dereferencing incorrectly identified as short array
+- Fixed bug [#1387][sq-1387] : Squiz.ControlStructures.ControlSignature does not handle alt syntax when checking space after closing brace
+- Fixed bug [#1392][sq-1392] : Scope indent calculated incorrectly when using array destructuring
+- Fixed bug [#1394][sq-1394] : integer type hints appearing as TypeHintMissing instead of ScalarTypeHintMissing
     - PHP 7 type hints were also being shown when run under PHP 5 in some cases
-- Fixed bug #1405 : Squiz.WhiteSpace.ScopeClosingBrace fails to fix closing brace within indented PHP tags
-- Fixed bug #1421 : Ternaries used in constant scalar expression for param default misidentified by tokenizer
-- Fixed bug #1431 : PHPCBF can't fix short open tags when they are not followed by a space
+- Fixed bug [#1405][sq-1405] : Squiz.WhiteSpace.ScopeClosingBrace fails to fix closing brace within indented PHP tags
+- Fixed bug [#1421][sq-1421] : Ternaries used in constant scalar expression for param default misidentified by tokenizer
+- Fixed bug [#1431][sq-1431] : PHPCBF can't fix short open tags when they are not followed by a space
     - Thanks to [Gonçalo Queirós][@ghunti] for the patch
-- Fixed bug #1432 : PHPCBF can make invalid fixes to inline JS control structures that make use of JS objects
+- Fixed bug [#1432][sq-1432] : PHPCBF can make invalid fixes to inline JS control structures that make use of JS objects
+
+[sq-946]: https://github.com/squizlabs/PHP_CodeSniffer/pull/946
+[sq-1266]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1266
+[sq-1364]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1364
+[sq-1373]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1373
+[sq-1381]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1381
+[sq-1387]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1387
+[sq-1392]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1392
+[sq-1394]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1394
+[sq-1405]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1405
+[sq-1421]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1421
+[sq-1431]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1431
+[sq-1432]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1432
 
 ## [2.8.1] - 2017-03-02
+
 ### Security
 - This release contains a fix for a security advisory related to the improper handling of shell commands
     - Uses of shell_exec() and exec() were not escaping filenames and configuration settings in most cases
@@ -2607,17 +3797,25 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Squiz.ControlStructures.InlineIfDeclaration is now able to fix the spacing errors it reports
 
 ### Fixed
-- Fixed bug #1340 : STDIN file contents not being populated in some cases
+- Fixed bug [#1340][sq-1340] : STDIN file contents not being populated in some cases
     - Thanks to [David Biňovec][@david-binda] for the patch
-- Fixed bug #1344 : PEAR.Functions.FunctionCallSignatureSniff throws error for blank comment lines
-- Fixed bug #1347 : PSR2.Methods.FunctionCallSignature strips some comments during fixing
+- Fixed bug [#1344][sq-1344] : PEAR.Functions.FunctionCallSignatureSniff throws error for blank comment lines
+- Fixed bug [#1347][sq-1347] : PSR2.Methods.FunctionCallSignature strips some comments during fixing
     - Thanks to [Algirdas Gurevicius][@uniquexor] for the patch
-- Fixed bug #1349 : Squiz.Strings.DoubleQuoteUsage.NotRequired message is badly formatted when string contains a CR newline char
+- Fixed bug [#1349][sq-1349] : Squiz.Strings.DoubleQuoteUsage.NotRequired message is badly formatted when string contains a CR newline char
     - Thanks to [Algirdas Gurevicius][@uniquexor] for the patch
-- Fixed bug #1350 : Invalid Squiz.Formatting.OperatorBracket error when using namespaces
-- Fixed bug #1369 : Empty line in multi-line function declaration cause infinite loop
+- Fixed bug [#1350][sq-1350] : Invalid Squiz.Formatting.OperatorBracket error when using namespaces
+- Fixed bug [#1369][sq-1369] : Empty line in multi-line function declaration cause infinite loop
+
+[sq-1340]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1340
+[sq-1344]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1344
+[sq-1347]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1347
+[sq-1349]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1349
+[sq-1350]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1350
+[sq-1369]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1369
 
 ## [2.8.0] - 2017-02-02
+
 ### Changed
 - The Internal.NoCodeFound error is no longer generated for content sourced from STDIN
     - This should stop some Git hooks generating errors because PHPCS is trying to process the refs passed on STDIN
@@ -2631,13 +3829,13 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 - The getMethodParameters() method now supports closures
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Added more guard code for JS files with syntax errors (request #1271 and request #1272)
-- Added more guard code for CSS files with syntax errors (request #1304)
+- Added more guard code for JS files with syntax errors (request [#1271][sq-1271] and request [#1272][sq-1272])
+- Added more guard code for CSS files with syntax errors (request [#1304][sq-1304])
 - PEAR.Commenting.FunctionComment fixers now correctly handle multi-line param comments
 - AbstractVariableSniff now supports anonymous classes
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 - Generic.NamingConventions.ConstructorName and PEAR.NamingConventions.ValidVariable now support anonymous classes
-- Generic.NamingConventions.CamelCapsFunctionName and PEAR.NamingConventions.ValidFunctionName now support anonymous   classes
+- Generic.NamingConventions.CamelCapsFunctionName and PEAR.NamingConventions.ValidFunctionName now support anonymous classes
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 - Generic.CodeAnalysis.UnusedFunctionParameter and PEAR.Functions.ValidDefaultValue now support closures
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
@@ -2652,32 +3850,55 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Algirdas Gurevicius][@uniquexor] for the patch
 
 ### Fixed
-- Fixed bug #1230 : JS tokeniser incorrectly tokenises bitwise shifts as comparison
+- Fixed bug [#1230][sq-1230] : JS tokeniser incorrectly tokenises bitwise shifts as comparison
     - Thanks to [Ryan McCue][@rmccue] for the patch
-- Fixed bug #1237 : Uninitialized string offset in PHP Tokenizer on PHP 5.2
-- Fixed bug #1239 : Warning when static method name is 'default'
-- Fixed bug #1240 : False positive for function names starting with triple underscore
+- Fixed bug [#1237][sq-1237] : Uninitialized string offset in PHP Tokenizer on PHP 5.2
+- Fixed bug [#1239][sq-1239] : Warning when static method name is 'default'
+- Fixed bug [#1240][sq-1240] : False positive for function names starting with triple underscore
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #1245 : SELF is not recognised as T_SELF token in: return new self
-- Fixed bug #1246 : A mix of USE statements with and without braces can cause the tokenizer to mismatch brace tokens
+- Fixed bug [#1245][sq-1245] : SELF is not recognised as T_SELF token in: return new self
+- Fixed bug [#1246][sq-1246] : A mix of USE statements with and without braces can cause the tokenizer to mismatch brace tokens
     - Thanks to [Michał Bundyra][@michalbundyra] for the patch
-- Fixed bug #1249 : GitBlame report requires a .git directory
-- Fixed bug #1252 : Squiz.Strings.ConcatenationSpacing fix creates syntax error when joining a number to a string
-- Fixed bug #1253 : Generic.ControlStructures.InlineControlStructure fix creates syntax error fixing if-try/catch
-- Fixed bug #1255 : Inconsistent indentation check results when ELSE on new line
-- Fixed bug #1257 : Double dash in CSS class name can lead to "Named colours are forbidden" false positives
-- Fixed bug #1260 : Syntax errors not being shown when error_prepend_string is set
-    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Fixed bug #1264 : Array return type hint is sometimes detected as T_ARRAY_HINT instead of T_RETURN_TYPE
+- Fixed bug [#1249][sq-1249] : GitBlame report requires a .git directory
+- Fixed bug [#1252][sq-1252] : Squiz.Strings.ConcatenationSpacing fix creates syntax error when joining a number to a string
+- Fixed bug [#1253][sq-1253] : Generic.ControlStructures.InlineControlStructure fix creates syntax error fixing if-try/catch
+- Fixed bug [#1255][sq-1255] : Inconsistent indentation check results when ELSE on new line
+- Fixed bug [#1257][sq-1257] : Double dash in CSS class name can lead to "Named colours are forbidden" false positives
+- Fixed bug [#1260][sq-1260] : Syntax errors not being shown when error_prepend_string is set
+    - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
+- Fixed bug [#1264][sq-1264] : Array return type hint is sometimes detected as T_ARRAY_HINT instead of T_RETURN_TYPE
     - Thanks to [Jaroslav Hanslík][@kukulich] for the patch
-- Fixed bug #1265 : ES6 arrow function raises unexpected operator spacing errors
-- Fixed bug #1267 : Fixer incorrectly handles filepaths with repeated dir names
+- Fixed bug [#1265][sq-1265] : ES6 arrow function raises unexpected operator spacing errors
+- Fixed bug [#1267][sq-1267] : Fixer incorrectly handles filepaths with repeated dir names
     - Thanks to [Sergey Ovchinnikov][@orx0r] for the patch
-- Fixed bug #1276 : Commenting.FunctionComment.InvalidReturnVoid conditional issue with anonymous classes
-- Fixed bug #1277 : Squiz.PHP.DisallowMultipleAssignments.Found error when var assignment is on the same line as an   open tag
-- Fixed bug #1284 : Squiz.Arrays.ArrayBracketSpacing.SpaceBeforeBracket false positive match for short list syntax
+- Fixed bug [#1276][sq-1276] : Commenting.FunctionComment.InvalidReturnVoid conditional issue with anonymous classes
+- Fixed bug [#1277][sq-1277] : Squiz.PHP.DisallowMultipleAssignments.Found error when var assignment is on the same line as an open tag
+- Fixed bug [#1284][sq-1284] : Squiz.Arrays.ArrayBracketSpacing.SpaceBeforeBracket false positive match for short list syntax
+
+[sq-1230]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1230
+[sq-1237]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1237
+[sq-1239]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1239
+[sq-1240]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1240
+[sq-1245]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1245
+[sq-1246]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1246
+[sq-1249]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1249
+[sq-1252]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1252
+[sq-1253]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1253
+[sq-1255]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1255
+[sq-1257]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1257
+[sq-1260]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1260
+[sq-1264]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1264
+[sq-1265]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1265
+[sq-1267]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1267
+[sq-1271]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1271
+[sq-1272]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1272
+[sq-1276]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1276
+[sq-1277]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1277
+[sq-1284]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1284
+[sq-1304]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1304
 
 ## [2.7.1] - 2016-11-30
+
 ### Changed
 - Squiz.ControlStructures.ControlSignature.SpaceAfterCloseParenthesis fix now removes unnecessary whitespace
 - Squiz.Formatting.OperatorBracket no longer errors for negative array indexes used within a function call
@@ -2693,34 +3914,52 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Sergey][@sserbin] for the patch
 
 ### Fixed
-- Fixed bug #1135 : PEAR.ControlStructures.MultiLineCondition.CloseBracketNewLine not detected if preceded by multiline function call
-- Fixed bug #1138 : PEAR.ControlStructures.MultiLineCondition.Alignment not detected if closing brace is first token on line
-- Fixed bug #1141 : Sniffs that check EOF newlines don't detect newlines properly when the last token is a doc block
-- Fixed bug #1150 : Squiz.Strings.EchoedStrings does not properly fix bracketed statements
-- Fixed bug #1156 : Generic.Formatting.DisallowMultipleStatements errors when multiple short echo tags are used on the same line
+- Fixed bug [#1135][sq-1135] : PEAR.ControlStructures.MultiLineCondition.CloseBracketNewLine not detected if preceded by multiline function call
+- Fixed bug [#1138][sq-1138] : PEAR.ControlStructures.MultiLineCondition.Alignment not detected if closing brace is first token on line
+- Fixed bug [#1141][sq-1141] : Sniffs that check EOF newlines don't detect newlines properly when the last token is a doc block
+- Fixed bug [#1150][sq-1150] : Squiz.Strings.EchoedStrings does not properly fix bracketed statements
+- Fixed bug [#1156][sq-1156] : Generic.Formatting.DisallowMultipleStatements errors when multiple short echo tags are used on the same line
     - Thanks to [Nikola Kovacs][@nkovacs] for the patch
-- Fixed bug #1161 : Absolute report path is treated like a relative path if it also exists within the current directory
-- Fixed bug #1170 : Javascript regular expression literal not recognized after comparison operator
-- Fixed bug #1180 : Class constant named FUNCTION is incorrectly tokenized
-- Fixed bug #1181 : Squiz.Operators.IncrementDecrementUsage.NoBrackets false positive when incrementing properties
+- Fixed bug [#1161][sq-1161] : Absolute report path is treated like a relative path if it also exists within the current directory
+- Fixed bug [#1170][sq-1170] : Javascript regular expression literal not recognized after comparison operator
+- Fixed bug [#1180][sq-1180] : Class constant named FUNCTION is incorrectly tokenized
+- Fixed bug [#1181][sq-1181] : Squiz.Operators.IncrementDecrementUsage.NoBrackets false positive when incrementing properties
     - Thanks to [Jürgen Henge-Ernst][@hernst42] for the patch
-- Fixed bug #1188 : Generic.WhiteSpace.ScopeIndent issues with inline HTML and multi-line function signatures
-- Fixed bug #1190 : phpcbf on if/else with trailing comment generates erroneous code
-- Fixed bug #1191 : Javascript sniffer fails with function called "Function"
-- Fixed bug #1203 : Inconsistent behavior of PHP_CodeSniffer_File::findEndOfStatement
-- Fixed bug #1218 : CASE conditions using class constants named NAMESPACE/INTERFACE/TRAIT etc are incorrectly tokenized
-- Fixed bug #1221 : Indented function call with multiple closure arguments can cause scope indent error
-- Fixed bug #1224 : PHPCBF fails to fix code with heredoc/nowdoc as first argument to a function
+- Fixed bug [#1188][sq-1188] : Generic.WhiteSpace.ScopeIndent issues with inline HTML and multi-line function signatures
+- Fixed bug [#1190][sq-1190] : phpcbf on if/else with trailing comment generates erroneous code
+- Fixed bug [#1191][sq-1191] : Javascript sniffer fails with function called "Function"
+- Fixed bug [#1203][sq-1203] : Inconsistent behavior of PHP_CodeSniffer_File::findEndOfStatement
+- Fixed bug [#1218][sq-1218] : CASE conditions using class constants named NAMESPACE/INTERFACE/TRAIT etc are incorrectly tokenized
+- Fixed bug [#1221][sq-1221] : Indented function call with multiple closure arguments can cause scope indent error
+- Fixed bug [#1224][sq-1224] : PHPCBF fails to fix code with heredoc/nowdoc as first argument to a function
+
+[sq-1135]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1135
+[sq-1138]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1138
+[sq-1141]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1141
+[sq-1150]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1150
+[sq-1156]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1156
+[sq-1161]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1161
+[sq-1170]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1170
+[sq-1180]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1180
+[sq-1181]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1181
+[sq-1188]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1188
+[sq-1190]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1190
+[sq-1191]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1191
+[sq-1203]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1203
+[sq-1218]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1218
+[sq-1221]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1221
+[sq-1224]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1224
 
 ## [2.7.0] - 2016-09-02
+
 ### Changed
 - Added --file-list command line argument to allow a list of files and directories to be specified in an external file
-    - Useful is you have a generated list of files to check that would be too long for the command line
+    - Useful if you have a generated list of files to check that would be too long for the command line
     - File and directory paths are listed one per line
     - Usage is: phpcs --file-list=/path/to/file-list ...
     - Thanks to [Blotzu][@andrei-propertyguru] for the patch
 - Values set using @codingStandardsChangeSetting comments can now contain spaces
-- Sniff unit tests can now specify a list of test files instead of letting the runner pick them (request #1078)
+- Sniff unit tests can now specify a list of test files instead of letting the runner pick them (request [#1078][sq-1078])
     - Useful if a sniff needs to exclude files based on the environment, or is checking filenames
     - Override the new getTestFiles() method to specify your own list of test files
 - Generic.Functions.OpeningFunctionBraceKernighanRitchie now ignores spacing for function return types
@@ -2745,7 +3984,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
 - Added Generic.PHP.DisallowAlternativePHPTags to ban the use of alternate PHP tags
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Squiz.WhiteSpace.LanguageConstructSpacing no longer checks for spaces if parenthesis are being used (request #1062)
+- Squiz.WhiteSpace.LanguageConstructSpacing no longer checks for spaces if parenthesis are being used (request [#1062][sq-1062])
     - Makes this sniff more compatible with those that check parenthesis spacing of function calls
 - Squiz.WhiteSpace.ObjectOperatorSpacing now has a setting to ignore newline characters around object operators
     - Default remains FALSE, so newlines are not allowed
@@ -2759,115 +3998,175 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Walt Sorensen][@photodude] for the patch
 - PHPCBF is now able to fix Generic.PHP.DisallowShortOpenTag
     - Thanks to [Juliette Reinders Folmer][@jrfnl] for the patch
-- Improved the formatting of the end brace when auto fixing InlineControlStructure errors (request #1121)
-- Generic.Functions.OpeningFunctionBraceKernighanRitchie.BraceOnNewLine fix no longer leaves blank line after brace (request #1085)
+- Improved the formatting of the end brace when auto fixing InlineControlStructure errors (request [#1121][sq-1121])
+- Generic.Functions.OpeningFunctionBraceKernighanRitchie.BraceOnNewLine fix no longer leaves blank line after brace (request [#1085][sq-1085])
 - Generic UpperCaseConstantNameSniff now allows lowercase namespaces in constant definitions
-  - Thanks to [Daniel Schniepp][@dschniepp] for the patch
+    - Thanks to [Daniel Schniepp][@dschniepp] for the patch
 - Squiz DoubleQuoteUsageSniff is now more tolerant of syntax errors caused by mismatched string tokens
 - A few sniffs that produce errors based on the current PHP version can now be told to run using a specific PHP version
-    - Set the php_version config var using --config-set, --runtime-set, or in a ruleset to specify a specific PHP version
-    - The format of the PHP version is the same as the PHP_VERSION_ID constant (e.g., 50403 for version 5.4.3)
+    - Set the `php_version` config var using `--config-set`, `--runtime-set`, or in a ruleset to specify a specific PHP version
+    - The format of the PHP version is the same as the `PHP_VERSION_ID` constant (e.g., 50403 for version 5.4.3)
     - Supported sniffs are Generic.PHP.DisallowAlternativePHPTags, PSR1.Classes.ClassDeclaration, Squiz.Commenting.FunctionComment
     - Thanks to [Finlay Beaton][@ofbeaton] for the patch
 
 ### Fixed
-- Fixed bug #985  : Duplicate class definition detection generates false-positives in media queries
+- Fixed bug [#985][sq-985] : Duplicate class definition detection generates false-positives in media queries
     - Thanks to [Raphael Horber][@rhorber] for the patch
-- Fixed bug #1014 : Squiz VariableCommentSniff doesn't always detect a missing comment
-- Fixed bug #1066 : Undefined index: quiet in CLI.php during unit test run with -v command line arg
-- Fixed bug #1072 : Squiz.SelfMemberReference.NotUsed not detected if leading namespace separator is used
-- Fixed bug #1089 : Rulesets cannot be loaded if the path contains urlencoded characters
-- Fixed bug #1091 : PEAR and Squiz FunctionComment sniffs throw errors for some invalid @param line formats
-- Fixed bug #1092 : PEAR.Functions.ValidDefaultValue should not flag type hinted methods with a NULL default argument
-- Fixed bug #1095 : Generic LineEndings sniff replaces tabs with spaces with --tab-width is set
-- Fixed bug #1096 : Squiz FunctionDeclarationArgumentSpacing gives incorrect error/fix when variadic operator is followed by a space
-- Fixed bug #1099 : Group use declarations are incorrectly fixed by the PSR2 standard
+- Fixed bug [#1014][sq-1014] : Squiz VariableCommentSniff doesn't always detect a missing comment
+- Fixed bug [#1066][sq-1066] : Undefined index: quiet in `CLI.php` during unit test run with `-v` command line arg
+- Fixed bug [#1072][sq-1072] : Squiz.SelfMemberReference.NotUsed not detected if leading namespace separator is used
+- Fixed bug [#1089][sq-1089] : Rulesets cannot be loaded if the path contains urlencoded characters
+- Fixed bug [#1091][sq-1091] : PEAR and Squiz FunctionComment sniffs throw errors for some invalid @param line formats
+- Fixed bug [#1092][sq-1092] : PEAR.Functions.ValidDefaultValue should not flag type hinted methods with a NULL default argument
+- Fixed bug [#1095][sq-1095] : Generic LineEndings sniff replaces tabs with spaces with --tab-width is set
+- Fixed bug [#1096][sq-1096] : Squiz FunctionDeclarationArgumentSpacing gives incorrect error/fix when variadic operator is followed by a space
+- Fixed bug [#1099][sq-1099] : Group use declarations are incorrectly fixed by the PSR2 standard
     - Thanks to [Jason McCreary][@jasonmccreary] for the patch
-- Fixed bug #1101 : Incorrect indent errors when breaking out of PHP inside an IF statement
-- Fixed bug #1102 : Squiz.Formatting.OperatorBracket.MissingBrackets faulty bracketing fix
-- Fixed bug #1109 : Wrong scope indent reported in anonymous class
-- Fixed bug #1112 : File docblock not recognized when require_once follows it
-- Fixed bug #1120 : InlineControlStructureSniff does not handle auto-fixing for control structures that make function calls
-- Fixed bug #1124 : Squiz.Operators.ComparisonOperatorUsage does not detect bracketed conditions for inline IF statements
+- Fixed bug [#1101][sq-1101] : Incorrect indent errors when breaking out of PHP inside an IF statement
+- Fixed bug [#1102][sq-1102] : Squiz.Formatting.OperatorBracket.MissingBrackets faulty bracketing fix
+- Fixed bug [#1109][sq-1109] : Wrong scope indent reported in anonymous class
+- Fixed bug [#1112][sq-1112] : File docblock not recognized when require_once follows it
+- Fixed bug [#1120][sq-1120] : InlineControlStructureSniff does not handle auto-fixing for control structures that make function calls
+- Fixed bug [#1124][sq-1124] : Squiz.Operators.ComparisonOperatorUsage does not detect bracketed conditions for inline IF statements
     - Thanks to [Raphael Horber][@rhorber] for the patch
 
+[sq-985]: https://github.com/squizlabs/PHP_CodeSniffer/issues/985
+[sq-1014]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1014
+[sq-1062]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1062
+[sq-1066]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1066
+[sq-1072]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1072
+[sq-1078]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1078
+[sq-1085]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1085
+[sq-1089]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1089
+[sq-1091]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1091
+[sq-1092]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1092
+[sq-1095]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1095
+[sq-1096]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1096
+[sq-1099]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1099
+[sq-1101]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1101
+[sq-1102]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1102
+[sq-1109]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1109
+[sq-1112]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1112
+[sq-1120]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1120
+[sq-1121]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1121
+[sq-1124]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1124
+
 ## [2.6.2] - 2016-07-14
+
 ### Changed
-- Added a new --exclude CLI argument to exclude a list of sniffs from checking and fixing (request #904)
+- Added a new --exclude CLI argument to exclude a list of sniffs from checking and fixing (request [#904][sq-904])
     - Accepts the same sniff codes as the --sniffs command line argument, but provides the opposite functionality
-- Added a new -q command line argument to disable progress and verbose information from being printed (request #969)
+- Added a new -q command line argument to disable progress and verbose information from being printed (request [#969][sq-969])
     - Useful if a coding standard hard-codes progress or verbose output but you want PHPCS to be quiet
     - Use the command "phpcs --config-set quiet true" to turn quiet mode on by default
-- Generic LineLength sniff no longer errors for comments that cannot be broken out onto a new line (request #766)
+- Generic LineLength sniff no longer errors for comments that cannot be broken out onto a new line (request [#766][sq-766])
     - A typical case is a comment that contains a very long URL
-    - The comment is ignored if putting the URL on a indented new comment line would be longer than the allowed length
+    - The comment is ignored if putting the URL on an indented new comment line would be longer than the allowed length
 - Settings extensions in a ruleset no longer causes PHP notices during unit testing
     - Thanks to [Klaus Purer][@klausi] for the patch
 - Version control reports now show which errors are fixable if you are showing sources
-- Added a new sniff to enforce a single space after a NOT operator (request #1051)
+- Added a new sniff to enforce a single space after a NOT operator (request [#1051][sq-1051])
     - Include in a ruleset using the code Generic.Formatting.SpaceAfterNot
-- The Squiz.Commenting.BlockComment sniff now supports tabs for indenting comment lines (request #1056)
+- The Squiz.Commenting.BlockComment sniff now supports tabs for indenting comment lines (request [#1056][sq-1056])
 
 ### Fixed
-- Fixed bug #790 : Incorrect missing @throws error in methods that use closures
-- Fixed bug #908 : PSR2 standard is not checking that closing brace is on line following the body
-- Fixed bug #945 : Incorrect indent behavior using deep-nested function and arrays
-- Fixed bug #961 : Two anonymous functions passed as function/method arguments cause indentation false positive
-- Fixed bug #1005 : Using global composer vendor autoload breaks PHP lowercase built-in function sniff
+- Fixed bug [#790][sq-790] : Incorrect missing @throws error in methods that use closures
+- Fixed bug [#908][sq-908] : PSR2 standard is not checking that closing brace is on line following the body
+- Fixed bug [#945][sq-945] : Incorrect indent behavior using deep-nested function and arrays
+- Fixed bug [#961][sq-961] : Two anonymous functions passed as function/method arguments cause indentation false positive
+- Fixed bug [#1005][sq-1005] : Using global composer vendor autoload breaks PHP lowercase built-in function sniff
     - Thanks to [Michael Butler][@michaelbutler] for the patch
-- Fixed bug #1007 : Squiz Unreachable code detection is not working properly with a closure inside a case
-- Fixed bug #1023 : PSR2.Classes.ClassDeclaration fails if class extends base class and "implements" is on trailing line
-- Fixed bug #1026 : Arrays in comma delimited class properties cause ScopeIndent to increase indent
-- Fixed bug #1028 : Squiz ArrayDeclaration incorrectly fixes multi-line array where end bracket is not on a new line
-- Fixed bug #1034 : Squiz FunctionDeclarationArgumentSpacing gives incorrect error when first arg is a variadic
-- Fixed bug #1036 : Adjacent assignments aligned analysis statement wrong
-- Fixed bug #1049 : Version control reports can show notices when the report width is very small
-- Fixed bug #21050 : PEAR MultiLineCondition sniff suppresses errors on last condition line
+- Fixed bug [#1007][sq-1007] : Squiz Unreachable code detection is not working properly with a closure inside a case
+- Fixed bug [#1023][sq-1023] : PSR2.Classes.ClassDeclaration fails if class extends base class and "implements" is on trailing line
+- Fixed bug [#1026][sq-1026] : Arrays in comma delimited class properties cause ScopeIndent to increase indent
+- Fixed bug [#1028][sq-1028] : Squiz ArrayDeclaration incorrectly fixes multi-line array where end bracket is not on a new line
+- Fixed bug [#1034][sq-1034] : Squiz FunctionDeclarationArgumentSpacing gives incorrect error when first arg is a variadic
+- Fixed bug [#1036][sq-1036] : Adjacent assignments aligned analysis statement wrong
+- Fixed bug [#1049][sq-1049] : Version control reports can show notices when the report width is very small
+- Fixed bug [#21050][pear-21050] : PEAR MultiLineCondition sniff suppresses errors on last condition line
+
+[sq-766]: https://github.com/squizlabs/PHP_CodeSniffer/issues/766
+[sq-790]: https://github.com/squizlabs/PHP_CodeSniffer/issues/790
+[sq-904]: https://github.com/squizlabs/PHP_CodeSniffer/issues/904
+[sq-908]: https://github.com/squizlabs/PHP_CodeSniffer/issues/908
+[sq-945]: https://github.com/squizlabs/PHP_CodeSniffer/issues/945
+[sq-961]: https://github.com/squizlabs/PHP_CodeSniffer/issues/961
+[sq-969]: https://github.com/squizlabs/PHP_CodeSniffer/issues/969
+[sq-1005]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1005
+[sq-1007]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1007
+[sq-1023]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1023
+[sq-1026]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1026
+[sq-1028]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1028
+[sq-1034]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1034
+[sq-1036]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1036
+[sq-1049]: https://github.com/squizlabs/PHP_CodeSniffer/pull/1049
+[sq-1051]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1051
+[sq-1056]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1056
+[pear-21050]: https://pear.php.net/bugs/bug.php?id=21050
 
 ## [2.6.1] - 2016-05-31
+
 ### Changed
 - The PHP-supplied T_COALESCE token has been replicated for PHP versions before 7.0
 - Function return types of self, parent and callable are now tokenized as T_RETURN_TYPE
     - Thanks to [Jaroslav Hanslík][@kukulich] for the patch
 - The default_standard config setting now allows multiple standards to be listed, like on the command line
     - Thanks to [Michael Mayer][@schnittstabil] for the patch
-- Installations done via composer now only include the composer autoloader for PHP 5.3.2+ (request #942)
+- Installations done via composer now only include the composer autoloader for PHP 5.3.2+ (request [#942][sq-942])
 - Added a rollbackChangeset() method to the Fixer class to purposely rollback the active changeset
 
 ### Fixed
-- Fixed bug #940 : Auto-fixing issue encountered with inconsistent use of braces
-- Fixed bug #943 : Squiz.PHP.InnerFunctions.NotAllowed reported in anonymous classes
-- Fixed bug #944 : PHP warning when running the latest phar
-- Fixed bug #951 : InlineIfDeclaration: invalid error produced with UTF-8 string
-- Fixed bug #957 : Operator spacing sniff errors when plus is used as part of a number
+- Fixed bug [#940][sq-940] : Auto-fixing issue encountered with inconsistent use of braces
+- Fixed bug [#943][sq-943] : Squiz.PHP.InnerFunctions.NotAllowed reported in anonymous classes
+- Fixed bug [#944][sq-944] : PHP warning when running the latest phar
+- Fixed bug [#951][sq-951] : InlineIfDeclaration: invalid error produced with UTF-8 string
+- Fixed bug [#957][sq-957] : Operator spacing sniff errors when plus is used as part of a number
     - Thanks to [Klaus Purer][@klausi] for the patch
-- Fixed bug #959 : Call-time pass-by-reference false positive if there is a square bracket before the ampersand
+- Fixed bug [#959][sq-959] : Call-time pass-by-reference false positive if there is a square bracket before the ampersand
     - Thanks to [Konstantin Leboev][@realmfoo] for the patch
-- Fixed bug #962 : Null coalescing operator (??) not detected as a token
+- Fixed bug [#962][sq-962] : Null coalescing operator (??) not detected as a token
     - Thanks to [Joel Posti][@joelposti] for the patch
-- Fixed bug #973 : Anonymous class declaration and PSR1.Files.SideEffects.FoundWithSymbols
-- Fixed bug #974 : Error when file ends with "function"
-- Fixed bug #979 : Anonymous function with return type hint is not refactored as expected
-- Fixed bug #983 : Squiz.WhiteSpace.MemberVarSpacing.AfterComment fails to fix error when comment is not a docblock
-- Fixed bug #1010 : Squiz NonExecutableCode sniff does not detect boolean OR
+- Fixed bug [#973][sq-973] : Anonymous class declaration and PSR1.Files.SideEffects.FoundWithSymbols
+- Fixed bug [#974][sq-974] : Error when file ends with "function"
+- Fixed bug [#979][sq-979] : Anonymous function with return type hint is not refactored as expected
+- Fixed bug [#983][sq-983] : Squiz.WhiteSpace.MemberVarSpacing.AfterComment fails to fix error when comment is not a docblock
+- Fixed bug [#1010][sq-1010] : Squiz NonExecutableCode sniff does not detect boolean OR
     - Thanks to [Derek Henderson][@2shediac] for the patch
-- Fixed bug #1015 : The Squiz.Commenting.FunctionComment sniff doesn't allow description in @return tag
+- Fixed bug [#1015][sq-1015] : The Squiz.Commenting.FunctionComment sniff doesn't allow description in @return tag
     - Thanks to [Alexander Obuhovich][@aik099] for the patch
-- Fixed bug #1022 : Duplicate spaces after opening bracket error with PSR2 standard
-- Fixed bug #1025 : Syntax error in JS file can cause undefined index for parenthesis_closer
+- Fixed bug [#1022][sq-1022] : Duplicate spaces after opening bracket error with PSR2 standard
+- Fixed bug [#1025][sq-1025] : Syntax error in JS file can cause undefined index for parenthesis_closer
+
+[sq-940]: https://github.com/squizlabs/PHP_CodeSniffer/issues/940
+[sq-942]: https://github.com/squizlabs/PHP_CodeSniffer/issues/942
+[sq-943]: https://github.com/squizlabs/PHP_CodeSniffer/issues/943
+[sq-944]: https://github.com/squizlabs/PHP_CodeSniffer/issues/944
+[sq-951]: https://github.com/squizlabs/PHP_CodeSniffer/issues/951
+[sq-957]: https://github.com/squizlabs/PHP_CodeSniffer/pull/957
+[sq-959]: https://github.com/squizlabs/PHP_CodeSniffer/issues/959
+[sq-962]: https://github.com/squizlabs/PHP_CodeSniffer/issues/962
+[sq-973]: https://github.com/squizlabs/PHP_CodeSniffer/issues/973
+[sq-974]: https://github.com/squizlabs/PHP_CodeSniffer/issues/974
+[sq-979]: https://github.com/squizlabs/PHP_CodeSniffer/issues/979
+[sq-983]: https://github.com/squizlabs/PHP_CodeSniffer/issues/983
+[sq-1010]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1010
+[sq-1015]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1015
+[sq-1022]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1022
+[sq-1025]: https://github.com/squizlabs/PHP_CodeSniffer/issues/1025
 
 ## [2.6.0] - 2016-04-04
+
 ### Changed
-- Paths used when setting CLI arguments inside ruleset.xml files are now relative to the ruleset location (request #847)
+- Paths used when setting CLI arguments inside ruleset.xml files are now relative to the ruleset location (request [#847][sq-847])
     - This change only applies to paths within ARG tags, used to set CLI arguments
     - Previously, the paths were relative to the directory PHPCS was being run from
     - Absolute paths are still allowed and work the same way they always have
     - This change allows ruleset.xml files to be more portable
 - Content passed via STDIN will now be processed even if files are specified on the command line or in a ruleset
-- When passing content via STDIN, you can now specify the file path to use on the command line (request #934)
+- When passing content via STDIN, you can now specify the file path to use on the command line (request [#934][sq-934])
     - This allows sniffs that check file paths to work correctly
     - This is the same functionality provided by the phpcs_input_file line, except it is available on the command line
-- Files processed with custom tokenizers will no longer be skipped if they appear minified (request #877)
+- Files processed with custom tokenizers will no longer be skipped if they appear minified (request [#877][sq-877])
     - If the custom tokenizer wants minified files skipped, it can set a $skipMinified member var to TRUE
     - See the included JS and CSS tokenizers for an example
 - Config vars set in ruleset.xml files are now processed earlier, allowing them to be used during sniff registration
@@ -2875,15 +4174,15 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Pieter Frenssen][@pfrenssen] for the patch
 - Improved detection of regular expressions in the JS tokenizer
 - Generic PHP Syntax sniff now uses PHP_BINARY (if available) to determine the path to PHP if no other path is available
-    - You can still manually set php_path to use a specific binary for testing
+    - You can still manually set `php_path` to use a specific binary for testing
     - Thanks to [Andrew Berry][@deviantintegral] for the patch
 - The PHP-supplied T_POW_EQUAL token has been replicated for PHP versions before 5.6
-- Added support for PHP7 use group declarations (request #878)
+- Added support for PHP7 use group declarations (request [#878][sq-878])
     - New tokens T_OPEN_USE_GROUP and T_CLOSE_USE_GROUP are assigned to the open and close curly braces
-- Generic ScopeIndent sniff now reports errors for every line that needs the indent changed (request #903)
+- Generic ScopeIndent sniff now reports errors for every line that needs the indent changed (request [#903][sq-903])
     - Previously, it ignored lines that were indented correctly in the context of their block
     - This change produces more technically accurate error messages, but is much more verbose
-- The PSR2 and Squiz standards now allow multi-line default values in function declarations (request #542)
+- The PSR2 and Squiz standards now allow multi-line default values in function declarations (request [#542][sq-542])
     - Previously, these would automatically make the function a multi-line declaration
 - Squiz InlineCommentSniff now allows docblocks on require(_once) and include(_once) statements
     - Thanks to [Gary Jones][@GaryJones] for the patch
@@ -2895,33 +4194,58 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Renamed Squiz.CSS.Opacity.SpacingAfterPoint to Squiz.CSS.Opacity.DecimalPrecision
     - Please update your ruleset if you are referencing this error code directly
 - Fixed PHP tokenizer problem that caused an infinite loop when checking a comment with specific content
-- Generic Disallow Space and Tab indent sniffs now detect and fix indents inside embedded HTML chunks (request #882)
+- Generic Disallow Space and Tab indent sniffs now detect and fix indents inside embedded HTML chunks (request [#882][sq-882])
 - Squiz CSS IndentationSniff no longer assumes the class opening brace is at the end of a line
 - Squiz FunctionCommentThrowTagSniff now ignores non-docblock comments
 - Squiz ComparisonOperatorUsageSniff now allows conditions like while(true)
 - PEAR FunctionCallSignatureSniff (and the Squiz and PSR2 sniffs that use it) now correctly check the first argument
-    - Further fix for bug #698
-
-### Fixed
-- Fixed bug #791 : codingStandardsChangeSetting settings not working with namespaces
-- Fixed bug #872 : Incorrect detection of blank lines between CSS class names
-- Fixed bug #879 : Generic InlineControlStructureSniff can create parse error when case/if/elseif/else have mixed brace and braceless definitions
-- Fixed bug #883 : PSR2 is not checking for blank lines at the start and end of control structures
-- Fixed bug #884 : Incorrect indentation notice for anonymous classes
-- Fixed bug #887 : Using curly braces for a shared CASE/DEFAULT statement can generate an error in PSR2 SwitchDeclaration
-- Fixed bug #889 : Closure inside catch/else/elseif causes indentation error
-- Fixed bug #890 : Function call inside returned short array value can cause indentation error inside CASE statements
-- Fixed bug #897 : Generic.Functions.CallTimePassByReference.NotAllowed false positive when short array syntax
-- Fixed bug #900 : Squiz.Functions.FunctionDeclarationArgumentSpacing bug when no space between type hint and argument
-- Fixed bug #902 : T_OR_EQUAL and T_POW_EQUAL are not seen as assignment tokens
-- Fixed bug #910 : Unrecognized "extends" and indentation on anonymous classes
-- Fixed bug #915 : JS Tokenizer generates errors when processing some decimals
-- Fixed bug #928 : Endless loop when sniffing a PHP file with a git merge conflict inside a function
-- Fixed bug #937 : Shebang can cause PSR1 SideEffects warning
+    - Further fix for bug [#698][sq-698]
+
+### Fixed
+- Fixed bug [#791][sq-791] : codingStandardsChangeSetting settings not working with namespaces
+- Fixed bug [#872][sq-872] : Incorrect detection of blank lines between CSS class names
+- Fixed bug [#879][sq-879] : Generic InlineControlStructureSniff can create parse error when case/if/elseif/else have mixed brace and braceless definitions
+- Fixed bug [#883][sq-883] : PSR2 is not checking for blank lines at the start and end of control structures
+- Fixed bug [#884][sq-884] : Incorrect indentation notice for anonymous classes
+- Fixed bug [#887][sq-887] : Using curly braces for a shared CASE/DEFAULT statement can generate an error in PSR2 SwitchDeclaration
+- Fixed bug [#889][sq-889] : Closure inside catch/else/elseif causes indentation error
+- Fixed bug [#890][sq-890] : Function call inside returned short array value can cause indentation error inside CASE statements
+- Fixed bug [#897][sq-897] : Generic.Functions.CallTimePassByReference.NotAllowed false positive when short array syntax
+- Fixed bug [#900][sq-900] : Squiz.Functions.FunctionDeclarationArgumentSpacing bug when no space between type hint and argument
+- Fixed bug [#902][sq-902] : T_OR_EQUAL and T_POW_EQUAL are not seen as assignment tokens
+- Fixed bug [#910][sq-910] : Unrecognized "extends" and indentation on anonymous classes
+- Fixed bug [#915][sq-915] : JS Tokenizer generates errors when processing some decimals
+- Fixed bug [#928][sq-928] : Endless loop when sniffing a PHP file with a git merge conflict inside a function
+- Fixed bug [#937][sq-937] : Shebang can cause PSR1 SideEffects warning
     - Thanks to [Clay Loveless][@claylo] for the patch
-- Fixed bug #938 : CallTimePassByReferenceSniff ignores functions with return value
+- Fixed bug [#938][sq-938] : CallTimePassByReferenceSniff ignores functions with return value
+
+[sq-542]: https://github.com/squizlabs/PHP_CodeSniffer/issues/542
+[sq-791]: https://github.com/squizlabs/PHP_CodeSniffer/issues/791
+[sq-847]: https://github.com/squizlabs/PHP_CodeSniffer/issues/847
+[sq-872]: https://github.com/squizlabs/PHP_CodeSniffer/issues/872
+[sq-877]: https://github.com/squizlabs/PHP_CodeSniffer/issues/877
+[sq-878]: https://github.com/squizlabs/PHP_CodeSniffer/issues/878
+[sq-879]: https://github.com/squizlabs/PHP_CodeSniffer/issues/879
+[sq-882]: https://github.com/squizlabs/PHP_CodeSniffer/issues/882
+[sq-883]: https://github.com/squizlabs/PHP_CodeSniffer/issues/883
+[sq-884]: https://github.com/squizlabs/PHP_CodeSniffer/issues/884
+[sq-887]: https://github.com/squizlabs/PHP_CodeSniffer/issues/887
+[sq-889]: https://github.com/squizlabs/PHP_CodeSniffer/issues/889
+[sq-890]: https://github.com/squizlabs/PHP_CodeSniffer/issues/890
+[sq-897]: https://github.com/squizlabs/PHP_CodeSniffer/issues/897
+[sq-900]: https://github.com/squizlabs/PHP_CodeSniffer/issues/900
+[sq-902]: https://github.com/squizlabs/PHP_CodeSniffer/issues/902
+[sq-903]: https://github.com/squizlabs/PHP_CodeSniffer/issues/903
+[sq-910]: https://github.com/squizlabs/PHP_CodeSniffer/issues/910
+[sq-915]: https://github.com/squizlabs/PHP_CodeSniffer/issues/915
+[sq-928]: https://github.com/squizlabs/PHP_CodeSniffer/issues/928
+[sq-934]: https://github.com/squizlabs/PHP_CodeSniffer/issues/934
+[sq-937]: https://github.com/squizlabs/PHP_CodeSniffer/pull/937
+[sq-938]: https://github.com/squizlabs/PHP_CodeSniffer/issues/938
 
 ## [2.5.1] - 2016-01-20
+
 ### Changed
 - The PHP-supplied T_SPACESHIP token has been replicated for PHP versions before 7.0
 - T_SPACESHIP is now correctly identified as an operator
@@ -2929,53 +4253,80 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Generic LowerCaseKeyword now ensures array type hints are lowercase as well
     - Thanks to [Mathieu Rochette][@mathroc] for the patch
 - Squiz ComparisonOperatorUsageSniff no longer hangs on JS FOR loops that don't use semicolons
-- PHP_CodesSniffer now includes the composer autoload.php file, if there is one
+- PHP_CodesSniffer now includes the composer `autoload.php` file, if there is one
     - Thanks to [Klaus Purer][@klausi] for the patch
-- Added error Squiz.Commenting.FunctionComment.ScalarTypeHintMissing for PHP7 only (request #858)
+- Added error Squiz.Commenting.FunctionComment.ScalarTypeHintMissing for PHP7 only (request [#858][sq-858])
     - These errors were previously reported as Squiz.Commenting.FunctionComment.TypeHintMissing on PHP7
     - Disable this error message in a ruleset.xml file if your code needs to run on both PHP5 and PHP7
 - The PHP 5.6 __debugInfo magic method no longer produces naming convention errors
     - Thanks to [Michael Nowack][@syranez] for the patch
-- PEAR and Squiz FunctionComment sniffs now support variadic functions (request #841)
-
-### Fixed
-- Fixed bug #622 : Wrong detection of Squiz.CSS.DuplicateStyleDefinition with media queries
-- Fixed bug #752 : The missing exception error is reported in first found DocBlock
-- Fixed bug #794 : PSR2 MultiLineFunctionDeclaration forbids comments after opening parenthesis of a multiline call
-- Fixed bug #820 : PEAR/PSR2 FunctionCallSignature sniffs suggest wrong indent when there are multiple arguments on a line
-- Fixed bug #822 : Ruleset hard-coded file paths are not used if not running from the same directory as the ruleset
-- Fixed bug #825 : FunctionCallArgumentSpacing sniff complains about more than one space before comment in multi-line function call
-- Fixed bug #828 : Null classname is tokenized as T_NULL instead of T_STRING
-- Fixed bug #829 : Short array argument not fixed correctly when multiple function arguments are on the same line
-- Fixed bug #831 : PHPCS freezes in an infinite loop under Windows if no standard is passed
-- Fixed bug #832 : Tokenizer does not support context sensitive parsing
+- PEAR and Squiz FunctionComment sniffs now support variadic functions (request [#841][sq-841])
+
+### Fixed
+- Fixed bug [#622][sq-622] : Wrong detection of Squiz.CSS.DuplicateStyleDefinition with media queries
+- Fixed bug [#752][sq-752] : The missing exception error is reported in first found DocBlock
+- Fixed bug [#794][sq-794] : PSR2 MultiLineFunctionDeclaration forbids comments after opening parenthesis of a multiline call
+- Fixed bug [#820][sq-820] : PEAR/PSR2 FunctionCallSignature sniffs suggest wrong indent when there are multiple arguments on a line
+- Fixed bug [#822][sq-822] : Ruleset hard-coded file paths are not used if not running from the same directory as the ruleset
+- Fixed bug [#825][sq-825] : FunctionCallArgumentSpacing sniff complains about more than one space before comment in multi-line function call
+- Fixed bug [#828][sq-828] : Null classname is tokenized as T_NULL instead of T_STRING
+- Fixed bug [#829][sq-829] : Short array argument not fixed correctly when multiple function arguments are on the same line
+- Fixed bug [#831][sq-831] : PHPCS freezes in an infinite loop under Windows if no standard is passed
+- Fixed bug [#832][sq-832] : Tokenizer does not support context sensitive parsing
     - Thanks to [Jaroslav Hanslík][@kukulich] for the patch
-- Fixed bug #835 : PEAR.Functions.FunctionCallSignature broken when closure uses return types
-- Fixed bug #838 : CSS indentation fixer changes color codes
+- Fixed bug [#835][sq-835] : PEAR.Functions.FunctionCallSignature broken when closure uses return types
+- Fixed bug [#838][sq-838] : CSS indentation fixer changes color codes
     - Thanks to [Klaus Purer][@klausi] for the patch
-- Fixed bug #839 : "__()" method is marked as not camel caps
+- Fixed bug [#839][sq-839] : "__()" method is marked as not camel caps
     - Thanks to [Tim Bezhashvyly][@tim-bezhashvyly] for the patch
-- Fixed bug #852 : Generic.Commenting.DocComment not finding errors when long description is omitted
-- Fixed bug #854 : Return typehints in interfaces are not reported as T_RETURN_TYPE
+- Fixed bug [#852][sq-852] : Generic.Commenting.DocComment not finding errors when long description is omitted
+- Fixed bug [#854][sq-854] : Return typehints in interfaces are not reported as T_RETURN_TYPE
     - Thanks to [Jaroslav Hanslík][@kukulich] for the patch
-- Fixed bug #855 : Capital letter detection for multibyte strings doesn't work correctly
-- Fixed bug #857 : PSR2.ControlStructure.SwitchDeclaration shouldn't check indent of curly brace closers
-- Fixed bug #859 : Switch statement indention issue when returning function call with closure
-- Fixed bug #861 : Single-line arrays and function calls can generate incorrect indentation errors
-- Fixed bug #867 : Squiz.Strings.DoubleQuoteUsage broken for some escape codes
+- Fixed bug [#855][sq-855] : Capital letter detection for multibyte strings doesn't work correctly
+- Fixed bug [#857][sq-857] : PSR2.ControlStructure.SwitchDeclaration shouldn't check indent of curly brace closers
+- Fixed bug [#859][sq-859] : Switch statement indention issue when returning function call with closure
+- Fixed bug [#861][sq-861] : Single-line arrays and function calls can generate incorrect indentation errors
+- Fixed bug [#867][sq-867] : Squiz.Strings.DoubleQuoteUsage broken for some escape codes
     - Thanks to [Jack Blower][@ElvenSpellmaker] for the help with the fix
-- Fixed bug #21005 : Incorrect indent detection when multiple properties are initialized to arrays
-- Fixed bug #21010 : Incorrect missing colon detection in CSS when first style is not on new line
-- Fixed bug #21011 : Incorrect error message text when newline found after opening brace
+- Fixed bug [#21005][pear-21005] : Incorrect indent detection when multiple properties are initialized to arrays
+- Fixed bug [#21010][pear-21010] : Incorrect missing colon detection in CSS when first style is not on new line
+- Fixed bug [#21011][pear-21011] : Incorrect error message text when newline found after opening brace
+
+[sq-622]: https://github.com/squizlabs/PHP_CodeSniffer/issues/622
+[sq-752]: https://github.com/squizlabs/PHP_CodeSniffer/issues/752
+[sq-794]: https://github.com/squizlabs/PHP_CodeSniffer/issues/794
+[sq-820]: https://github.com/squizlabs/PHP_CodeSniffer/issues/820
+[sq-822]: https://github.com/squizlabs/PHP_CodeSniffer/issues/822
+[sq-825]: https://github.com/squizlabs/PHP_CodeSniffer/issues/825
+[sq-828]: https://github.com/squizlabs/PHP_CodeSniffer/issues/828
+[sq-829]: https://github.com/squizlabs/PHP_CodeSniffer/issues/829
+[sq-831]: https://github.com/squizlabs/PHP_CodeSniffer/issues/831
+[sq-832]: https://github.com/squizlabs/PHP_CodeSniffer/issues/832
+[sq-835]: https://github.com/squizlabs/PHP_CodeSniffer/issues/835
+[sq-838]: https://github.com/squizlabs/PHP_CodeSniffer/pull/838
+[sq-839]: https://github.com/squizlabs/PHP_CodeSniffer/issues/839
+[sq-841]: https://github.com/squizlabs/PHP_CodeSniffer/issues/841
+[sq-852]: https://github.com/squizlabs/PHP_CodeSniffer/issues/852
+[sq-854]: https://github.com/squizlabs/PHP_CodeSniffer/issues/854
+[sq-855]: https://github.com/squizlabs/PHP_CodeSniffer/pull/855
+[sq-857]: https://github.com/squizlabs/PHP_CodeSniffer/issues/857
+[sq-858]: https://github.com/squizlabs/PHP_CodeSniffer/issues/858
+[sq-859]: https://github.com/squizlabs/PHP_CodeSniffer/issues/859
+[sq-861]: https://github.com/squizlabs/PHP_CodeSniffer/issues/861
+[sq-867]: https://github.com/squizlabs/PHP_CodeSniffer/issues/867
+[pear-21005]: https://pear.php.net/bugs/bug.php?id=21005
+[pear-21010]: https://pear.php.net/bugs/bug.php?id=21010
+[pear-21011]: https://pear.php.net/bugs/bug.php?id=21011
 
 ## [2.5.0] - 2015-12-11
+
 ### Changed
-- PHPCS will now look for a phpcs.xml file in parent directories as well as the current directory (request #626)
+- PHPCS will now look for a phpcs.xml file in parent directories as well as the current directory (request [#626][sq-626])
 - PHPCS will now use a phpcs.xml file even if files are specified on the command line
     - This file is still only used if no standard is specified on the command line
-- Added support for a phpcs.xml.dist file (request #583)
+- Added support for a phpcs.xml.dist file (request [#583][sq-583])
     - If both a phpcs.xml and phpcs.xml.dist file are present, the phpcs.xml file will be used
-- Added support for setting PHP ini values in ruleset.xml files (request #560)
+- Added support for setting PHP ini values in ruleset.xml files (request [#560][sq-560])
     - Setting the value of the new ini tags to name="memory_limit" value="32M" is the same as -d memory_limit=32M
 - Added support for one or more bootstrap files to be run before processing begins
     - Use the --bootstrap=file,file,file command line argument to include bootstrap files
@@ -2986,24 +4337,39 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Arnout Boks][@aboks] for the patch
 
 ### Fixed
-- Fixed bug #660 : Syntax checks can fail on Windows with PHP5.6
-- Fixed bug #784 : $this->trait is seen as a T_TRAIT token
-- Fixed bug #786 : Switch indent issue with short array notation
-- Fixed bug #787 : SpacingAfterDefaultBreak confused by multi-line statements
-- Fixed bug #797 : Parsing CSS url() value breaks further parsing
-- Fixed bug #805 : Squiz.Commenting.FunctionComment.InvalidTypeHint on Scalar types on PHP7
-- Fixed bug #807 : Cannot fix line endings when open PHP tag is not on the first line
-- Fixed bug #808 : JS tokeniser incorrectly setting some function and class names to control structure tokens
-- Fixed bug #809 : PHPCBF can break a require_once statement with a space before the open parenthesis
-- Fixed bug #813 : PEAR FunctionCallSignature checks wrong indent when first token on line is part of a multi-line string
+- Fixed bug [#660][sq-660] : Syntax checks can fail on Windows with PHP5.6
+- Fixed bug [#784][sq-784] : $this->trait is seen as a T_TRAIT token
+- Fixed bug [#786][sq-786] : Switch indent issue with short array notation
+- Fixed bug [#787][sq-787] : SpacingAfterDefaultBreak confused by multi-line statements
+- Fixed bug [#797][sq-797] : Parsing CSS url() value breaks further parsing
+- Fixed bug [#805][sq-805] : Squiz.Commenting.FunctionComment.InvalidTypeHint on Scalar types on PHP7
+- Fixed bug [#807][sq-807] : Cannot fix line endings when open PHP tag is not on the first line
+- Fixed bug [#808][sq-808] : JS tokenizer incorrectly setting some function and class names to control structure tokens
+- Fixed bug [#809][sq-809] : PHPCBF can break a require_once statement with a space before the open parenthesis
+- Fixed bug [#813][sq-813] : PEAR FunctionCallSignature checks wrong indent when first token on line is part of a multi-line string
+
+[sq-560]: https://github.com/squizlabs/PHP_CodeSniffer/issues/560
+[sq-583]: https://github.com/squizlabs/PHP_CodeSniffer/issues/583
+[sq-626]: https://github.com/squizlabs/PHP_CodeSniffer/issues/626
+[sq-660]: https://github.com/squizlabs/PHP_CodeSniffer/pull/660
+[sq-784]: https://github.com/squizlabs/PHP_CodeSniffer/issues/784
+[sq-786]: https://github.com/squizlabs/PHP_CodeSniffer/issues/786
+[sq-787]: https://github.com/squizlabs/PHP_CodeSniffer/issues/787
+[sq-797]: https://github.com/squizlabs/PHP_CodeSniffer/issues/797
+[sq-805]: https://github.com/squizlabs/PHP_CodeSniffer/issues/805
+[sq-807]: https://github.com/squizlabs/PHP_CodeSniffer/issues/807
+[sq-808]: https://github.com/squizlabs/PHP_CodeSniffer/issues/808
+[sq-809]: https://github.com/squizlabs/PHP_CodeSniffer/issues/809
+[sq-813]: https://github.com/squizlabs/PHP_CodeSniffer/issues/813
 
 ## [2.4.0] - 2015-11-24
+
 ### Changed
 - Added support for PHP 7 anonymous classes
     - Anonymous classes are now tokenized as T_ANON_CLASS and ignored by normal class sniffs
 - Added support for PHP 7 function return type declarations
     - Return types are now tokenized as T_RETURN_TYPE
-- Fixed tokenizing of the XOR operator, which was incorrectly identified as a power operator (bug #765)
+- Fixed tokenizing of the XOR operator, which was incorrectly identified as a power operator (bug [#765][sq-765])
     - The T_POWER token has been removed and replaced by the T_BITWISE_XOR token
     - The PHP-supplied T_POW token has been replicated for PHP versions before 5.6
 - Traits are now tokenized in PHP versions before 5.4 to make testing easier
@@ -3023,40 +4389,66 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Generic InlineControlStructureSniff now correctly fixes ELSEIF statements
 
 ### Fixed
-- Fixed bug #601 : Expected type hint int[]; found array in Squiz FunctionCommentSniff
+- Fixed bug [#601][sq-601] : Expected type hint int[]; found array in Squiz FunctionCommentSniff
     - Thanks to [Scato Eggen][@scato] for the patch
-- Fixed bug #625 : Consider working around T_HASHBANG in HHVM 3.5.x and 3.6.x
+- Fixed bug [#625][sq-625] : Consider working around T_HASHBANG in HHVM 3.5.x and 3.6.x
     - Thanks to [Kunal Mehta][@legoktm] for the patch
-- Fixed bug #692 : Comment tokenizer can break when using mbstring function overloading
-- Fixed bug #694 : Long sniff codes can cause PHP warnings in source report when showing error codes
-- Fixed bug #698 : PSR2.Methods.FunctionCallSignature.Indent forces exact indent of ternary operator parameters
-- Fixed bug #704 : ScopeIndent can fail when an opening parenthesis is on a line by itself
-- Fixed bug #707 : Squiz MethodScopeSniff doesn't handle nested functions
-- Fixed bug #709 : Squiz.Sniffs.Whitespace.ScopeClosingBraceSniff marking indented endif in mixed inline HTML blocks
-- Fixed bug #711 : Sniffing from STDIN shows Generic.Files.LowercasedFilename.NotFound error
-- Fixed bug #714 : Fixes suppression of errors using docblocks
+- Fixed bug [#692][sq-692] : Comment tokenizer can break when using mbstring function overloading
+- Fixed bug [#694][sq-694] : Long sniff codes can cause PHP warnings in source report when showing error codes
+- Fixed bug [#698][sq-698] : PSR2.Methods.FunctionCallSignature.Indent forces exact indent of ternary operator parameters
+- Fixed bug [#704][sq-704] : ScopeIndent can fail when an opening parenthesis is on a line by itself
+- Fixed bug [#707][sq-707] : Squiz MethodScopeSniff doesn't handle nested functions
+- Fixed bug [#709][sq-709] : Squiz.Sniffs.Whitespace.ScopeClosingBraceSniff marking indented endif in mixed inline HTML blocks
+- Fixed bug [#711][sq-711] : Sniffing from STDIN shows Generic.Files.LowercasedFilename.NotFound error
+- Fixed bug [#714][sq-714] : Fixes suppression of errors using docblocks
     - Thanks to [Andrzej Karmazyn][@akarmazyn] for the patch
-- Fixed bug #716 : JSON report is invalid when messages contain newlines or tabs
+- Fixed bug [#716][sq-716] : JSON report is invalid when messages contain newlines or tabs
     - Thanks to [Pieter Frenssen][@pfrenssen] for the patch
-- Fixed bug #723 : ScopeIndent can fail when multiple array closers are on the same line
-- Fixed bug #730 : ScopeIndent can fail when a short array opening square bracket is on a line by itself
-- Fixed bug #732 : PHP Notice if @package name is made up of all invalid characters
+- Fixed bug [#723][sq-723] : ScopeIndent can fail when multiple array closers are on the same line
+- Fixed bug [#730][sq-730] : ScopeIndent can fail when a short array opening square bracket is on a line by itself
+- Fixed bug [#732][sq-732] : PHP Notice if @package name is made up of all invalid characters
     - Adds new error code PEAR.Commenting.FileComment.InvalidPackageValue
-- Fixed bug #748 : Auto fix for Squiz.Commenting.BlockComment.WrongEnd is incorrect
+- Fixed bug [#748][sq-748] : Auto fix for Squiz.Commenting.BlockComment.WrongEnd is incorrect
     - Thanks to [J.D. Grimes][@JDGrimes] for the patch
-- Fixed bug #753 : PSR2 standard shouldn't require space after USE block when next code is a closing tag
-- Fixed bug #768 : PEAR FunctionCallSignature sniff forbids comments after opening parenthesis of a multiline call
-- Fixed bug #769 : Incorrect detection of variable reference operator when used with short array syntax
+- Fixed bug [#753][sq-753] : PSR2 standard shouldn't require space after USE block when next code is a closing tag
+- Fixed bug [#768][sq-768] : PEAR FunctionCallSignature sniff forbids comments after opening parenthesis of a multiline call
+- Fixed bug [#769][sq-769] : Incorrect detection of variable reference operator when used with short array syntax
     - Thanks to [Klaus Purer][@klausi] for the patch
-- Fixed bug #772 : Syntax error when using PHPCBF on alternative style foreach loops
-- Fixed bug #773 : Syntax error when stripping trailing PHP close tag and previous statement has no semicolon
-- Fixed bug #778 : PHPCBF creates invalid PHP for inline FOREACH containing multiple control structures
-- Fixed bug #781 : Incorrect checking for PHP7 return types on multi-line function declarations
-- Fixed bug #782 : Conditional function declarations cause fixing conflicts in Squiz standard
+- Fixed bug [#772][sq-772] : Syntax error when using PHPCBF on alternative style foreach loops
+- Fixed bug [#773][sq-773] : Syntax error when stripping trailing PHP close tag and previous statement has no semicolon
+- Fixed bug [#778][sq-778] : PHPCBF creates invalid PHP for inline FOREACH containing multiple control structures
+- Fixed bug [#781][sq-781] : Incorrect checking for PHP7 return types on multi-line function declarations
+- Fixed bug [#782][sq-782] : Conditional function declarations cause fixing conflicts in Squiz standard
     - Squiz.ControlStructures.ControlSignature no longer enforces a single newline after open brace
     - Squiz.WhiteSpace.ControlStructureSpacing can be used to check spacing at the start/end of control structures
 
+[sq-601]: https://github.com/squizlabs/PHP_CodeSniffer/issues/601
+[sq-625]: https://github.com/squizlabs/PHP_CodeSniffer/issues/625
+[sq-692]: https://github.com/squizlabs/PHP_CodeSniffer/pull/692
+[sq-694]: https://github.com/squizlabs/PHP_CodeSniffer/issues/694
+[sq-698]: https://github.com/squizlabs/PHP_CodeSniffer/issues/698
+[sq-704]: https://github.com/squizlabs/PHP_CodeSniffer/issues/704
+[sq-707]: https://github.com/squizlabs/PHP_CodeSniffer/pull/707
+[sq-709]: https://github.com/squizlabs/PHP_CodeSniffer/issues/709
+[sq-711]: https://github.com/squizlabs/PHP_CodeSniffer/issues/711
+[sq-714]: https://github.com/squizlabs/PHP_CodeSniffer/pull/714
+[sq-716]: https://github.com/squizlabs/PHP_CodeSniffer/pull/716
+[sq-723]: https://github.com/squizlabs/PHP_CodeSniffer/issues/723
+[sq-730]: https://github.com/squizlabs/PHP_CodeSniffer/pull/730
+[sq-732]: https://github.com/squizlabs/PHP_CodeSniffer/pull/732
+[sq-748]: https://github.com/squizlabs/PHP_CodeSniffer/pull/748
+[sq-753]: https://github.com/squizlabs/PHP_CodeSniffer/issues/753
+[sq-765]: https://github.com/squizlabs/PHP_CodeSniffer/issues/765
+[sq-768]: https://github.com/squizlabs/PHP_CodeSniffer/issues/768
+[sq-769]: https://github.com/squizlabs/PHP_CodeSniffer/pull/769
+[sq-772]: https://github.com/squizlabs/PHP_CodeSniffer/issues/772
+[sq-773]: https://github.com/squizlabs/PHP_CodeSniffer/issues/773
+[sq-778]: https://github.com/squizlabs/PHP_CodeSniffer/issues/778
+[sq-781]: https://github.com/squizlabs/PHP_CodeSniffer/issues/781
+[sq-782]: https://github.com/squizlabs/PHP_CodeSniffer/issues/782
+
 ## [2.3.4] - 2015-09-09
+
 ### Changed
 - JSON report format now includes the fixable status for each error message and the total number of fixable errors
 - Added more guard code for function declarations with syntax errors
@@ -3066,33 +4458,51 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Set the allowMultiline property to TRUE (default is FALSE) in your ruleset.xml file to enable this
     - By default, concat used only for getting around line length limits still generates an error
     - Thanks to [Stefan Lenselink][@stefanlenselink] for the contribution
-- Invalid byte sequences no longer throw iconv_strlen() errors (request #639)
+- Invalid byte sequences no longer throw iconv_strlen() errors (request [#639][sq-639])
     - Thanks to [Willem Stuursma][@willemstuursma] for the patch
 - Generic TodoSniff and FixmeSniff are now better at processing strings with invalid characters
 - PEAR FunctionCallSignatureSniff now ignores indentation of inline HTML content
 - Squiz ControlSignatureSniff now supports control structures with only inline HTML content
 
 ### Fixed
-- Fixed bug #636 : Some class names cause CSS tokenizer to hang
-- Fixed bug #638 : VCS blame reports output error content from the blame commands for files not under VC
-- Fixed bug #642 : Method params incorrectly detected when default value uses short array syntax
+- Fixed bug [#636][sq-636] : Some class names cause CSS tokenizer to hang
+- Fixed bug [#638][sq-638] : VCS blame reports output error content from the blame commands for files not under VC
+- Fixed bug [#642][sq-642] : Method params incorrectly detected when default value uses short array syntax
     - Thanks to [Josh Davis][@joshdavis11] for the patch
-- Fixed bug #644 : PEAR ScopeClosingBrace sniff does not work with mixed HTML/PHP
-- Fixed bug #645 : FunctionSignature and ScopeIndent sniffs don't detect indents correctly when PHP open tag is not on a line by itself
-- Fixed bug #648 : Namespace not tokenized correctly when followed by multiple use statements
-- Fixed bug #654 : Comments affect indent check for BSDAllman brace style
-- Fixed bug #658 : Squiz.Functions.FunctionDeclarationSpacing error for multi-line declarations with required spaces greater than zero
+- Fixed bug [#644][sq-644] : PEAR ScopeClosingBrace sniff does not work with mixed HTML/PHP
+- Fixed bug [#645][sq-645] : FunctionSignature and ScopeIndent sniffs don't detect indents correctly when PHP open tag is not on a line by itself
+- Fixed bug [#648][sq-648] : Namespace not tokenized correctly when followed by multiple use statements
+- Fixed bug [#654][sq-654] : Comments affect indent check for BSDAllman brace style
+- Fixed bug [#658][sq-658] : Squiz.Functions.FunctionDeclarationSpacing error for multi-line declarations with required spaces greater than zero
     - Thanks to [J.D. Grimes][@JDGrimes] for the patch
-- Fixed bug #663 : No space after class name generates: Class name "" is not in camel caps format
-- Fixed bug #667 : Scope indent check can go into infinite loop due to some parse errors
-- Fixed bug #670 : Endless loop in PSR1 SideEffects sniffer if no semicolon after last statement
+- Fixed bug [#663][sq-663] : No space after class name generates: Class name "" is not in camel caps format
+- Fixed bug [#667][sq-667] : Scope indent check can go into infinite loop due to some parse errors
+- Fixed bug [#670][sq-670] : Endless loop in PSR1 SideEffects sniffer if no semicolon after last statement
     - Thanks to [Thomas Jarosch][@thomasjfox] for the patch
-- Fixed bug #672 : Call-time pass-by-reference false positive
-- Fixed bug #683 : Comments are incorrectly reported by PSR2.ControlStructures.SwitchDeclaration sniff
-- Fixed bug #687 : ScopeIndent does not check indent correctly for method prefixes like public and abstract
-- Fixed bug #689 : False error on some comments after class closing brace
+- Fixed bug [#672][sq-672] : Call-time pass-by-reference false positive
+- Fixed bug [#683][sq-683] : Comments are incorrectly reported by PSR2.ControlStructures.SwitchDeclaration sniff
+- Fixed bug [#687][sq-687] : ScopeIndent does not check indent correctly for method prefixes like public and abstract
+- Fixed bug [#689][sq-689] : False error on some comments after class closing brace
+
+[sq-636]: https://github.com/squizlabs/PHP_CodeSniffer/issues/636
+[sq-638]: https://github.com/squizlabs/PHP_CodeSniffer/issues/638
+[sq-639]: https://github.com/squizlabs/PHP_CodeSniffer/pull/639
+[sq-642]: https://github.com/squizlabs/PHP_CodeSniffer/pull/642
+[sq-644]: https://github.com/squizlabs/PHP_CodeSniffer/issues/644
+[sq-645]: https://github.com/squizlabs/PHP_CodeSniffer/issues/645
+[sq-648]: https://github.com/squizlabs/PHP_CodeSniffer/issues/648
+[sq-654]: https://github.com/squizlabs/PHP_CodeSniffer/issues/654
+[sq-658]: https://github.com/squizlabs/PHP_CodeSniffer/pull/658
+[sq-663]: https://github.com/squizlabs/PHP_CodeSniffer/issues/663
+[sq-667]: https://github.com/squizlabs/PHP_CodeSniffer/issues/667
+[sq-670]: https://github.com/squizlabs/PHP_CodeSniffer/pull/670
+[sq-672]: https://github.com/squizlabs/PHP_CodeSniffer/issues/672
+[sq-683]: https://github.com/squizlabs/PHP_CodeSniffer/issues/683
+[sq-687]: https://github.com/squizlabs/PHP_CodeSniffer/issues/687
+[sq-689]: https://github.com/squizlabs/PHP_CodeSniffer/issues/689
 
 ## [2.3.3] - 2015-06-24
+
 ### Changed
 - Improved the performance of the CSS tokenizer, especially on very large CSS files (thousands of lines)
     - Thanks to [Klaus Purer][@klausi] for the patch
@@ -3101,82 +4511,124 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Added more guard code for syntax errors to various sniffs
 - Improved support for older HHVM versions
     - Thanks to [Kunal Mehta][@legoktm] for the patch
-- Squiz ValidLogicalOperatorsSniff now ignores XOR as type casting is different when using the ^ operator (request #567)
+- Squiz ValidLogicalOperatorsSniff now ignores XOR as type casting is different when using the ^ operator (request [#567][sq-567])
 - Squiz CommentedOutCodeSniff is now better at ignoring URLs inside comments
 - Squiz ControlSignatureSniff is now better at checking embedded PHP code
 - Squiz ScopeClosingBraceSniff is now better at checking embedded PHP code
 
 ### Fixed
-- Fixed bug #584 : Squiz.Arrays.ArrayDeclaration sniff gives incorrect NoComma error for multiline string values
-- Fixed bug #589 : PEAR.Functions.FunctionCallSignature sniff not checking all function calls
-- Fixed bug #592 : USE statement tokenising can sometimes result in mismatched scopes
-- Fixed bug #594 : Tokenizer issue on closure that returns by reference
-- Fixed bug #595 : Colons in CSS selectors within media queries throw false positives
+- Fixed bug [#584][sq-584] : Squiz.Arrays.ArrayDeclaration sniff gives incorrect NoComma error for multiline string values
+- Fixed bug [#589][sq-589] : PEAR.Functions.FunctionCallSignature sniff not checking all function calls
+- Fixed bug [#592][sq-592] : USE statement tokenizing can sometimes result in mismatched scopes
+- Fixed bug [#594][sq-594] : Tokenizer issue on closure that returns by reference
+- Fixed bug [#595][sq-595] : Colons in CSS selectors within media queries throw false positives
     - Thanks to [Klaus Purer][@klausi] for the patch
-- Fixed bug #598 : PHPCBF can break function/use closure brace placement
-- Fixed bug #603 : Squiz ControlSignatureSniff hard-codes opener type while fixing
-- Fixed bug #605 : Auto report-width specified in ruleset.xml ignored
-- Fixed bug #611 : Invalid numeric literal on CSS files under PHP7
-- Fixed bug #612 : Multi-file diff generating incorrectly if files do not end with EOL char
-- Fixed bug #615 : Squiz OperatorBracketSniff incorrectly reports and fixes operations using self::
-- Fixed bug #616 : Squiz DisallowComparisonAssignmentSniff inconsistent errors with inline IF statements
-- Fixed bug #617 : Space after switch keyword in PSR-2 is not being enforced
-- Fixed bug #621 : PSR2 SwitchDeclaration sniff doesn't detect, or correctly fix, case body on same line as statement
+- Fixed bug [#598][sq-598] : PHPCBF can break function/use closure brace placement
+- Fixed bug [#603][sq-603] : Squiz ControlSignatureSniff hard-codes opener type while fixing
+- Fixed bug [#605][sq-605] : Auto report-width specified in ruleset.xml ignored
+- Fixed bug [#611][sq-611] : Invalid numeric literal on CSS files under PHP7
+- Fixed bug [#612][sq-612] : Multi-file diff generating incorrectly if files do not end with EOL char
+- Fixed bug [#615][sq-615] : Squiz OperatorBracketSniff incorrectly reports and fixes operations using self::
+- Fixed bug [#616][sq-616] : Squiz DisallowComparisonAssignmentSniff inconsistent errors with inline IF statements
+- Fixed bug [#617][sq-617] : Space after switch keyword in PSR-2 is not being enforced
+- Fixed bug [#621][sq-621] : PSR2 SwitchDeclaration sniff doesn't detect, or correctly fix, case body on same line as statement
+
+[sq-567]: https://github.com/squizlabs/PHP_CodeSniffer/issues/567
+[sq-584]: https://github.com/squizlabs/PHP_CodeSniffer/issues/584
+[sq-589]: https://github.com/squizlabs/PHP_CodeSniffer/issues/589
+[sq-592]: https://github.com/squizlabs/PHP_CodeSniffer/issues/592
+[sq-594]: https://github.com/squizlabs/PHP_CodeSniffer/issues/594
+[sq-595]: https://github.com/squizlabs/PHP_CodeSniffer/pull/595
+[sq-598]: https://github.com/squizlabs/PHP_CodeSniffer/issues/598
+[sq-603]: https://github.com/squizlabs/PHP_CodeSniffer/issues/603
+[sq-605]: https://github.com/squizlabs/PHP_CodeSniffer/issues/605
+[sq-611]: https://github.com/squizlabs/PHP_CodeSniffer/issues/611
+[sq-612]: https://github.com/squizlabs/PHP_CodeSniffer/issues/612
+[sq-615]: https://github.com/squizlabs/PHP_CodeSniffer/issues/615
+[sq-616]: https://github.com/squizlabs/PHP_CodeSniffer/issues/616
+[sq-617]: https://github.com/squizlabs/PHP_CodeSniffer/issues/617
+[sq-621]: https://github.com/squizlabs/PHP_CodeSniffer/issues/621
 
 ## [2.3.2] - 2015-04-29
+
 ### Changed
-- The error message for PSR2.ControlStructures.SwitchDeclaration.WrongOpenercase is now clearer (request #579)
+- The error message for PSR2.ControlStructures.SwitchDeclaration.WrongOpenercase is now clearer (request [#579][sq-579])
 
 ### Fixed
-- Fixed bug #545 : Long list of CASE statements can cause tokenizer to reach a depth limit
-- Fixed bug #565 : Squiz.WhiteSpace.OperatorSpacing reports negative number in short array
+- Fixed bug [#545][sq-545] : Long list of CASE statements can cause tokenizer to reach a depth limit
+- Fixed bug [#565][sq-565] : Squiz.WhiteSpace.OperatorSpacing reports negative number in short array
     - Thanks to [Vašek Purchart][@VasekPurchart] for the patch
     - Same fix also applied to Squiz.Formatting.OperatorBracket
-- Fixed bug #569 : Generic ScopeIndentSniff throws PHP notices in JS files
-- Fixed bug #570 : Phar class fatals in PHP less than 5.3
+- Fixed bug [#569][sq-569] : Generic ScopeIndentSniff throws PHP notices in JS files
+- Fixed bug [#570][sq-570] : Phar class fatals in PHP less than 5.3
+
+[sq-545]: https://github.com/squizlabs/PHP_CodeSniffer/issues/545
+[sq-565]: https://github.com/squizlabs/PHP_CodeSniffer/pull/565
+[sq-569]: https://github.com/squizlabs/PHP_CodeSniffer/pull/569
+[sq-570]: https://github.com/squizlabs/PHP_CodeSniffer/issues/570
+[sq-579]: https://github.com/squizlabs/PHP_CodeSniffer/issues/579
 
 ## [2.3.1] - 2015-04-23
+
 ### Changed
 - PHPCS can now exit with 0 even if errors are found
     - Set the ignore_errors_on_exit config variable to 1 to set this behaviour
     - Use with the ignore_warnings_on_exit config variable to never return a non-zero exit code
-- Added Generic DisallowLongArraySyntaxSniff to enforce the use of the PHP short array syntax (request #483)
+- Added Generic DisallowLongArraySyntaxSniff to enforce the use of the PHP short array syntax (request [#483][sq-483])
     - Thanks to [Xaver Loppenstedt][@xalopp] for helping with tests
-- Added Generic DisallowShortArraySyntaxSniff to ban the use of the PHP short array syntax (request #483)
+- Added Generic DisallowShortArraySyntaxSniff to ban the use of the PHP short array syntax (request [#483][sq-483])
     - Thanks to [Xaver Loppenstedt][@xalopp] for helping with tests
-- Generic ScopeIndentSniff no longer does exact checking for content inside parenthesis (request #528)
+- Generic ScopeIndentSniff no longer does exact checking for content inside parenthesis (request [#528][sq-528])
     - Only applies to custom coding standards that set the "exact" flag to TRUE
-- Squiz ConcatenationSpacingSniff now has a setting to ignore newline characters around operators (request #511)
+- Squiz ConcatenationSpacingSniff now has a setting to ignore newline characters around operators (request [#511][sq-511])
     - Default remains FALSE, so newlines are not allowed
     - Override the "ignoreNewlines" setting in a ruleset.xml file to change
-- Squiz InlineCommentSniff no longer checks the last char of a comment if the first char is not a letter (request #505)
+- Squiz InlineCommentSniff no longer checks the last char of a comment if the first char is not a letter (request [#505][sq-505])
 - The Squiz standard has increased the max padding for statement alignment from 12 to 20
 
 ### Fixed
-- Fixed bug #479 : Yielded values are not recognised as returned values in Squiz FunctionComment sniff
-- Fixed bug #512 : Endless loop whilst parsing mixture of control structure styles
-- Fixed bug #515 : Spaces in JS block incorrectly flagged as indentation error
-- Fixed bug #523 : Generic ScopeIndent errors for IF in FINALLY
-- Fixed bug #527 : Closure inside IF statement is not tokenized correctly
-- Fixed bug #529 : Squiz.Strings.EchoedStrings gives false positive when echo'ing using an inline condition
-- Fixed bug #537 : Using --config-set is breaking phpcs.phar
-- Fixed bug #543 : SWITCH with closure in condition generates inline control structure error
-- Fixed bug #551 : Multiple catch blocks not checked in Squiz.ControlStructures.ControlSignature sniff
-- Fixed bug #554 : ScopeIndentSniff causes errors when encountering an unmatched parenthesis
-- Fixed bug #558 : PHPCBF adds brace for ELSE IF split over multiple lines
-- Fixed bug #564 : Generic MultipleStatementAlignment sniff reports incorrect errors for multiple assignments on a single line
+- Fixed bug [#479][sq-479] : Yielded values are not recognised as returned values in Squiz FunctionComment sniff
+- Fixed bug [#512][sq-512] : Endless loop whilst parsing mixture of control structure styles
+- Fixed bug [#515][sq-515] : Spaces in JS block incorrectly flagged as indentation error
+- Fixed bug [#523][sq-523] : Generic ScopeIndent errors for IF in FINALLY
+- Fixed bug [#527][sq-527] : Closure inside IF statement is not tokenized correctly
+- Fixed bug [#529][sq-529] : Squiz.Strings.EchoedStrings gives false positive when echoing using an inline condition
+- Fixed bug [#537][sq-537] : Using --config-set is breaking phpcs.phar
+- Fixed bug [#543][sq-543] : SWITCH with closure in condition generates inline control structure error
+- Fixed bug [#551][sq-551] : Multiple catch blocks not checked in Squiz.ControlStructures.ControlSignature sniff
+- Fixed bug [#554][sq-554] : ScopeIndentSniff causes errors when encountering an unmatched parenthesis
+- Fixed bug [#558][sq-558] : PHPCBF adds brace for ELSE IF split over multiple lines
+- Fixed bug [#564][sq-564] : Generic MultipleStatementAlignment sniff reports incorrect errors for multiple assignments on a single line
+
+[sq-479]: https://github.com/squizlabs/PHP_CodeSniffer/issues/479
+[sq-483]: https://github.com/squizlabs/PHP_CodeSniffer/issues/483
+[sq-505]: https://github.com/squizlabs/PHP_CodeSniffer/issues/505
+[sq-511]: https://github.com/squizlabs/PHP_CodeSniffer/issues/511
+[sq-512]: https://github.com/squizlabs/PHP_CodeSniffer/issues/512
+[sq-515]: https://github.com/squizlabs/PHP_CodeSniffer/issues/515
+[sq-523]: https://github.com/squizlabs/PHP_CodeSniffer/issues/523
+[sq-527]: https://github.com/squizlabs/PHP_CodeSniffer/issues/527
+[sq-528]: https://github.com/squizlabs/PHP_CodeSniffer/issues/528
+[sq-529]: https://github.com/squizlabs/PHP_CodeSniffer/issues/529
+[sq-537]: https://github.com/squizlabs/PHP_CodeSniffer/issues/537
+[sq-543]: https://github.com/squizlabs/PHP_CodeSniffer/issues/543
+[sq-551]: https://github.com/squizlabs/PHP_CodeSniffer/issues/551
+[sq-554]: https://github.com/squizlabs/PHP_CodeSniffer/issues/554
+[sq-558]: https://github.com/squizlabs/PHP_CodeSniffer/issues/558
+[sq-564]: https://github.com/squizlabs/PHP_CodeSniffer/issues/564
 
 ## [2.3.0] - 2015-03-04
+
 ### Changed
-- The existence of the main config file is now cached to reduce is_file() calls when it doesn't exist (request #486)
-- Abstract classes inside the Sniffs directory are now ignored even if they are named [Name]Sniff.php (request #476)
+- The existence of the main config file is now cached to reduce is_file() calls when it doesn't exist (request [#486][sq-486])
+- Abstract classes inside the Sniffs directory are now ignored even if they are named `[Name]Sniff.php` (request [#476][sq-476])
     - Thanks to [David Vernet][@Decave] for the patch
 - PEAR and Squiz FileComment sniffs no longer have @ in their error codes
     - e.g., PEAR.Commenting.FileComment.Duplicate@categoryTag becomes PEAR.Commenting.FileComment.DuplicateCategoryTag
     - e.g., Squiz.Commenting.FileComment.Missing@categoryTag becomes Squiz.Commenting.FileComment.MissingCategoryTag
 - PEAR MultiLineConditionSniff now allows comment lines inside multi-line IF statement conditions
     - Thanks to [Klaus Purer][@klausi] for the patch
-- Generic ForbiddenFunctionsSniff now supports setting null replacements in ruleset files (request #263)
+- Generic ForbiddenFunctionsSniff now supports setting null replacements in ruleset files (request [#263][sq-263])
 - Generic opening function brace sniffs now support checking of closures
     - Set the checkClosures property to TRUE (default is FALSE) in your ruleset.xml file to enable this
     - Can also set the checkFunctions property to FALSE (default is TRUE) in your ruleset.xml file to only check closures
@@ -3187,7 +4639,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Improved auto report width for the "full" report
 - Improved conflict detection during auto fixing
 - Generic ScopeIndentSniff is no longer confused by empty closures
-- Squiz ControlSignatureSniff now always ignores comments (fixes bug #490)
+- Squiz ControlSignatureSniff now always ignores comments (fixes bug [#490][sq-490])
     - Include the Squiz.Commenting.PostStatementComment sniff in your ruleset.xml to ban these comments again
 - Squiz OperatorSpacingSniff no longer throws errors for code in the form ($foo || -1 === $bar)
 - Fixed errors tokenizing T_ELSEIF tokens on HHVM 3.5
@@ -3195,26 +4647,46 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - PEAR IncludingFileSniff no longer produces invalid code when removing parenthesis from require/include statements
 
 ### Fixed
-- Fixed bug #415 : The @codingStandardsIgnoreStart has no effect during fixing
-- Fixed bug #432 : Properties of custom sniffs cannot be configured
-- Fixed bug #453 : PSR2 standard does not allow closing tag for mixed PHP/HTML files
-- Fixed bug #457 : FunctionCallSignature sniffs do not support here/nowdoc syntax and can cause syntax error when fixing
-- Fixed bug #466 : PropertyLabelSpacing JS fixer issue when there is no space after colon
-- Fixed bug #473 : Writing a report for an empty folder to existing file includes the existing contents
-- Fixed bug #485 : PHP notice in Squiz.Commenting.FunctionComment when checking malformed @throws comment
-- Fixed bug #491 : Generic InlineControlStructureSniff can correct with missing semicolon
+- Fixed bug [#415][sq-415] : The @codingStandardsIgnoreStart has no effect during fixing
+- Fixed bug [#432][sq-432] : Properties of custom sniffs cannot be configured
+- Fixed bug [#453][sq-453] : PSR2 standard does not allow closing tag for mixed PHP/HTML files
+- Fixed bug [#457][sq-457] : FunctionCallSignature sniffs do not support here/nowdoc syntax and can cause syntax error when fixing
+- Fixed bug [#466][sq-466] : PropertyLabelSpacing JS fixer issue when there is no space after colon
+- Fixed bug [#473][sq-473] : Writing a report for an empty folder to existing file includes the existing contents
+- Fixed bug [#485][sq-485] : PHP notice in Squiz.Commenting.FunctionComment when checking malformed @throws comment
+- Fixed bug [#491][sq-491] : Generic InlineControlStructureSniff can correct with missing semicolon
     - Thanks to [Jesse Donat][@donatj] for the patch
-- Fixed bug #492 : Use statements don't increase the scope indent
-- Fixed bug #493 : PSR1_Sniffs_Methods_CamelCapsMethodNameSniff false positives for some magic method detection
+- Fixed bug [#492][sq-492] : Use statements don't increase the scope indent
+- Fixed bug [#493][sq-493] : PSR1_Sniffs_Methods_CamelCapsMethodNameSniff false positives for some magic method detection
     - Thanks to [Andreas Möller][@localheinz] for the patch
-- Fixed bug #496 : Closures in PSR2 are not checked for a space after the function keyword
-- Fixed bug #497 : Generic InlineControlStructureSniff does not support alternative SWITCH syntax
-- Fixed bug #500 : Functions not supported as values in Squiz ArrayDeclaration sniff
-- Fixed bug #501 : ScopeClosingBrace and ScopeIndent conflict with closures used as array values
+- Fixed bug [#496][sq-496] : Closures in PSR2 are not checked for a space after the function keyword
+- Fixed bug [#497][sq-497] : Generic InlineControlStructureSniff does not support alternative SWITCH syntax
+- Fixed bug [#500][sq-500] : Functions not supported as values in Squiz ArrayDeclaration sniff
+- Fixed bug [#501][sq-501] : ScopeClosingBrace and ScopeIndent conflict with closures used as array values
     - Generic ScopeIndentSniff may now report fewer errors for closures, but perform the same fixes
-- Fixed bug #502 : PSR1 SideEffectsSniff sees declare() statements as side effects
+- Fixed bug [#502][sq-502] : PSR1 SideEffectsSniff sees declare() statements as side effects
+
+[sq-415]: https://github.com/squizlabs/PHP_CodeSniffer/issues/415
+[sq-432]: https://github.com/squizlabs/PHP_CodeSniffer/issues/432
+[sq-453]: https://github.com/squizlabs/PHP_CodeSniffer/issues/453
+[sq-457]: https://github.com/squizlabs/PHP_CodeSniffer/issues/457
+[sq-466]: https://github.com/squizlabs/PHP_CodeSniffer/issues/466
+[sq-473]: https://github.com/squizlabs/PHP_CodeSniffer/issues/473
+[sq-476]: https://github.com/squizlabs/PHP_CodeSniffer/issues/476
+[sq-485]: https://github.com/squizlabs/PHP_CodeSniffer/issues/485
+[sq-486]: https://github.com/squizlabs/PHP_CodeSniffer/issues/486
+[sq-490]: https://github.com/squizlabs/PHP_CodeSniffer/issues/490
+[sq-491]: https://github.com/squizlabs/PHP_CodeSniffer/pull/491
+[sq-492]: https://github.com/squizlabs/PHP_CodeSniffer/pull/492
+[sq-493]: https://github.com/squizlabs/PHP_CodeSniffer/pull/493
+[sq-496]: https://github.com/squizlabs/PHP_CodeSniffer/issues/496
+[sq-497]: https://github.com/squizlabs/PHP_CodeSniffer/issues/497
+[sq-500]: https://github.com/squizlabs/PHP_CodeSniffer/issues/500
+[sq-501]: https://github.com/squizlabs/PHP_CodeSniffer/issues/501
+[sq-502]: https://github.com/squizlabs/PHP_CodeSniffer/issues/502
 
 ## [2.2.0] - 2015-01-22
+
 ### Changed
 - Added (hopefully) tastefully used colors to report and progress output for the phpcs command
     - Use the --colors command line argument to use colors in output
@@ -3238,24 +4710,24 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - PHP and JS functions and closures are now treated the same way
 - Squiz MultiLineFunctionDeclarationSniff now supports JS files
 - Interactive mode no longer breaks if you also specify a report type on the command line
-- PEAR InlineCommentSniff now fixes the Perl-style comments that it finds (request #375)
+- PEAR InlineCommentSniff now fixes the Perl-style comments that it finds (request [#375][sq-375])
 - PSR2 standard no longer fixes the placement of docblock open tags as comments are excluded from this standard
 - PSR2 standard now sets a default tab width of 4 spaces
-- Generic DocCommentSniff now only disallows lowercase letters at the start of a long/short comment (request #377)
+- Generic DocCommentSniff now only disallows lowercase letters at the start of a long/short comment (request [#377][sq-377])
     - All non-letter characters are now allowed, including markdown special characters and numbers
-- Generic DisallowMultipleStatementsSniff now allows multiple open/close tags on the same line (request #423)
-- Generic CharacterBeforePHPOpeningTagSniff now only checks the first PHP tag it finds (request #423)
-- Generic CharacterBeforePHPOpeningTagSniff now allows a shebang line at the start of the file (request #20481)
-- Generic InlineHTMLUnitTest now allows a shebang line at the start of the file (request #20481)
+- Generic DisallowMultipleStatementsSniff now allows multiple open/close tags on the same line (request [#423][sq-423])
+- Generic CharacterBeforePHPOpeningTagSniff now only checks the first PHP tag it finds (request [#423][sq-423])
+- Generic CharacterBeforePHPOpeningTagSniff now allows a shebang line at the start of the file (request [#20481][pear-20481])
+- Generic InlineHTMLUnitTest now allows a shebang line at the start of the file (request [#20481][pear-20481])
 - PEAR ObjectOperatorIndentSniff now only checks object operators at the start of a line
 - PEAR FileComment and ClassComment sniffs no longer have @ in their error codes
     - E.g., PEAR.Commenting.FileComment.Missing@categoryTag becomes PEAR.Commenting.FileComment.MissingCategoryTag
     - Thanks to [Grzegorz Rygielski][@grzr] for the patch
 - Squiz ControlStructureSpacingSniff no longer enforces a blank line before CATCH statements
-- Squiz FunctionCommentSniff now fixes the return type in the @return tag (request #392)
+- Squiz FunctionCommentSniff now fixes the return type in the @return tag (request [#392][sq-392])
 - Squiz BlockCommentSniff now only disallows lowercase letters at the start of the comment
 - Squiz InlineCommentSniff now only disallows lowercase letters at the start of the comment
-- Squiz OperatorSpacingSniff now has a setting to ignore newline characters around operators (request #348)
+- Squiz OperatorSpacingSniff now has a setting to ignore newline characters around operators (request [#348][sq-348])
     - Default remains FALSE, so newlines are not allowed
     - Override the "ignoreNewlines" setting in a ruleset.xml file to change
 - PSR2 ControlStructureSpacingSniff now checks for, and fixes, newlines after the opening parenthesis
@@ -3263,28 +4735,53 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Stefano Kowalke][@Konafets] for the contribution
 
 ### Fixed
-- Fixed bug #379 : Squiz.Arrays.ArrayDeclaration.NoCommaAfterLast incorrectly detects comments
-- Fixed bug #382 : JS tokenizer incorrect for inline conditionally created immediately invoked anon function
-- Fixed bug #383 : Squiz.Arrays.ArrayDeclaration.ValueNoNewline incorrectly detects nested arrays
-- Fixed bug #386 : Undefined offset in Squiz.FunctionComment sniff when param has no comment
-- Fixed bug #390 : Indentation of non-control structures isn't adjusted when containing structure is fixed
-- Fixed bug #400 : InlineControlStructureSniff fails to fix when statement has no semicolon
-- Fixed bug #401 : PHPCBF no-patch option shows an error when there are no fixable violations in a file
-- Fixed bug #405 : The "Squiz.WhiteSpace.FunctionSpacing" sniff removes class "}" during fixing
-- Fixed bug #407 : PEAR.ControlStructures.MultiLineCondition doesn't account for comments at the end of lines
-- Fixed bug #410 : The "Squiz.WhiteSpace.MemberVarSpacing" not respecting "var"
-- Fixed bug #411 : Generic.WhiteSpace.ScopeIndent.Incorrect - false positive with multiple arrays in argument list
-- Fixed bug #412 : PSR2 multi-line detection doesn't work for inline IF and string concats
-- Fixed bug #414 : Squiz.WhiteSpace.MemberVarSpacing - inconsistent checking of member vars with comment
-- Fixed bug #433 : Wrong detection of Squiz.Arrays.ArrayDeclaration.KeyNotAligned when key contains space
-- Fixed bug #434 : False positive for spacing around "=>" in inline array within foreach
-- Fixed bug #452 : Ruleset exclude-pattern for specific sniff code ignored when using CLI --ignore option
-- Fixed bug #20482 : Scope indent sniff can get into infinite loop when processing a parse error
+- Fixed bug [#379][sq-379] : Squiz.Arrays.ArrayDeclaration.NoCommaAfterLast incorrectly detects comments
+- Fixed bug [#382][sq-382] : JS tokenizer incorrect for inline conditionally created immediately invoked anon function
+- Fixed bug [#383][sq-383] : Squiz.Arrays.ArrayDeclaration.ValueNoNewline incorrectly detects nested arrays
+- Fixed bug [#386][sq-386] : Undefined offset in Squiz.FunctionComment sniff when param has no comment
+- Fixed bug [#390][sq-390] : Indentation of non-control structures isn't adjusted when containing structure is fixed
+- Fixed bug [#400][sq-400] : InlineControlStructureSniff fails to fix when statement has no semicolon
+- Fixed bug [#401][sq-401] : PHPCBF no-patch option shows an error when there are no fixable violations in a file
+- Fixed bug [#405][sq-405] : The "Squiz.WhiteSpace.FunctionSpacing" sniff removes class "}" during fixing
+- Fixed bug [#407][sq-407] : PEAR.ControlStructures.MultiLineCondition doesn't account for comments at the end of lines
+- Fixed bug [#410][sq-410] : The "Squiz.WhiteSpace.MemberVarSpacing" not respecting "var"
+- Fixed bug [#411][sq-411] : Generic.WhiteSpace.ScopeIndent.Incorrect - false positive with multiple arrays in argument list
+- Fixed bug [#412][sq-412] : PSR2 multi-line detection doesn't work for inline IF and string concats
+- Fixed bug [#414][sq-414] : Squiz.WhiteSpace.MemberVarSpacing - inconsistent checking of member vars with comment
+- Fixed bug [#433][sq-433] : Wrong detection of Squiz.Arrays.ArrayDeclaration.KeyNotAligned when key contains space
+- Fixed bug [#434][sq-434] : False positive for spacing around "=>" in inline array within foreach
+- Fixed bug [#452][sq-452] : Ruleset exclude-pattern for specific sniff code ignored when using CLI --ignore option
+- Fixed bug [#20482][pear-20482] : Scope indent sniff can get into infinite loop when processing a parse error
+
+[sq-348]: https://github.com/squizlabs/PHP_CodeSniffer/issues/348
+[sq-375]: https://github.com/squizlabs/PHP_CodeSniffer/issues/375
+[sq-377]: https://github.com/squizlabs/PHP_CodeSniffer/issues/377
+[sq-379]: https://github.com/squizlabs/PHP_CodeSniffer/issues/379
+[sq-382]: https://github.com/squizlabs/PHP_CodeSniffer/issues/382
+[sq-383]: https://github.com/squizlabs/PHP_CodeSniffer/issues/383
+[sq-386]: https://github.com/squizlabs/PHP_CodeSniffer/issues/386
+[sq-390]: https://github.com/squizlabs/PHP_CodeSniffer/issues/390
+[sq-392]: https://github.com/squizlabs/PHP_CodeSniffer/issues/392
+[sq-400]: https://github.com/squizlabs/PHP_CodeSniffer/issues/400
+[sq-401]: https://github.com/squizlabs/PHP_CodeSniffer/issues/401
+[sq-405]: https://github.com/squizlabs/PHP_CodeSniffer/issues/405
+[sq-407]: https://github.com/squizlabs/PHP_CodeSniffer/issues/407
+[sq-410]: https://github.com/squizlabs/PHP_CodeSniffer/issues/410
+[sq-411]: https://github.com/squizlabs/PHP_CodeSniffer/issues/411
+[sq-412]: https://github.com/squizlabs/PHP_CodeSniffer/issues/412
+[sq-414]: https://github.com/squizlabs/PHP_CodeSniffer/issues/414
+[sq-423]: https://github.com/squizlabs/PHP_CodeSniffer/issues/423
+[sq-433]: https://github.com/squizlabs/PHP_CodeSniffer/issues/433
+[sq-434]: https://github.com/squizlabs/PHP_CodeSniffer/issues/434
+[sq-452]: https://github.com/squizlabs/PHP_CodeSniffer/issues/452
+[pear-20481]: https://pear.php.net/bugs/bug.php?id=20481
+[pear-20482]: https://pear.php.net/bugs/bug.php?id=20482
 
 ## [2.1.0] - 2014-12-18
+
 ### Changed
-- Time and memory output is now shown if progress information is also shown (request #335)
-- A tilde can now be used to reference a user's home directory in a path to a standard (request #353)
+- Time and memory output is now shown if progress information is also shown (request [#335][sq-335])
+- A tilde can now be used to reference a user's home directory in a path to a standard (request [#353][sq-353])
 - Added PHP_CodeSniffer_File::findStartOfStatement() to find the first non-whitespace token in a statement
     - Possible alternative for code using PHP_CodeSniffer_File::findPrevious() with the local flag set
 - Added PHP_CodeSniffer_File::findEndOfStatement() to find the last non-whitespace token in a statement
@@ -3293,17 +4790,17 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Affects OpeningFunctionBraceBsdAllmanSniff and OpeningFunctionBraceKernighanRitchieSniff
     - Also enforced in PEAR FunctionDeclarationSniff and Squiz MultiLineFunctionDeclarationSniff
 - Generic DisallowTabIndentSniff now replaces tabs everywhere it finds them, except in strings and here/now docs
-- Generic EmptyStatementSniff error codes now contain the type of empty statement detected (request #314)
+- Generic EmptyStatementSniff error codes now contain the type of empty statement detected (request [#314][sq-314])
     - All messages generated by this sniff are now errors (empty CATCH was previously a warning)
-    - Message code Generic.CodeAnalysis.EmptyStatement.NotAllowed has been removed
-    - Message code Generic.CodeAnalysis.EmptyStatement.NotAllowedWarning has been removed
-    - New message codes have the format Generic.CodeAnalysis.EmptyStatement.Detected[TYPE]
-    - Example code is Generic.CodeAnalysis.EmptyStatement.DetectedCATCH
+    - Message code `Generic.CodeAnalysis.EmptyStatement.NotAllowed` has been removed
+    - Message code `Generic.CodeAnalysis.EmptyStatement.NotAllowedWarning` has been removed
+    - New message codes have the format `Generic.CodeAnalysis.EmptyStatement.Detected[TYPE]`
+    - Example code is `Generic.CodeAnalysis.EmptyStatement.DetectedCATCH`
     - You can now use a custom ruleset to change messages to warnings and to exclude them
-- PEAR and Squiz FunctionCommentSniffs no longer ban @return tags for constructors and destructors
+- PEAR and Squiz FunctionCommentSniffs no longer ban `@return` tags for constructors and destructors
     - Removed message PEAR.Commenting.FunctionComment.ReturnNotRequired
     - Removed message Squiz.Commenting.FunctionComment.ReturnNotRequired
-    - Change initiated by request #324 and request #369
+    - Change initiated by request [#324][sq-324] and request [#369][sq-369]
 - Squiz EmptyStatementSniff has been removed
     - Squiz standard now includes Generic EmptyStatementSniff and turns off the empty CATCH error
 - Squiz ControlSignatureSniff fixes now retain comments between the closing parenthesis and open brace
@@ -3312,23 +4809,44 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Squiz ArrayDeclarationSniff now skips function calls while checking multi-line arrays
 
 ### Fixed
-- Fixed bug #337 : False positive with anonymous functions in Generic_Sniffs_WhiteSpace_ScopeIndentSniff
-- Fixed bug #339 : reformatting brace location can result in broken code
-- Fixed bug #342 : Nested ternary operators not tokenized correctly
-- Fixed bug #345 : Javascript regex not tokenized when inside array
-- Fixed bug #346 : PHP path can't be determined in some cases in "phpcs.bat" (on Windows XP)
-- Fixed bug #358 : False positives for Generic_Sniffs_WhiteSpace_ScopeIndentSniff
-- Fixed bug #361 : Sniff-specific exclude patterns don't work for Windows
-- Fixed bug #364 : Don't interpret "use function" as declaration
-- Fixed bug #366 : phpcbf with PSR2 errors on control structure alternative syntax
-- Fixed bug #367 : Nested Anonymous Functions Causing False Negative
-- Fixed bug #371 : Shorthand binary cast causes tokenizer errors
+- Fixed bug [#337][sq-337] : False positive with anonymous functions in Generic_Sniffs_WhiteSpace_ScopeIndentSniff
+- Fixed bug [#339][sq-339] : reformatting brace location can result in broken code
+- Fixed bug [#342][sq-342] : Nested ternary operators not tokenized correctly
+- Fixed bug [#345][sq-345] : Javascript regex not tokenized when inside array
+- Fixed bug [#346][sq-346] : PHP path can't be determined in some cases in "phpcs.bat" (on Windows XP)
+- Fixed bug [#358][sq-358] : False positives for Generic_Sniffs_WhiteSpace_ScopeIndentSniff
+- Fixed bug [#361][sq-361] : Sniff-specific exclude patterns don't work for Windows
+- Fixed bug [#364][sq-364] : Don't interpret "use function" as declaration
+- Fixed bug [#366][sq-366] : phpcbf with PSR2 errors on control structure alternative syntax
+- Fixed bug [#367][sq-367] : Nested Anonymous Functions Causing False Negative
+- Fixed bug [#371][sq-371] : Shorthand binary cast causes tokenizer errors
     - New token T_BINARY_CAST added for the b"string" cast format (the 'b' is the T_BINARY_CAST token)
-- Fixed bug #372 : phpcbf parse problem, wrong brace placement for inline IF
-- Fixed bug #373 : Double quote usage fix removing too many double quotes
-- Fixed bug #20196 : 1.5.2 breaks scope_closer position
+- Fixed bug [#372][sq-372] : phpcbf parse problem, wrong brace placement for inline IF
+- Fixed bug [#373][sq-373] : Double quote usage fix removing too many double quotes
+- Fixed bug [#20196][pear-20196] : 1.5.2 breaks scope_closer position
+
+[sq-314]: https://github.com/squizlabs/PHP_CodeSniffer/issues/314
+[sq-324]: https://github.com/squizlabs/PHP_CodeSniffer/issues/324
+[sq-335]: https://github.com/squizlabs/PHP_CodeSniffer/issues/335
+[sq-337]: https://github.com/squizlabs/PHP_CodeSniffer/issues/337
+[sq-339]: https://github.com/squizlabs/PHP_CodeSniffer/issues/339
+[sq-342]: https://github.com/squizlabs/PHP_CodeSniffer/issues/342
+[sq-345]: https://github.com/squizlabs/PHP_CodeSniffer/issues/345
+[sq-346]: https://github.com/squizlabs/PHP_CodeSniffer/issues/346
+[sq-353]: https://github.com/squizlabs/PHP_CodeSniffer/issues/353
+[sq-358]: https://github.com/squizlabs/PHP_CodeSniffer/issues/358
+[sq-361]: https://github.com/squizlabs/PHP_CodeSniffer/issues/361
+[sq-364]: https://github.com/squizlabs/PHP_CodeSniffer/pull/364
+[sq-366]: https://github.com/squizlabs/PHP_CodeSniffer/issues/366
+[sq-367]: https://github.com/squizlabs/PHP_CodeSniffer/issues/367
+[sq-369]: https://github.com/squizlabs/PHP_CodeSniffer/issues/369
+[sq-371]: https://github.com/squizlabs/PHP_CodeSniffer/issues/371
+[sq-372]: https://github.com/squizlabs/PHP_CodeSniffer/issues/372
+[sq-373]: https://github.com/squizlabs/PHP_CodeSniffer/issues/373
+[pear-20196]: https://pear.php.net/bugs/bug.php?id=20196
 
 ## [2.0.0] - 2014-12-05
+
 ### Changed
 - JS tokenizer now sets functions as T_CLOSUREs if the function is anonymous
 - JS tokenizer now sets all objects to T_OBJECT
@@ -3358,11 +4876,15 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Improved fixing of lines after cases statements in Squiz SwitchDeclarationSniff
 
 ### Fixed
-- Fixed bug #311 : Suppression of function prototype breaks checking of lines within function
-- Fixed bug #320 : Code sniffer indentation issue
-- Fixed bug #333 : Nested ternary operators causing problems
+- Fixed bug [#311][sq-311] : Suppression of function prototype breaks checking of lines within function
+- Fixed bug [#320][sq-320] : Code sniffer indentation issue
+- Fixed bug [#333][sq-333] : Nested ternary operators causing problems
+
+[sq-320]: https://github.com/squizlabs/PHP_CodeSniffer/issues/320
+[sq-333]: https://github.com/squizlabs/PHP_CodeSniffer/issues/333
 
 ## [1.5.6] - 2014-12-05
+
 ### Changed
 - JS tokenizer now detects xor statements correctly
 - The --config-show command now pretty-prints the config values
@@ -3377,13 +4899,16 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Thibaud Fabre][@fabre-thibaud] for the patch
 
 ### Fixed
-- Fixed bug #280 : The --config-show option generates error when there is no config file
-- Fixed bug #306 : File containing only a namespace declaration raises undefined index notice
-- Fixed bug #308 : Squiz InlineIfDeclarationSniff fails on ternary operators inside closure
-- Fixed bug #310 : Variadics not recognized by tokenizer
-- Fixed bug #311 : Suppression of function prototype breaks checking of lines within function
+- Fixed bug [#280][sq-280] : The --config-show option generates error when there is no config file
+- Fixed bug [#306][sq-306] : File containing only a namespace declaration raises undefined index notice
+- Fixed bug [#308][sq-308] : Squiz InlineIfDeclarationSniff fails on ternary operators inside closure
+- Fixed bug [#310][sq-310] : Variadics not recognized by tokenizer
+- Fixed bug [#311][sq-311] : Suppression of function prototype breaks checking of lines within function
+
+[sq-311]: https://github.com/squizlabs/PHP_CodeSniffer/issues/311
 
 ## [2.0.0RC4] - 2014-11-07
+
 ### Changed
 - JS tokenizer now detects xor statements correctly
 - Improved detection of properties and objects in the JS tokenizer
@@ -3407,16 +4932,26 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Running unit tests with the -v CLI argument no longer generates PHP errors
 
 ### Fixed
-- Fixed bug #295 : ScopeIndentSniff hangs when processing nested closures
-- Fixed bug #298 : False positive in ScopeIndentSniff when anonymous functions are used with method chaining
-- Fixed bug #302 : Fixing code in Squiz InlineComment sniff can remove some comment text
-- Fixed bug #303 : Open and close tag on same line can cause a PHP notice checking scope indent
-- Fixed bug #306 : File containing only a namespace declaration raises undefined index notice
-- Fixed bug #307 : Conditional breaks in case statements get incorrect indentations
-- Fixed bug #308 : Squiz InlineIfDeclarationSniff fails on ternary operators inside closure
-- Fixed bug #310 : Variadics not recognized by tokenizer
+- Fixed bug [#295][sq-295] : ScopeIndentSniff hangs when processing nested closures
+- Fixed bug [#298][sq-298] : False positive in ScopeIndentSniff when anonymous functions are used with method chaining
+- Fixed bug [#302][sq-302] : Fixing code in Squiz InlineComment sniff can remove some comment text
+- Fixed bug [#303][sq-303] : Open and close tag on same line can cause a PHP notice checking scope indent
+- Fixed bug [#306][sq-306] : File containing only a namespace declaration raises undefined index notice
+- Fixed bug [#307][sq-307] : Conditional breaks in case statements get incorrect indentations
+- Fixed bug [#308][sq-308] : Squiz InlineIfDeclarationSniff fails on ternary operators inside closure
+- Fixed bug [#310][sq-310] : Variadics not recognized by tokenizer
+
+[sq-295]: https://github.com/squizlabs/PHP_CodeSniffer/issues/295
+[sq-298]: https://github.com/squizlabs/PHP_CodeSniffer/issues/298
+[sq-302]: https://github.com/squizlabs/PHP_CodeSniffer/issues/302
+[sq-303]: https://github.com/squizlabs/PHP_CodeSniffer/issues/303
+[sq-306]: https://github.com/squizlabs/PHP_CodeSniffer/issues/306
+[sq-307]: https://github.com/squizlabs/PHP_CodeSniffer/issues/307
+[sq-308]: https://github.com/squizlabs/PHP_CodeSniffer/issues/308
+[sq-310]: https://github.com/squizlabs/PHP_CodeSniffer/issues/310
 
 ## [2.0.0RC3] - 2014-10-16
+
 ### Changed
 - Improved default output for PHPCBF and removed the options to print verbose and progress output
 - If a .fixed file is supplied for a unit test file, the auto fixes will be checked against it during testing
@@ -3435,26 +4970,30 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Squiz EmbeddedPhpSniff now checks open and close tag indents and fixes some errors
 - Squiz FileCommentSniff no longer throws incorrect blank line before comment errors in JS files
 - Squiz ClassDeclarationSniff now has better checking for blank lines after a closing brace
-- Removed error Squiz.Classes.ClassDeclaration.NoNewlineAfterCloseBrace (request #285)
+- Removed error Squiz.Classes.ClassDeclaration.NoNewlineAfterCloseBrace (request [#285][sq-285])
     - Already handled by Squiz.Classes.ClassDeclaration.CloseBraceSameLine
 
 ### Fixed
-- Fixed bug #280 : The --config-show option generates error when there is no config file
+- Fixed bug [#280][sq-280] : The --config-show option generates error when there is no config file
+
+[sq-280]: https://github.com/squizlabs/PHP_CodeSniffer/issues/280
+[sq-285]: https://github.com/squizlabs/PHP_CodeSniffer/issues/285
 
 ## [2.0.0RC2] - 2014-09-26
+
 ### Changed
-- Minified JS and CSS files are now detected and skipped (fixes bug #252 and bug #19899)
+- Minified JS and CSS files are now detected and skipped (fixes bug [#252][sq-252] and bug [#19899][pear-19899])
     - A warning will be added to the file so it can be found in the report and ignored in the future
 - Fixed incorrect length of JS object operator tokens
 - PHP tokenizer no longer converts class/function names to special tokens types
     - Class/function names such as parent and true would become special tokens such as T_PARENT and T_TRUE
-- PHPCS can now exit with 0 if only warnings were found (request #262)
+- PHPCS can now exit with 0 if only warnings were found (request [#262][sq-262])
     - Set the ignore_warnings_on_exit config variable to 1 to set this behaviour
     - Default remains at exiting with 0 only if no errors and no warnings were found
     - Also changes return value of PHP_CodeSniffer_Reporting::printReport()
 - Rulesets can now set associative array properties
-    - property name="[property]" type="array" value="foo=>bar,baz=>qux"
-- Generic ForbiddenFunctionsSniff now has a public property called forbiddenFunctions (request #263)
+    - property `name="[property]" type="array" value="foo=>bar,baz=>qux"`
+- Generic ForbiddenFunctionsSniff now has a public property called forbiddenFunctions (request [#263][sq-263])
     - Override the property in a ruleset.xml file to define forbidden functions and their replacements
     - A replacement of NULL indicates that no replacement is available
     - e.g., value="delete=>unset,print=>echo,create_function=>null"
@@ -3466,14 +5005,14 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - If 2 sniffs look to be conflicting, one change will be ignored to allow a fix to occur
 - Generic CamelCapsFunctionNameSniff now ignores a single leading underscore
     - Thanks to [Alex Slobodiskiy][@xt99] for the patch
-- Standards can now be located within hidden directories (further fix for bug #20323)
+- Standards can now be located within hidden directories (further fix for bug [#20323][pear-20323])
     - Thanks to [Klaus Purer][@klausi] for the patch
 - Sniff ignore patterns now replace Win dir separators like file ignore patterns already did
 - Exclude patterns now use backtick delimiters, allowing all special characters to work correctly again
     - Thanks to [Jeremy Edgell][@jedgell] for the patch
 - Errors converted to warnings in a ruleset (and vice versa) now retain their fixable status
     - Thanks to [Alexander Obuhovich][@aik099] for the patch
-- Squiz ConcatenationSpacingSniff now has a setting to specify how many spaces there should around concat operators
+- Squiz ConcatenationSpacingSniff now has a setting to specify how many spaces there should be around concat operators
     - Default remains at 0
     - Override the "spacing" setting in a ruleset.xml file to change
 - Added auto-fixes for Squiz InlineCommentSniff
@@ -3491,17 +5030,26 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Generic UpperCaseConstantSniff and LowerCaseConstantSniff now ignore function names
 
 ### Fixed
-- Fixed bug #243 : Missing DocBlock not detected
-- Fixed bug #248 : FunctionCommentSniff expects ampersand on param name
-- Fixed bug #265 : False positives with type hints in ForbiddenFunctionsSniff
-- Fixed bug #20373 : Inline comment sniff tab handling way
-- Fixed bug #20377 : Error when trying to execute phpcs with report=json
-- Fixed bug #20378 : Report appended to existing file if no errors found in run
-- Fixed bug #20381 : Invalid "Comment closer must be on a new line"
+- Fixed bug [#243][sq-243] : Missing DocBlock not detected
+- Fixed bug [#248][sq-248] : FunctionCommentSniff expects ampersand on param name
+- Fixed bug [#265][sq-265] : False positives with type hints in ForbiddenFunctionsSniff
+- Fixed bug [#20373][pear-20373] : Inline comment sniff tab handling way
+- Fixed bug [#20377][pear-20377] : Error when trying to execute phpcs with report=json
+- Fixed bug [#20378][pear-20378] : Report appended to existing file if no errors found in run
+- Fixed bug [#20381][pear-20381] : Invalid "Comment closer must be on a new line"
     - Thanks to [Brad Kent][@bkdotcom] for the patch
-- Fixed bug #20402 : SVN pre-commit hook fails due to unknown argument error
+- Fixed bug [#20402][pear-20402] : SVN pre-commit hook fails due to unknown argument error
+
+[sq-243]: https://github.com/squizlabs/PHP_CodeSniffer/issues/243
+[sq-252]: https://github.com/squizlabs/PHP_CodeSniffer/issues/252
+[sq-262]: https://github.com/squizlabs/PHP_CodeSniffer/issues/262
+[sq-263]: https://github.com/squizlabs/PHP_CodeSniffer/issues/263
+[pear-19899]: https://pear.php.net/bugs/bug.php?id=19899
+[pear-20377]: https://pear.php.net/bugs/bug.php?id=20377
+[pear-20402]: https://pear.php.net/bugs/bug.php?id=20402
 
 ## [1.5.5] - 2014-09-25
+
 ### Changed
 - PHP tokenizer no longer converts class/function names to special tokens types
     - Class/function names such as parent and true would become special tokens such as T_PARENT and T_TRUE
@@ -3509,7 +5057,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Improved indented PHP tag support in Generic ScopeIndentSniff
 - Generic CamelCapsFunctionNameSniff now ignores a single leading underscore
     - Thanks to [Alex Slobodiskiy][@xt99] for the patch
-- Standards can now be located within hidden directories (further fix for bug #20323)
+- Standards can now be located within hidden directories (further fix for bug [#20323][pear-20323])
     - Thanks to [Klaus Purer][@klausi] for the patch
 - Added Generic SyntaxSniff to check for syntax errors in PHP files
     - Thanks to [Blaine Schmeisser][@bayleedev] for the contribution
@@ -3519,18 +5067,26 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Generic UpperCaseConstantSniff and LowerCaseConstantSniff now ignore function names
 
 ### Fixed
-- Fixed bug #248 : FunctionCommentSniff expects ampersand on param name
-- Fixed bug #265 : False positives with type hints in ForbiddenFunctionsSniff
-- Fixed bug #20373 : Inline comment sniff tab handling way
-- Fixed bug #20378 : Report appended to existing file if no errors found in run
-- Fixed bug #20381 : Invalid "Comment closer must be on a new line"
+- Fixed bug [#248][sq-248] : FunctionCommentSniff expects ampersand on param name
+- Fixed bug [#265][sq-265] : False positives with type hints in ForbiddenFunctionsSniff
+- Fixed bug [#20373][pear-20373] : Inline comment sniff tab handling way
+- Fixed bug [#20378][pear-20378] : Report appended to existing file if no errors found in run
+- Fixed bug [#20381][pear-20381] : Invalid "Comment closer must be on a new line"
     - Thanks to [Brad Kent][@bkdotcom] for the patch
-- Fixed bug #20386 : Squiz.Commenting.ClassComment.SpacingBefore thrown if first block comment
+- Fixed bug [#20386][pear-20386] : Squiz.Commenting.ClassComment.SpacingBefore thrown if first block comment
+
+[sq-248]: https://github.com/squizlabs/PHP_CodeSniffer/issues/248
+[sq-265]: https://github.com/squizlabs/PHP_CodeSniffer/pull/265
+[pear-20373]: https://pear.php.net/bugs/bug.php?id=20373
+[pear-20378]: https://pear.php.net/bugs/bug.php?id=20378
+[pear-20381]: https://pear.php.net/bugs/bug.php?id=20381
+[pear-20386]: https://pear.php.net/bugs/bug.php?id=20386
 
 ## [2.0.0RC1] - 2014-08-06
+
 ### Changed
 - PHPCBF will now fix incorrect newline characters in a file
-- PHPCBF now exists cleanly when there are no errors to fix
+- PHPCBF now exits cleanly when there are no errors to fix
 - Added phpcbf.bat file for Windows
 - Verbose option no longer errors when using a phar file with a space in the path
 - Fixed a reporting error when using HHVM
@@ -3548,7 +5104,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - The filtering component of the --extensions argument is now ignored again when passing filenames
     - Can still be used to specify a custom tokenizer for each extension when passing filenames
     - If no tokenizer is specified, default values will be used for common file extensions
-- Diff report now produces relative paths on Windows, where possible (further fix for bug #20234)
+- Diff report now produces relative paths on Windows, where possible (further fix for bug [#20234][pear-20234])
 - If a token's content has been modified by the tab-width setting, it will now have an orig_content in the tokens array
 - Generic DisallowSpaceIndent and DisallowTabIndent sniffs now check original indent content even when tab-width is set
     - Previously, setting --tab-width would force both to check the indent as spaces
@@ -3572,31 +5128,37 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Ole Martin Handeland][@olemartinorg] for the patch
 - Generic LowerCaseConstantSniff and UpperCaseConstantSniff now ignore namespaces beginning with TRUE/FALSE/NULL
     - Thanks to [Renan Gonçalves][@renan] for the patch
-- Squiz InlineCommentSniff no longer requires a blank line after post-statement comments (request #20299)
+- Squiz InlineCommentSniff no longer requires a blank line after post-statement comments (request [#20299][pear-20299])
 - Squiz SelfMemberReferenceSniff now works correctly with namespaces
 - Squiz FunctionCommentSniff is now more relaxed when checking namespaced type hints
-- Tab characters are now encoded in abstract pattern errors messages
+- Tab characters are now encoded in abstract pattern error messages
     - Thanks to [Blaine Schmeisser][@bayleedev] for the patch
-- Invalid sniff codes passed to --sniffs now show a friendly error message (request #20313)
-- Generic LineLengthSniff now shows a warning if the iconv module is disabled (request #20314)
+- Invalid sniff codes passed to --sniffs now show a friendly error message (request [#20313][pear-20313])
+- Generic LineLengthSniff now shows a warning if the iconv module is disabled (request [#20314][pear-20314])
 - Source report no longer shows errors if category or sniff names ends in an uppercase error
     - Thanks to [Jonathan Marcil][@jmarcil] for the patch
 
 ### Fixed
-- Fixed bug #20261 : phpcbf has an endless fixing loop
-- Fixed bug #20268 : Incorrect documentation titles in PEAR documentation
-- Fixed bug #20296 : new array notion in function comma check fails
-- Fixed bug #20297 : phar does not work when renamed it to phpcs
-- Fixed bug #20307 : PHP_CodeSniffer_Standards_AbstractVariableSniff analyze traits
-- Fixed bug #20308 : Squiz.ValidVariableNameSniff - wrong variable usage
-- Fixed bug #20309 : Use "member variable" term in sniff "processMemberVar" method
-- Fixed bug #20310 : PSR2 does not check for space after function name
-- Fixed bug #20322 : Display rules set to type=error even when suppressing warnings
-- Fixed bug #20323 : PHPCS tries to load sniffs from hidden directories
-- Fixed bug #20346 : Fixer endless loop with Squiz.CSS sniffs
-- Fixed bug #20355 : No sniffs are registered with PHAR on Windows
+- Fixed bug [#20261][pear-20261] : phpcbf has an endless fixing loop
+- Fixed bug [#20268][pear-20268] : Incorrect documentation titles in PEAR documentation
+- Fixed bug [#20296][pear-20296] : new array notion in function comma check fails
+- Fixed bug [#20297][pear-20297] : phar does not work when renamed it to phpcs
+- Fixed bug [#20307][pear-20307] : PHP_CodeSniffer_Standards_AbstractVariableSniff analyze traits
+- Fixed bug [#20308][pear-20308] : Squiz.ValidVariableNameSniff - wrong variable usage
+- Fixed bug [#20309][pear-20309] : Use "member variable" term in sniff "processMemberVar" method
+- Fixed bug [#20310][pear-20310] : PSR2 does not check for space after function name
+- Fixed bug [#20322][pear-20322] : Display rules set to type=error even when suppressing warnings
+- Fixed bug [#20323][pear-20323] : PHPCS tries to load sniffs from hidden directories
+- Fixed bug [#20346][pear-20346] : Fixer endless loop with Squiz.CSS sniffs
+- Fixed bug [#20355][pear-20355] : No sniffs are registered with PHAR on Windows
+
+[pear-20261]: https://pear.php.net/bugs/bug.php?id=20261
+[pear-20297]: https://pear.php.net/bugs/bug.php?id=20297
+[pear-20346]: https://pear.php.net/bugs/bug.php?id=20346
+[pear-20355]: https://pear.php.net/bugs/bug.php?id=20355
 
 ## [1.5.4] - 2014-08-06
+
 ### Changed
 - Removed use of sys_get_temp_dir() as this is not supported by the min PHP version
 - The installed_paths config var now accepts relative paths
@@ -3611,26 +5173,39 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Ole Martin Handeland][@olemartinorg] for the patch
 - Generic LowerCaseConstantSniff and UpperCaseConstantSniff now ignore namespaces beginning with TRUE/FALSE/NULL
     - Thanks to [Renan Gonçalves][@renan] for the patch
-- Squiz InlineCommentSniff no longer requires a blank line after post-statement comments (request #20299)
+- Squiz InlineCommentSniff no longer requires a blank line after post-statement comments (request [#20299][pear-20299])
 - Squiz SelfMemberReferenceSniff now works correctly with namespaces
-- Tab characters are now encoded in abstract pattern errors messages
+- Tab characters are now encoded in abstract pattern error messages
     - Thanks to [Blaine Schmeisser][@bayleedev] for the patch
-- Invalid sniff codes passed to --sniffs now show a friendly error message (request #20313)
-- Generic LineLengthSniff now shows a warning if the iconv module is disabled (request #20314)
+- Invalid sniff codes passed to --sniffs now show a friendly error message (request [#20313][pear-20313])
+- Generic LineLengthSniff now shows a warning if the iconv module is disabled (request [#20314][pear-20314])
 - Source report no longer shows errors if category or sniff names ends in an uppercase error
     - Thanks to [Jonathan Marcil][@jmarcil] for the patch
 
 ### Fixed
-- Fixed bug #20268 : Incorrect documentation titles in PEAR documentation
-- Fixed bug #20296 : new array notion in function comma check fails
-- Fixed bug #20307 : PHP_CodeSniffer_Standards_AbstractVariableSniff analyze traits
-- Fixed bug #20308 : Squiz.ValidVariableNameSniff - wrong variable usage
-- Fixed bug #20309 : Use "member variable" term in sniff "processMemberVar" method
-- Fixed bug #20310 : PSR2 does not check for space after function name
-- Fixed bug #20322 : Display rules set to type=error even when suppressing warnings
-- Fixed bug #20323 : PHPCS tries to load sniffs from hidden directories
+- Fixed bug [#20268][pear-20268] : Incorrect documentation titles in PEAR documentation
+- Fixed bug [#20296][pear-20296] : new array notion in function comma check fails
+- Fixed bug [#20307][pear-20307] : PHP_CodeSniffer_Standards_AbstractVariableSniff analyze traits
+- Fixed bug [#20308][pear-20308] : Squiz.ValidVariableNameSniff - wrong variable usage
+- Fixed bug [#20309][pear-20309] : Use "member variable" term in sniff "processMemberVar" method
+- Fixed bug [#20310][pear-20310] : PSR2 does not check for space after function name
+- Fixed bug [#20322][pear-20322] : Display rules set to type=error even when suppressing warnings
+- Fixed bug [#20323][pear-20323] : PHPCS tries to load sniffs from hidden directories
+
+[pear-20268]: https://pear.php.net/bugs/bug.php?id=20268
+[pear-20296]: https://pear.php.net/bugs/bug.php?id=20296
+[pear-20299]: https://pear.php.net/bugs/bug.php?id=20299
+[pear-20307]: https://pear.php.net/bugs/bug.php?id=20307
+[pear-20308]: https://pear.php.net/bugs/bug.php?id=20308
+[pear-20309]: https://pear.php.net/bugs/bug.php?id=20309
+[pear-20310]: https://pear.php.net/bugs/bug.php?id=20310
+[pear-20313]: https://pear.php.net/bugs/bug.php?id=20313
+[pear-20314]: https://pear.php.net/bugs/bug.php?id=20314
+[pear-20322]: https://pear.php.net/bugs/bug.php?id=20322
+[pear-20323]: https://pear.php.net/bugs/bug.php?id=20323
 
 ## [2.0.0a2] - 2014-05-01
+
 ### Changed
 - Added report type --report=info to show information about the checked code to make building a standard easier
     - Checks a number of things, such as what line length you use, and spacing are brackets, but not everything
@@ -3654,7 +5229,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - PSR1 CamelCapsMethodNameSniff now ignores magic methods
     - Thanks to [Eser Ozvataf][@eser] for the patch
 - PSR1 SideEffectsSniff now ignores methods named define()
-- PSR1 and PEAR ClassDeclarationSniffs now support traits (request #20208)
+- PSR1 and PEAR ClassDeclarationSniffs now support traits (request [#20208][pear-20208])
 - PSR2 ControlStructureSpacingSniff now allows newlines before/after parentheses
     - Thanks to [Maurus Cuelenaere][@mcuelenaere] for the patch
 - PSR2 ControlStructureSpacingSniff now checks TRY and CATCH statements
@@ -3665,29 +5240,32 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Squiz SwitchDeclarationSniff now allows exit() as a breaking statement for case/default
 - Squiz ValidVariableNameSniff and Zend ValidVariableNameSniff now ignore additional PHP reserved vars
     - Thanks to Mikuláš Dítě and Adrian Crepaz for the patch
-- Sniff code Squiz.WhiteSpace.MemberVarSpacing.After changed to Squiz.WhiteSpace.MemberVarSpacing.Incorrect (request #20241)
+- Sniff code Squiz.WhiteSpace.MemberVarSpacing.After changed to Squiz.WhiteSpace.MemberVarSpacing.Incorrect (request [#20241][pear-20241])
 
 ### Fixed
-- Fixed bug #20200 : Invalid JSON produced with specific error message
-- Fixed bug #20204 : Ruleset exclude checks are case sensitive
-- Fixed bug #20213 : Invalid error, Inline IF must be declared on single line
-- Fixed bug #20225 : array_merge() that takes more than one line generates error
-- Fixed bug #20230 : Squiz ControlStructureSpacing sniff assumes specific condition formatting
-- Fixed bug #20234 : phpcbf patch command absolute paths
-- Fixed bug #20240 : Squiz block comment sniff fails when newline present
-- Fixed bug #20247 : The Squiz.WhiteSpace.ControlStructureSpacing sniff and do-while
+- Fixed bug [#20200][pear-20200] : Invalid JSON produced with specific error message
+- Fixed bug [#20204][pear-20204] : Ruleset exclude checks are case sensitive
+- Fixed bug [#20213][pear-20213] : Invalid error, Inline IF must be declared on single line
+- Fixed bug [#20225][pear-20225] : array_merge() that takes more than one line generates error
+- Fixed bug [#20230][pear-20230] : Squiz ControlStructureSpacing sniff assumes specific condition formatting
+- Fixed bug [#20234][pear-20234] : phpcbf patch command absolute paths
+- Fixed bug [#20240][pear-20240] : Squiz block comment sniff fails when newline present
+- Fixed bug [#20247][pear-20247] : The Squiz.WhiteSpace.ControlStructureSpacing sniff and do-while
     - Thanks to [Alexander Obuhovich][@aik099] for the patch
-- Fixed bug #20248 : The Squiz_Sniffs_WhiteSpace_ControlStructureSpacingSniff sniff and empty scope
-- Fixed bug #20252 : Unitialized string offset when package name starts with underscore
+- Fixed bug [#20248][pear-20248] : The Squiz_Sniffs_WhiteSpace_ControlStructureSpacingSniff sniff and empty scope
+- Fixed bug [#20252][pear-20252] : Unitialized string offset when package name starts with underscore
+
+[pear-20234]: https://pear.php.net/bugs/bug.php?id=20234
 
 ## [1.5.3] - 2014-05-01
+
 ### Changed
 - Improved detection of nested IF statements that use the alternate IF/ENDIF syntax
 - PHP tokenizer now supports DEFAULT statements opened with a T_SEMICOLON
 - PSR1 CamelCapsMethodNameSniff now ignores magic methods
     - Thanks to [Eser Ozvataf][@eser] for the patch
 - PSR1 SideEffectsSniff now ignores methods named define()
-- PSR1 and PEAR ClassDeclarationSniffs now support traits (request #20208)
+- PSR1 and PEAR ClassDeclarationSniffs now support traits (request [#20208][pear-20208])
 - PSR2 ControlStructureSpacingSniff now allows newlines before/after parentheses
     - Thanks to [Maurus Cuelenaere][@mcuelenaere] for the patch
 - Squiz LowercasePHPFunctionsSniff no longer reports errors for namespaced functions
@@ -3695,21 +5273,34 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Squiz SwitchDeclarationSniff now allows exit() as a breaking statement for case/default
 - Squiz ValidVariableNameSniff and Zend ValidVariableNameSniff now ignore additional PHP reserved vars
     - Thanks to Mikuláš Dítě and Adrian Crepaz for the patch
-- Sniff code Squiz.WhiteSpace.MemberVarSpacing.After changed to Squiz.WhiteSpace.MemberVarSpacing.Incorrect (request #20241)
+- Sniff code Squiz.WhiteSpace.MemberVarSpacing.After changed to Squiz.WhiteSpace.MemberVarSpacing.Incorrect (request [#20241][pear-20241])
 
 ### Fixed
-- Fixed bug #20200 : Invalid JSON produced with specific error message
-- Fixed bug #20204 : Ruleset exclude checks are case sensitive
-- Fixed bug #20213 : Invalid error, Inline IF must be declared on single line
-- Fixed bug #20225 : array_merge() that takes more than one line generates error
-- Fixed bug #20230 : Squiz ControlStructureSpacing sniff assumes specific condition formatting
-- Fixed bug #20240 : Squiz block comment sniff fails when newline present
-- Fixed bug #20247 : The Squiz.WhiteSpace.ControlStructureSpacing sniff and do-while
+- Fixed bug [#20200][pear-20200] : Invalid JSON produced with specific error message
+- Fixed bug [#20204][pear-20204] : Ruleset exclude checks are case sensitive
+- Fixed bug [#20213][pear-20213] : Invalid error, Inline IF must be declared on single line
+- Fixed bug [#20225][pear-20225] : array_merge() that takes more than one line generates error
+- Fixed bug [#20230][pear-20230] : Squiz ControlStructureSpacing sniff assumes specific condition formatting
+- Fixed bug [#20240][pear-20240] : Squiz block comment sniff fails when newline present
+- Fixed bug [#20247][pear-20247] : The Squiz.WhiteSpace.ControlStructureSpacing sniff and do-while
     - Thanks to [Alexander Obuhovich][@aik099] for the patch
-- Fixed bug #20248 : The Squiz_Sniffs_WhiteSpace_ControlStructureSpacingSniff sniff and empty scope
-- Fixed bug #20252 : Uninitialized string offset when package name starts with underscore
+- Fixed bug [#20248][pear-20248] : The Squiz_Sniffs_WhiteSpace_ControlStructureSpacingSniff sniff and empty scope
+- Fixed bug [#20252][pear-20252] : Uninitialized string offset when package name starts with underscore
+
+[pear-20200]: https://pear.php.net/bugs/bug.php?id=20200
+[pear-20204]: https://pear.php.net/bugs/bug.php?id=20204
+[pear-20208]: https://pear.php.net/bugs/bug.php?id=20208
+[pear-20213]: https://pear.php.net/bugs/bug.php?id=20213
+[pear-20225]: https://pear.php.net/bugs/bug.php?id=20225
+[pear-20230]: https://pear.php.net/bugs/bug.php?id=20230
+[pear-20240]: https://pear.php.net/bugs/bug.php?id=20240
+[pear-20241]: https://pear.php.net/bugs/bug.php?id=20241
+[pear-20247]: https://pear.php.net/bugs/bug.php?id=20247
+[pear-20248]: https://pear.php.net/bugs/bug.php?id=20248
+[pear-20252]: https://pear.php.net/bugs/bug.php?id=20252
 
 ## [2.0.0a1] - 2014-02-05
+
 ### Changed
 - Added the phpcbf script to automatically fix many errors found by the phpcs script
 - Added report type --report=diff to show suggested changes to fix coding standard violations
@@ -3717,12 +5308,12 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Use the full path to your custom report class as the report name
 - The --extensions argument is now respected when passing filenames; not just with directories
 - The --extensions argument now allows you to specify the tokenizer for each extension
-    - e.g., --extensions=module/php,es/js
+    - e.g., `--extensions=module/php,es/js`
 - Command line arguments can now be set in ruleset files
-    - e.g., arg name="report" value="summary" (print summary report; same as --report=summary)
-    - e.g., arg value="sp" (print source and progress information; same as -sp)
-    - The -vvv, --sniffs, --standard and -l command line arguments cannot be set in this way
-- Sniff process() methods can not optionally return a token to ignore up to
+    - e.g., `arg name="report" value="summary"` (print summary report; same as `--report=summary`)
+    - e.g., `arg value="sp"` (print source and progress information; same as `-sp`)
+    - The `-vvv`, `--sniffs`, `--standard` and `-l` command line arguments cannot be set in this way
+- Sniff process() methods can now optionally return a token to ignore up to
     - If returned, the sniff will not be executed again until the passed token is reached in the file
     - Useful if you are looking for tokens like T_OPEN_TAG but only want to process the first one
 - Removed the comment parser classes and replaced it with a simple comment tokenizer
@@ -3761,6 +5352,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Removed MySource ChannelExceptionSniff
 
 ## [1.5.2] - 2014-02-05
+
 ### Changed
 - Improved support for the PHP 5.5. classname::class syntax
     - PSR2 SwitchDeclarationSniff no longer throws errors when this syntax is used in CASE conditions
@@ -3794,14 +5386,20 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Generic FixmeSniff and TodoSniff now work correctly with accented characters
 
 ### Fixed
-- Fixed bug #20145 : Custom ruleset preferences directory over installed standard
-- Fixed bug #20147 : phpcs-svn-pre-commit - no more default error report
-- Fixed bug #20151 : Problem handling "if(): ... else: ... endif;" syntax
-- Fixed bug #20190 : Invalid regex in Squiz_Sniffs_WhiteSpace_SuperfluousWhitespaceSniff
+- Fixed bug [#20145][pear-20145] : Custom ruleset preferences directory over installed standard
+- Fixed bug [#20147][pear-20147] : phpcs-svn-pre-commit - no more default error report
+- Fixed bug [#20151][pear-20151] : Problem handling "if(): ... else: ... endif;" syntax
+- Fixed bug [#20190][pear-20190] : Invalid regex in Squiz_Sniffs_WhiteSpace_SuperfluousWhitespaceSniff
+
+[pear-20145]: https://pear.php.net/bugs/bug.php?id=20145
+[pear-20147]: https://pear.php.net/bugs/bug.php?id=20147
+[pear-20151]: https://pear.php.net/bugs/bug.php?id=20151
+[pear-20190]: https://pear.php.net/bugs/bug.php?id=20190
 
 ## [1.5.1] - 2013-12-12
+
 ### Changed
-- Config values can now be set at runtime using the command line argument [--runtime-set key value]
+- Config values can now be set at runtime using the command line argument `--runtime-set key value`
     - Runtime values are the same as config values, but are not written to the main config file
     - Thanks to [Wim Godden][@wimg] for the patch
 - Config values can now be set in ruleset files
@@ -3816,15 +5414,20 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - PSR2 ClassDeclarationSniff now allows a list of extended interfaces to be split across multiple lines
 - Squiz DoubleQuoteUsageSniff now allows \b in double quoted strings
 - Generic ForbiddenFunctionsSniff now ignores object creation
-    - This is a further fix for bug #20100 : incorrect Function mysql() has been deprecated report
+    - This is a further fix for bug [#20100][pear-20100] : incorrect Function mysql() has been deprecated report
 
 ### Fixed
-- Fixed bug #20136 : Squiz_Sniffs_WhiteSpace_ScopeKeywordSpacingSniff and Traits
-- Fixed bug #20138 : Protected property underscore and camel caps issue (in trait with Zend)
+- Fixed bug [#20136][pear-20136] : Squiz_Sniffs_WhiteSpace_ScopeKeywordSpacingSniff and Traits
+- Fixed bug [#20138][pear-20138] : Protected property underscore and camel caps issue (in trait with Zend)
     - Thanks to [Gaetan Rousseau][@Naelyth] for the patch
-- Fixed bug #20139 : No report file generated on success
+- Fixed bug [#20139][pear-20139] : No report file generated on success
+
+[pear-20136]: https://pear.php.net/bugs/bug.php?id=20136
+[pear-20138]: https://pear.php.net/bugs/bug.php?id=20138
+[pear-20139]: https://pear.php.net/bugs/bug.php?id=20139
 
 ## [1.5.0] - 2013-11-28
+
 ### Changed
 - Doc generation is now working again for installed standards
     - Includes a fix for limiting the docs to specific sniffs
@@ -3832,9 +5435,9 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - E.g., to ignore comments, override a property using:
     - name="ignoreIndentationTokens" type="array" value="T_COMMENT,T_DOC_COMMENT"
 - PSR2 standard now ignores comments when checking indentation rules
-- Generic UpperCaseConstantNameSniff no longer reports errors where constants are used (request #20090)
+- Generic UpperCaseConstantNameSniff no longer reports errors where constants are used (request [#20090][pear-20090])
     - It still reports errors where constants are defined
-- Individual messages can now be excluded in ruleset.xml files using the exclude tag (request #20091)
+- Individual messages can now be excluded in ruleset.xml files using the exclude tag (request [#20091][pear-20091])
     - Setting message severity to 0 continues to be supported
 - Squiz OperatorSpacingSniff no longer throws errors for the ?: short ternary operator
     - Thanks to [Antoine Musso][@hashar] for the patch
@@ -3847,15 +5450,20 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Maksim Kochkin][@ksimka] for the patch
 
 ### Fixed
-- Fixed bug #20093 : Bug with ternary operator token
-- Fixed bug #20097 : CLI.php throws error in php 5.2
-- Fixed bug #20100 : incorrect Function mysql() has been deprecated report
-- Fixed bug #20119 : PHP warning: invalid argument to str_repeat() in SVN blame report with -s
-- Fixed bug #20123 : PSR2 complains about an empty second statement in for-loop
-- Fixed bug #20131 : PHP errors in svnblame report, if there are files not under version control
-- Fixed bug #20133 : Allow "HG: hg_id" as value for @version tag
+- Fixed bug [#20093][pear-20093] : Bug with ternary operator token
+- Fixed bug [#20097][pear-20097] : `CLI.php` throws error in PHP 5.2
+- Fixed bug [#20100][pear-20100] : incorrect Function mysql() has been deprecated report
+- Fixed bug [#20119][pear-20119] : PHP warning: invalid argument to str_repeat() in SVN blame report with -s
+- Fixed bug [#20123][pear-20123] : PSR2 complains about an empty second statement in for-loop
+- Fixed bug [#20131][pear-20131] : PHP errors in svnblame report, if there are files not under version control
+- Fixed bug [#20133][pear-20133] : Allow "HG: hg_id" as value for @version tag
+
+[pear-20090]: https://pear.php.net/bugs/bug.php?id=20090
+[pear-20091]: https://pear.php.net/bugs/bug.php?id=20091
+[pear-20093]: https://pear.php.net/bugs/bug.php?id=20093
 
 ## [1.4.8] - 2013-11-26
+
 ### Changed
 - Generic ScopeIndentSniff now allows for ignored tokens to be set via ruleset.xml files
     - E.g., to ignore comments, override a property using:
@@ -3872,14 +5480,22 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Maksim Kochkin][@ksimka] for the patch
 
 ### Fixed
-- Fixed bug #20097 : CLI.php throws error in php 5.2
-- Fixed bug #20100 : incorrect Function mysql() has been deprecated report
-- Fixed bug #20119 : PHP warning: invalid argument to str_repeat() in SVN blame report with -s
-- Fixed bug #20123 : PSR2 complains about an empty second statement in for-loop
-- Fixed bug #20131 : PHP errors in svnblame report, if there are files not under version control
-- Fixed bug #20133 : Allow "HG: hg_id" as value for @version tag
+- Fixed bug [#20097][pear-20097] : `CLI.php` throws error in PHP 5.2
+- Fixed bug [#20100][pear-20100] : incorrect Function mysql() has been deprecated report
+- Fixed bug [#20119][pear-20119] : PHP warning: invalid argument to str_repeat() in SVN blame report with -s
+- Fixed bug [#20123][pear-20123] : PSR2 complains about an empty second statement in for-loop
+- Fixed bug [#20131][pear-20131] : PHP errors in svnblame report, if there are files not under version control
+- Fixed bug [#20133][pear-20133] : Allow "HG: hg_id" as value for @version tag
+
+[pear-20097]: https://pear.php.net/bugs/bug.php?id=20097
+[pear-20100]: https://pear.php.net/bugs/bug.php?id=20100
+[pear-20119]: https://pear.php.net/bugs/bug.php?id=20119
+[pear-20123]: https://pear.php.net/bugs/bug.php?id=20123
+[pear-20131]: https://pear.php.net/bugs/bug.php?id=20131
+[pear-20133]: https://pear.php.net/bugs/bug.php?id=20133
 
 ## [1.5.0RC4] - 2013-09-26
+
 ### Changed
 - You can now restrict violations to individual sniff codes using the --sniffs command line argument
     - Previously, this only restricted violations to an entire sniff and not individual messages
@@ -3892,7 +5508,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Oleg Lobach][@bladeofsteel] for the contribution
 - Added support for the PHP 5.4 callable type hint
 - Fixed problem where some file content could be ignored when checking STDIN
-- Version information is now printed when installed via composer or run from a Git clone (request #20050)
+- Version information is now printed when installed via composer or run from a Git clone (request [#20050][pear-20050])
 - Added Squiz DisallowBooleanStatementSniff to ban boolean operators outside of control structure conditions
 - The CSS tokenizer is now more reliable when encountering 'list' and 'break' strings
 - Coding standard ignore comments can now appear instead doc blocks as well as inline comments
@@ -3929,22 +5545,25 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 
 ### Fixed
 - Fixed cases where code was incorrectly assigned the T_GOTO_LABEL token when used in a complex CASE condition
-- Fixed bug #20026 : Check for multi-line arrays that should be single-line is slightly wrong
+- Fixed bug [#20026][pear-20026] : Check for multi-line arrays that should be single-line is slightly wrong
     - Adds new error message for single-line arrays that end with a comma
-- Fixed bug #20029 : ForbiddenFunction sniff incorrectly recognizes methods in USE clauses
-- Fixed bug #20043 : Mis-interpretation of Foo::class
-- Fixed bug #20044 : PSR1 camelCase check does not ignore leading underscores
-- Fixed bug #20045 : Errors about indentation for closures with multi-line 'use' in functions
-- Fixed bug #20051 : Undefined index: scope_opener / scope_closer
+- Fixed bug [#20029][pear-20029] : ForbiddenFunction sniff incorrectly recognizes methods in USE clauses
+- Fixed bug [#20043][pear-20043] : Mis-interpretation of Foo::class
+- Fixed bug [#20044][pear-20044] : PSR1 camelCase check does not ignore leading underscores
+- Fixed bug [#20045][pear-20045] : Errors about indentation for closures with multi-line 'use' in functions
+- Fixed bug [#20051][pear-20051] : Undefined index: scope_opener / scope_closer
     - Thanks to [Anthon Pang][@robocoder] for the patch
 
+[pear-20051]: https://pear.php.net/bugs/bug.php?id=20051
+
 ## [1.4.7] - 2013-09-26
+
 ### Changed
 - Added report type --report=junit to show the error list in a JUnit compatible format
     - Thanks to [Oleg Lobach][@bladeofsteel] for the contribution
 - Added support for the PHP 5.4 callable type hint
 - Fixed problem where some file content could be ignored when checking STDIN
-- Version information is now printed when installed via composer or run from a Git clone (request #20050)
+- Version information is now printed when installed via composer or run from a Git clone (request [#20050][pear-20050])
 - The CSS tokenizer is now more reliable when encountering 'list' and 'break' strings
 - Coding standard ignore comments can now appear instead doc blocks as well as inline comments
     - Thanks to [Stuart Langley][@sjlangley] for the patch
@@ -3978,14 +5597,22 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - PSR UseDeclarationSniff no longer throws errors for USE statements inside TRAITs
 
 ### Fixed
-- Fixed bug #20026 : Check for multi-line arrays that should be single-line is slightly wrong
+- Fixed bug [#20026][pear-20026] : Check for multi-line arrays that should be single-line is slightly wrong
     - Adds new error message for single-line arrays that end with a comma
-- Fixed bug #20029 : ForbiddenFunction sniff incorrectly recognizes methods in USE clauses
-- Fixed bug #20043 : Mis-interpretation of Foo::class
-- Fixed bug #20044 : PSR1 camelCase check does not ignore leading underscores
-- Fixed bug #20045 : Errors about indentation for closures with multi-line 'use' in functions
+- Fixed bug [#20029][pear-20029] : ForbiddenFunction sniff incorrectly recognizes methods in USE clauses
+- Fixed bug [#20043][pear-20043] : Mis-interpretation of Foo::class
+- Fixed bug [#20044][pear-20044] : PSR1 camelCase check does not ignore leading underscores
+- Fixed bug [#20045][pear-20045] : Errors about indentation for closures with multi-line 'use' in functions
+
+[pear-20026]: https://pear.php.net/bugs/bug.php?id=20026
+[pear-20029]: https://pear.php.net/bugs/bug.php?id=20029
+[pear-20043]: https://pear.php.net/bugs/bug.php?id=20043
+[pear-20044]: https://pear.php.net/bugs/bug.php?id=20044
+[pear-20045]: https://pear.php.net/bugs/bug.php?id=20045
+[pear-20050]: https://pear.php.net/bugs/bug.php?id=20050
 
 ## [1.5.0RC3] - 2013-07-25
+
 ### Changed
 - Added report type --report=json to show the error list and total counts for all checked files
     - Thanks to [Jeffrey Fisher][@jeffslofish] for the contribution
@@ -4034,23 +5661,26 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Arnout Boks][@aboks] for the patch
 
 ### Fixed
-- Fixed bug #19811 : Comments not ignored in all cases in AbstractPatternSniff
+- Fixed bug [#19811][pear-19811] : Comments not ignored in all cases in AbstractPatternSniff
     - Thanks to [Erik Wiffin][@erikwiffin] for the patch
-- Fixed bug #19892 : ELSE with no braces causes incorrect SWITCH break statement indentation error
-- Fixed bug #19897 : Indenting warnings in templates not consistent
-- Fixed bug #19908 : PEAR MultiLineCondition Does Not Apply elseif
-- Fixed bug #19930 : option --report-file generate an empty file
-- Fixed bug #19935 : notify-send reports do not vanish in gnome-shell
+- Fixed bug [#19892][pear-19892] : ELSE with no braces causes incorrect SWITCH break statement indentation error
+- Fixed bug [#19897][pear-19897] : Indenting warnings in templates not consistent
+- Fixed bug [#19908][pear-19908] : PEAR MultiLineCondition Does Not Apply elseif
+- Fixed bug [#19930][pear-19930] : option --report-file generate an empty file
+- Fixed bug [#19935][pear-19935] : notify-send reports do not vanish in gnome-shell
     - Thanks to [Christian Weiske][@cweiske] for the patch
-- Fixed bug #19944 : docblock squiz sniff "return void" trips over return in lambda function
-- Fixed bug #19953 : PSR2 - Spaces before interface name for abstract class
-- Fixed bug #19956 : phpcs warns for Type Hint missing Resource
-- Fixed bug #19957 : Does not understand trait method aliasing
-- Fixed bug #19968 : Permission denied on excluded directory
-- Fixed bug #19969 : Sniffs with namespace not recognized in reports
-- Fixed bug #19997 : Class names incorrectly detected as constants
+- Fixed bug [#19944][pear-19944] : docblock squiz sniff "return void" trips over return in lambda function
+- Fixed bug [#19953][pear-19953] : PSR2 - Spaces before interface name for abstract class
+- Fixed bug [#19956][pear-19956] : phpcs warns for Type Hint missing Resource
+- Fixed bug [#19957][pear-19957] : Does not understand trait method aliasing
+- Fixed bug [#19968][pear-19968] : Permission denied on excluded directory
+- Fixed bug [#19969][pear-19969] : Sniffs with namespace not recognized in reports
+- Fixed bug [#19997][pear-19997] : Class names incorrectly detected as constants
+
+[pear-19930]: https://pear.php.net/bugs/bug.php?id=19930
 
 ## [1.4.6] - 2013-07-25
+
 ### Changed
 - Added report type --report=json to show the error list and total counts for all checked files
     - Thanks to [Jeffrey Fisher][@jeffslofish] for the contribution
@@ -4095,39 +5725,54 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Arnout Boks][@aboks] for the patch
 
 ### Fixed
-- Fixed bug #19811 : Comments not ignored in all cases in AbstractPatternSniff
+- Fixed bug [#19811][pear-19811] : Comments not ignored in all cases in AbstractPatternSniff
     - Thanks to [Erik Wiffin][@erikwiffin] for the patch
-- Fixed bug #19892 : ELSE with no braces causes incorrect SWITCH break statement indentation error
-- Fixed bug #19897 : Indenting warnings in templates not consistent
-- Fixed bug #19908 : PEAR MultiLineCondition Does Not Apply elseif
-- Fixed bug #19913 : Running phpcs in interactive mode causes warnings
+- Fixed bug [#19892][pear-19892] : ELSE with no braces causes incorrect SWITCH break statement indentation error
+- Fixed bug [#19897][pear-19897] : Indenting warnings in templates not consistent
+- Fixed bug [#19908][pear-19908] : PEAR MultiLineCondition Does Not Apply elseif
+- Fixed bug [#19913][pear-19913] : Running phpcs in interactive mode causes warnings
     - Thanks to [Harald Franndorfer][pear-gemineye] for the patch
-- Fixed bug #19935 : notify-send reports do not vanish in gnome-shell
+- Fixed bug [#19935][pear-19935] : notify-send reports do not vanish in gnome-shell
     - Thanks to [Christian Weiske][@cweiske] for the patch
-- Fixed bug #19944 : docblock squiz sniff "return void" trips over return in lambda function
-- Fixed bug #19953 : PSR2 - Spaces before interface name for abstract class
-- Fixed bug #19956 : phpcs warns for Type Hint missing Resource
-- Fixed bug #19957 : Does not understand trait method aliasing
-- Fixed bug #19968 : Permission denied on excluded directory
-- Fixed bug #19969 : Sniffs with namespace not recognized in reports
-- Fixed bug #19997 : Class names incorrectly detected as constants
+- Fixed bug [#19944][pear-19944] : docblock squiz sniff "return void" trips over return in lambda function
+- Fixed bug [#19953][pear-19953] : PSR2 - Spaces before interface name for abstract class
+- Fixed bug [#19956][pear-19956] : phpcs warns for Type Hint missing Resource
+- Fixed bug [#19957][pear-19957] : Does not understand trait method aliasing
+- Fixed bug [#19968][pear-19968] : Permission denied on excluded directory
+- Fixed bug [#19969][pear-19969] : Sniffs with namespace not recognized in reports
+- Fixed bug [#19997][pear-19997] : Class names incorrectly detected as constants
+
+[pear-19811]: https://pear.php.net/bugs/bug.php?id=19811
+[pear-19892]: https://pear.php.net/bugs/bug.php?id=19892
+[pear-19897]: https://pear.php.net/bugs/bug.php?id=19897
+[pear-19908]: https://pear.php.net/bugs/bug.php?id=19908
+[pear-19913]: https://pear.php.net/bugs/bug.php?id=19913
+[pear-19935]: https://pear.php.net/bugs/bug.php?id=19935
+[pear-19944]: https://pear.php.net/bugs/bug.php?id=19944
+[pear-19953]: https://pear.php.net/bugs/bug.php?id=19953
+[pear-19956]: https://pear.php.net/bugs/bug.php?id=19956
+[pear-19957]: https://pear.php.net/bugs/bug.php?id=19957
+[pear-19968]: https://pear.php.net/bugs/bug.php?id=19968
+[pear-19969]: https://pear.php.net/bugs/bug.php?id=19969
+[pear-19997]: https://pear.php.net/bugs/bug.php?id=19997
 
 ## [1.5.0RC2] - 2013-04-04
+
 ### Changed
 - Ruleset processing has been rewritten to be more predictable
     - Provides much better support for relative paths inside ruleset files
     - May mean that sniffs that were previously ignored are now being included when importing external rulesets
     - Ruleset processing output can be seen by using the -vv command line argument
     - Internal sniff registering functions have all changed, so please review custom scripts
-- You can now pass multiple coding standards on the command line, comma separated (request #19144)
+- You can now pass multiple coding standards on the command line, comma separated (request [#19144][pear-19144])
     - Works with built-in or custom standards and rulesets, or a mix of both
-- You can now exclude directories or whole standards in a ruleset XML file (request #19731)
+- You can now exclude directories or whole standards in a ruleset XML file (request [#19731][pear-19731])
     - e.g., exclude "Generic.Commenting" or just "Generic"
     - You can also pass in a path to a directory instead, if you know it
 - Added Generic LowerCaseKeywordSniff to ensure all PHP keywords are defined in lowercase
     - The PSR2 and Squiz standards now use this sniff
-- Added Generic SAPIUsageSniff to ensure the PHP_SAPI constant is used instead of php_sapi_name() (request #19863)
-- Squiz FunctionSpacingSniff now has a setting to specify how many lines there should between functions (request #19843)
+- Added Generic SAPIUsageSniff to ensure the `PHP_SAPI` constant is used instead of `php_sapi_name()` (request [#19863][pear-19863])
+- Squiz FunctionSpacingSniff now has a setting to specify how many lines there should between functions (request [#19843][pear-19843])
     - Default remains at 2
     - Override the "spacing" setting in a ruleset.xml file to change
 - Squiz LowercasePHPFunctionSniff no longer throws errors for the limited set of PHP keywords it was checking
@@ -4151,18 +5796,22 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Generic DuplicateClassNameSniff no longer reports duplicate errors if multiple PHP open tags exist in a file
 
 ### Fixed
-- Fixed bug #19819 : Freeze with syntax error in use statement
-- Fixed bug #19820 : Wrong message level in Generic_Sniffs_CodeAnalysis_EmptyStatementSniff
-- Fixed bug #19859 : CodeSniffer::setIgnorePatterns API changed
-- Fixed bug #19871 : findExtendedClassName doesn't return FQCN on namespaced classes
-- Fixed bug #19879 : bitwise and operator interpreted as reference by value
+- Fixed bug [#19819][pear-19819] : Freeze with syntax error in use statement
+- Fixed bug [#19820][pear-19820] : Wrong message level in Generic_Sniffs_CodeAnalysis_EmptyStatementSniff
+- Fixed bug [#19859][pear-19859] : CodeSniffer::setIgnorePatterns API changed
+- Fixed bug [#19871][pear-19871] : findExtendedClassName doesn't return FQCN on namespaced classes
+- Fixed bug [#19879][pear-19879] : bitwise and operator interpreted as reference by value
+
+[pear-19144]: https://pear.php.net/bugs/bug.php?id=19144
+[pear-19731]: https://pear.php.net/bugs/bug.php?id=19731
 
 ## [1.4.5] - 2013-04-04
+
 ### Changed
 - Added Generic LowerCaseKeywordSniff to ensure all PHP keywords are defined in lowercase
     - The PSR2 and Squiz standards now use this sniff
-- Added Generic SAPIUsageSniff to ensure the PHP_SAPI constant is used instead of php_sapi_name() (request #19863)
-- Squiz FunctionSpacingSniff now has a setting to specify how many lines there should between functions (request #19843)
+- Added Generic SAPIUsageSniff to ensure the `PHP_SAPI` constant is used instead of `php_sapi_name()` (request [#19863][pear-19863])
+- Squiz FunctionSpacingSniff now has a setting to specify how many lines there should between functions (request [#19843][pear-19843])
     - Default remains at 2
     - Override the "spacing" setting in a ruleset.xml file to change
 - Squiz LowercasePHPFunctionSniff no longer throws errors for the limited set of PHP keywords it was checking
@@ -4186,22 +5835,32 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Generic DuplicateClassNameSniff no longer reports duplicate errors if multiple PHP open tags exist in a file
 
 ### Fixed
-- Fixed bug #19819 : Freeze with syntax error in use statement
-- Fixed bug #19820 : Wrong message level in Generic_Sniffs_CodeAnalysis_EmptyStatementSniff
-- Fixed bug #19859 : CodeSniffer::setIgnorePatterns API changed
-- Fixed bug #19871 : findExtendedClassName doesn't return FQCN on namespaced classes
-- Fixed bug #19879 : bitwise and operator interpreted as reference by value
+- Fixed bug [#19819][pear-19819] : Freeze with syntax error in use statement
+- Fixed bug [#19820][pear-19820] : Wrong message level in Generic_Sniffs_CodeAnalysis_EmptyStatementSniff
+- Fixed bug [#19859][pear-19859] : CodeSniffer::setIgnorePatterns API changed
+- Fixed bug [#19871][pear-19871] : findExtendedClassName doesn't return FQCN on namespaced classes
+- Fixed bug [#19879][pear-19879] : bitwise and operator interpreted as reference by value
+
+[pear-19819]: https://pear.php.net/bugs/bug.php?id=19819
+[pear-19820]: https://pear.php.net/bugs/bug.php?id=19820
+[pear-19843]: https://pear.php.net/bugs/bug.php?id=19843
+[pear-19859]: https://pear.php.net/bugs/bug.php?id=19859
+[pear-19863]: https://pear.php.net/bugs/bug.php?id=19863
+[pear-19871]: https://pear.php.net/bugs/bug.php?id=19871
+[pear-19879]: https://pear.php.net/bugs/bug.php?id=19879
 
 ## [1.5.0RC1] - 2013-02-08
+
 ### Changed
 - Reports have been completely rewritten to consume far less memory
     - Each report is incrementally written to the file system during a run and then printed out when the run ends
     - There is no longer a need to keep the list of errors and warnings in memory during a run
 - Multi-file sniff support has been removed because they are too memory intensive
     - If you have a custom multi-file sniff, you can convert it into a standard sniff quite easily
-    - See CodeSniffer/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php for an example
+    - See `CodeSniffer/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php` for an example
 
 ## [1.4.4] - 2013-02-07
+
 ### Changed
 - Ignored lines no longer cause the summary report to show incorrect error and warning counts
     - Thanks to [Bert Van Hauwaert][@becoded] for the patch
@@ -4209,7 +5868,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Set full command to run CSSLint using phpcs --config-set csslint_path /path/to/csslint
     - Thanks to [Roman Levishchenko][@index0h] for the contribution
 - Added PSR2 ControlStructureSpacingSniff to ensure there are no spaces before and after parenthesis in control structures
-    - Fixes bug #19732 : PSR2: some control structures errors not reported
+    - Fixes bug [#19732][pear-19732] : PSR2: some control structures errors not reported
 - Squiz commenting sniffs now support non-English characters when checking for capital letters
     - Thanks to [Roman Levishchenko][@index0h] for the patch
 - Generic EndFileNewlineSniff now supports JS and CSS files
@@ -4225,17 +5884,29 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Squiz SuperfluousWhitespaceSniff now allows a single newline at the end of JS and CSS files
 
 ### Fixed
-- Fixed bug #19755 : Token of T_CLASS type has no scope_opener and scope_closer keys
-- Fixed bug #19759 : Squiz.PHP.NonExecutableCode fails for return function()...
-- Fixed bug #19763 : Use statements for traits not recognised correctly for PSR2 code style
-- Fixed bug #19764 : Instead of for traits throws uppercase constant name errors
-- Fixed bug #19772 : PSR2_Sniffs_Namespaces_UseDeclarationSniff does not properly recognize last use
-- Fixed bug #19775 : False positive in NonExecutableCode sniff when not using curly braces
-- Fixed bug #19782 : Invalid found size functions in loop when using object operator
-- Fixed bug #19799 : config folder is not created automatically
-- Fixed bug #19804 : JS Tokenizer wrong /**/ parsing
+- Fixed bug [#19755][pear-19755] : Token of T_CLASS type has no scope_opener and scope_closer keys
+- Fixed bug [#19759][pear-19759] : Squiz.PHP.NonExecutableCode fails for return function()...
+- Fixed bug [#19763][pear-19763] : Use statements for traits not recognised correctly for PSR2 code style
+- Fixed bug [#19764][pear-19764] : Instead of for traits throws uppercase constant name errors
+- Fixed bug [#19772][pear-19772] : PSR2_Sniffs_Namespaces_UseDeclarationSniff does not properly recognize last use
+- Fixed bug [#19775][pear-19775] : False positive in NonExecutableCode sniff when not using curly braces
+- Fixed bug [#19782][pear-19782] : Invalid found size functions in loop when using object operator
+- Fixed bug [#19799][pear-19799] : config folder is not created automatically
+- Fixed bug [#19804][pear-19804] : JS Tokenizer wrong /**/ parsing
+
+[pear-19732]: https://pear.php.net/bugs/bug.php?id=19732
+[pear-19755]: https://pear.php.net/bugs/bug.php?id=19755
+[pear-19759]: https://pear.php.net/bugs/bug.php?id=19759
+[pear-19763]: https://pear.php.net/bugs/bug.php?id=19763
+[pear-19764]: https://pear.php.net/bugs/bug.php?id=19764
+[pear-19772]: https://pear.php.net/bugs/bug.php?id=19772
+[pear-19775]: https://pear.php.net/bugs/bug.php?id=19775
+[pear-19782]: https://pear.php.net/bugs/bug.php?id=19782
+[pear-19799]: https://pear.php.net/bugs/bug.php?id=19799
+[pear-19804]: https://pear.php.net/bugs/bug.php?id=19804
 
 ## [1.4.3] - 2012-12-04
+
 ### Changed
 - Added support for the PHP 5.5 T_FINALLY token to detect try/catch/finally statements
 - Added empty CodeSniffer.conf to enable config settings for Composer installs
@@ -4251,14 +5922,19 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Andy Grunwald][@andygrunwald] for the patch
 
 ### Fixed
-- Fixed bug #19699 : Generic.Files.LineLength giving false positives when tab-width is used
-- Fixed bug #19726 : Wrong number of spaces expected after instanceof static
-- Fixed bug #19727 : PSR2: no error reported when using } elseif {
+- Fixed bug [#19699][pear-19699] : Generic.Files.LineLength giving false positives when tab-width is used
+- Fixed bug [#19726][pear-19726] : Wrong number of spaces expected after instanceof static
+- Fixed bug [#19727][pear-19727] : PSR2: no error reported when using } elseif {
+
+[pear-19699]: https://pear.php.net/bugs/bug.php?id=19699
+[pear-19726]: https://pear.php.net/bugs/bug.php?id=19726
+[pear-19727]: https://pear.php.net/bugs/bug.php?id=19727
 
 ## [1.4.2] - 2012-11-09
+
 ### Changed
 - PHP_CodeSniffer can now be installed using Composer
-    - Require squizlabs/php_codesniffer in your composer.json file
+    - Require `squizlabs/php_codesniffer` in your `composer.json` file
     - Thanks to [Rob Bast][@alcohol], [Stephen Rees-Carter][@valorin], [Stefano Kowalke][@Konafets] and [Ivan Habunek][@ihabunek] for help with this
 - Squiz BlockCommentSniff and InlineCommentSniff no longer report errors for trait block comments
 - Squiz SelfMemberReferenceSniff now supports namespaces
@@ -4274,20 +5950,26 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Fixed gitblame report not working on Windows
     - Thanks to [Rogerio Prado de Jesus][@rogeriopradoj]
 - Fixed an incorrect error in Squiz OperatorSpacingSniff for default values inside a closure definition
-- Fixed bug #19691 : SubversionPropertiesSniff fails to find missing properties
+- Fixed bug [#19691][pear-19691] : SubversionPropertiesSniff fails to find missing properties
     - Thanks to [Kevin Winahradsky][pear-kwinahradsky] for the patch
-- Fixed bug #19692 : DisallowMultipleAssignments is triggered by a closure
-- Fixed bug #19693 : exclude-patterns no longer work on specific messages
-- Fixed bug #19694 : Squiz.PHP.LowercasePHPFunctions incorrectly matches return by ref functions
+- Fixed bug [#19692][pear-19692] : DisallowMultipleAssignments is triggered by a closure
+- Fixed bug [#19693][pear-19693] : exclude-patterns no longer work on specific messages
+- Fixed bug [#19694][pear-19694] : Squiz.PHP.LowercasePHPFunctions incorrectly matches return by ref functions
+
+[pear-19691]: https://pear.php.net/bugs/bug.php?id=19691
+[pear-19692]: https://pear.php.net/bugs/bug.php?id=19692
+[pear-19693]: https://pear.php.net/bugs/bug.php?id=19693
+[pear-19694]: https://pear.php.net/bugs/bug.php?id=19694
 
 ## [1.4.1] - 2012-11-02
+
 ### Changed
 - All ignore patterns have been reverted to being checked against the absolute path of a file
     - Patterns can be specified to be relative in a ruleset.xml file, but nowhere else
-    - e.g., [exclude-pattern type="relative"]^tests/*[/exclude-pattern] (with angle brackets, not square brackets)
+    - e.g., `^tests/*`
 - Added support for PHP tokenizing of T_INLINE_ELSE colons, so this token type is now available
     - Custom sniffs that rely on looking for T_COLON tokens inside inline if statements must be changed to use the new token
-    - Fixes bug #19666 : PSR1.Files.SideEffects throws a notice Undefined index: scope_closer
+    - Fixes bug [#19666][pear-19666] : PSR1.Files.SideEffects throws a notice Undefined index: scope_closer
 - Messages can now be changed from errors to warnings (and vice versa) inside ruleset.xml files
     - As you would with "message" and "severity", specify a "type" tag under a "rule" tag and set the value to "error" or "warning"
 - PHP_CodeSniffer will now generate a warning on files that it detects have mixed line endings
@@ -4318,23 +6000,33 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - PSR1 ClassDeclarationSniff no longer throws an error for non-namespaced code if PHP version is less than 5.3.0
 
 ### Fixed
-- Fixed bug #19616 : Nested switches cause false error in PSR2
-- Fixed bug #19629 : PSR2 error for inline comments on multi-line argument lists
-- Fixed bug #19644 : Alternative syntax, e.g. if/endif triggers Inline Control Structure error
-- Fixed bug #19655 : Closures reporting as multi-line when they are not
-- Fixed bug #19675 : Improper indent of nested anonymous function bodies in a call
-- Fixed bug #19685 : PSR2 catch-22 with empty third statement in for loop
-- Fixed bug #19687 : Anonymous functions inside arrays marked as indented incorrectly in PSR2
+- Fixed bug [#19616][pear-19616] : Nested switches cause false error in PSR2
+- Fixed bug [#19629][pear-19629] : PSR2 error for inline comments on multi-line argument lists
+- Fixed bug [#19644][pear-19644] : Alternative syntax, e.g. if/endif triggers Inline Control Structure error
+- Fixed bug [#19655][pear-19655] : Closures reporting as multi-line when they are not
+- Fixed bug [#19675][pear-19675] : Improper indent of nested anonymous function bodies in a call
+- Fixed bug [#19685][pear-19685] : PSR2 catch-22 with empty third statement in for loop
+- Fixed bug [#19687][pear-19687] : Anonymous functions inside arrays marked as indented incorrectly in PSR2
+
+[pear-19616]: https://pear.php.net/bugs/bug.php?id=19616
+[pear-19629]: https://pear.php.net/bugs/bug.php?id=19629
+[pear-19644]: https://pear.php.net/bugs/bug.php?id=19644
+[pear-19655]: https://pear.php.net/bugs/bug.php?id=19655
+[pear-19666]: https://pear.php.net/bugs/bug.php?id=19666
+[pear-19675]: https://pear.php.net/bugs/bug.php?id=19675
+[pear-19685]: https://pear.php.net/bugs/bug.php?id=19685
+[pear-19687]: https://pear.php.net/bugs/bug.php?id=19687
 
 ## [1.4.0] - 2012-09-26
+
 ### Changed
 - Added PSR1 and PSR2 coding standards that can be used to check your code against these guidelines
 - PHP 5.4 short array syntax is now detected and tokens are assigned to the open and close characters
     - New tokens are T_OPEN_SHORT_ARRAY and T_CLOSE_SHORT_ARRAY as PHP does not define its own
 - Added the ability to explain a coding standard by listing the sniffs that it includes
     - The sniff list includes all imported and native sniffs
-    - Explain a standard by using the -e and --standard=[standard] command line arguments
-    - E.g., phpcs -e --standard=Squiz
+    - Explain a standard by using the `-e` and `--standard=[standard]` command line arguments
+    - E.g., `phpcs -e --standard=Squiz`
     - Thanks to [Ben Selby][@benmatselby] for the idea
 - Added report to show results using notify-send
     - Use --report=notifysend to generate the report
@@ -4350,13 +6042,19 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 
 ### Fixed
 - Fixed a PHP notice generated when loading custom array settings from a ruleset.xml file
-- Fixed bug #17908 : CodeSniffer does not recognise optional @params
+- Fixed bug [#17908][pear-17908] : CodeSniffer does not recognise optional @params
     - Thanks to [Pete Walker][pear-pete] for the patch
-- Fixed bug #19538 : Function indentation code sniffer checks inside short arrays
-- Fixed bug #19565 : Non-Executable Code Sniff Broken for Case Statements with both return and break
-- Fixed bug #19612 : Invalid @package suggestion
+- Fixed bug [#19538][pear-19538] : Function indentation code sniffer checks inside short arrays
+- Fixed bug [#19565][pear-19565] : Non-Executable Code Sniff Broken for Case Statements with both return and break
+- Fixed bug [#19612][pear-19612] : Invalid @package suggestion
+
+[pear-17908]: https://pear.php.net/bugs/bug.php?id=17908
+[pear-19538]: https://pear.php.net/bugs/bug.php?id=19538
+[pear-19565]: https://pear.php.net/bugs/bug.php?id=19565
+[pear-19612]: https://pear.php.net/bugs/bug.php?id=19612
 
 ## [1.3.6] - 2012-08-08
+
 ### Changed
 - Memory usage has been dramatically reduced when using the summary report
     - Reduced memory is only available when displaying a single summary report to the screen
@@ -4382,12 +6080,18 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 
 ### Fixed
 - Fixed undefined variable error in PEAR FunctionCallSignatureSniff for lines with no indent
-- Fixed bug #19502 : Generic.Files.LineEndingsSniff fails if no new-lines in file
-- Fixed bug #19508 : switch+return: Closing brace indented incorrectly
-- Fixed bug #19532 : The PSR-2 standard don't recognize Null in class names
-- Fixed bug #19546 : Error thrown for __call() method in traits
+- Fixed bug [#19502][pear-19502] : Generic.Files.LineEndingsSniff fails if no new-lines in file
+- Fixed bug [#19508][pear-19508] : switch+return: Closing brace indented incorrectly
+- Fixed bug [#19532][pear-19532] : The PSR-2 standard don't recognize Null in class names
+- Fixed bug [#19546][pear-19546] : Error thrown for __call() method in traits
+
+[pear-19502]: https://pear.php.net/bugs/bug.php?id=19502
+[pear-19508]: https://pear.php.net/bugs/bug.php?id=19508
+[pear-19532]: https://pear.php.net/bugs/bug.php?id=19532
+[pear-19546]: https://pear.php.net/bugs/bug.php?id=19546
 
 ## [1.3.5] - 2012-07-12
+
 ### Changed
 - Added Generic CamelCapsFunctionNameSniff to just check if function and method names use camel caps
     - Does not allow underscore prefixes for private/protected methods
@@ -4407,21 +6111,33 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 
 ### Fixed
 - Fixed duplicate message codes in Generic OpeningFunctionBraceKernighanRitchieSniff
-- Fixed bug #18651 : PHPunit Test cases for custom standards are not working on Windows
-- Fixed bug #19416 : Shorthand arrays cause bracket spacing errors
-- Fixed bug #19421 : phpcs doesn't recognize ${x} as equivalent to $x
-- Fixed bug #19428 : PHPCS Report "hgblame" doesn't support windows paths
+- Fixed bug [#18651][pear-18651] : PHPUnit Test cases for custom standards are not working on Windows
+- Fixed bug [#19416][pear-19416] : Shorthand arrays cause bracket spacing errors
+- Fixed bug [#19421][pear-19421] : phpcs doesn't recognize ${x} as equivalent to $x
+- Fixed bug [#19428][pear-19428] : PHPCS Report "hgblame" doesn't support windows paths
     - Thanks to [Justin Rovang][@rovangju] for the patch
-- Fixed bug #19448 : Problem with detecting remote standards
-- Fixed bug #19463 : Anonymous functions incorrectly being flagged by NonExecutableCodeSniff
-- Fixed bug #19469 : PHP_CodeSniffer_File::getMemberProperties() sets wrong scope
-- Fixed bug #19471 : phpcs on Windows, when using Zend standard, doesn't catch problems
+- Fixed bug [#19448][pear-19448] : Problem with detecting remote standards
+- Fixed bug [#19463][pear-19463] : Anonymous functions incorrectly being flagged by NonExecutableCodeSniff
+- Fixed bug [#19469][pear-19469] : PHP_CodeSniffer_File::getMemberProperties() sets wrong scope
+- Fixed bug [#19471][pear-19471] : phpcs on Windows, when using Zend standard, doesn't catch problems
     - Thanks to [Ivan Habunek][@ihabunek] for the patch
-- Fixed bug #19478 : Incorrect indent detection in PEAR standard
+- Fixed bug [#19478][pear-19478] : Incorrect indent detection in PEAR standard
     - Thanks to [Shane Auckland][@shanethehat] for the patch
-- Fixed bug #19483 : Blame Reports fail with space in directory name
+- Fixed bug [#19483][pear-19483] : Blame Reports fail with space in directory name
+
+[pear-18651]: https://pear.php.net/bugs/bug.php?id=18651
+[pear-19416]: https://pear.php.net/bugs/bug.php?id=19416
+[pear-19421]: https://pear.php.net/bugs/bug.php?id=19421
+[pear-19428]: https://pear.php.net/bugs/bug.php?id=19428
+[pear-19448]: https://pear.php.net/bugs/bug.php?id=19448
+[pear-19463]: https://pear.php.net/bugs/bug.php?id=19463
+[pear-19469]: https://pear.php.net/bugs/bug.php?id=19469
+[pear-19471]: https://pear.php.net/bugs/bug.php?id=19471
+[pear-19478]: https://pear.php.net/bugs/bug.php?id=19478
+[pear-19483]: https://pear.php.net/bugs/bug.php?id=19483
 
 ## [1.3.4] - 2012-05-17
+
 ### Changed
 - Added missing package.xml entries for new Generic FixmeSniff
     - Thanks to [Jaroslav Hanslík][@kukulich] for the patch
@@ -4432,8 +6148,8 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - In particular, allows the Drupal CS to work without needing to symlink it into the PHPCS install
     - Thanks to [Peter Philipp][@das-peter] for the patch
 - Rule references for standards, directories and specific sniffs can now be relative in ruleset.xml files
-    - For example: ref="../MyStandard/Sniffs/Commenting/DisallowHashCommentsSniff.php"
-- Symlinked standards now work correctly, allowing aliasing of installed standards (request #19417)
+    - For example: `ref="../MyStandard/Sniffs/Commenting/DisallowHashCommentsSniff.php"`
+- Symlinked standards now work correctly, allowing aliasing of installed standards (request [#19417][pear-19417])
     - Thanks to [Tom Klingenberg][@ktomk] for the patch
 - Squiz ObjectInstantiationSniff now allows objects to be returned without assigning them to a variable
 - Added Squiz.Commenting.FileComment.MissingShort error message for file comments that only contains tags
@@ -4450,26 +6166,41 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Fixed an issue in Generic UpperCaseConstantNameSniff where errors were incorrectly reported on goto statements
     - Thanks to [Tom Klingenberg][@ktomk] for the patch
 - PEAR FileCommentSniff and ClassCommentSniff now support author emails with a single character in the local part
-    - E.g., a@me.com
+    - E.g., `a@me.com`
     - Thanks to Denis Shapkin for the patch
 
 ### Fixed
-- Fixed bug #19290 : Generic indent sniffer fails for anonymous functions
-- Fixed bug #19324 : Setting show_warnings configuration option does not work
-- Fixed bug #19354 : Not recognizing references passed to method
-- Fixed bug #19361 : CSS tokenizer generates errors when PHP embedded in CSS file
-- Fixed bug #19374 : HEREDOC/NOWDOC Indentation problems
-- Fixed bug #19381 : traits and indentations in traits are not handled properly
-- Fixed bug #19394 : Notice in NonExecutableCodeSniff
-- Fixed bug #19402 : Syntax error when executing phpcs on Windows with parens in PHP path
+- Fixed bug [#19290][pear-19290] : Generic indent sniffer fails for anonymous functions
+- Fixed bug [#19324][pear-19324] : Setting show_warnings configuration option does not work
+- Fixed bug [#19354][pear-19354] : Not recognizing references passed to method
+- Fixed bug [#19361][pear-19361] : CSS tokenizer generates errors when PHP embedded in CSS file
+- Fixed bug [#19374][pear-19374] : HEREDOC/NOWDOC Indentation problems
+- Fixed bug [#19381][pear-19381] : traits and indentations in traits are not handled properly
+- Fixed bug [#19394][pear-19394] : Notice in NonExecutableCodeSniff
+- Fixed bug [#19402][pear-19402] : Syntax error when executing phpcs on Windows with parens in PHP path
     - Thanks to [Tom Klingenberg][@ktomk] for the patch
-- Fixed bug #19411 : magic method error on __construct()
+- Fixed bug [#19411][pear-19411] : magic method error on __construct()
     - The fix required a rewrite of AbstractScopeSniff, so please test any sniffs that extend this class
-- Fixed bug #19412 : Incorrect error about assigning objects to variables when inside inline IF
-- Fixed bug #19413 : php_cs thinks I haven't used a parameter when I have
-- Fixed bug #19414 : php_cs seems to not track variables correctly in heredocs
+- Fixed bug [#19412][pear-19412] : Incorrect error about assigning objects to variables when inside inline IF
+- Fixed bug [#19413][pear-19413] : PHP_CodeSniffer thinks I haven't used a parameter when I have
+- Fixed bug [#19414][pear-19414] : PHP_CodeSniffer seems to not track variables correctly in heredocs
+
+[pear-19290]: https://pear.php.net/bugs/bug.php?id=19290
+[pear-19324]: https://pear.php.net/bugs/bug.php?id=19324
+[pear-19354]: https://pear.php.net/bugs/bug.php?id=19354
+[pear-19361]: https://pear.php.net/bugs/bug.php?id=19361
+[pear-19374]: https://pear.php.net/bugs/bug.php?id=19374
+[pear-19381]: https://pear.php.net/bugs/bug.php?id=19381
+[pear-19394]: https://pear.php.net/bugs/bug.php?id=19394
+[pear-19402]: https://pear.php.net/bugs/bug.php?id=19402
+[pear-19411]: https://pear.php.net/bugs/bug.php?id=19411
+[pear-19412]: https://pear.php.net/bugs/bug.php?id=19412
+[pear-19413]: https://pear.php.net/bugs/bug.php?id=19413
+[pear-19414]: https://pear.php.net/bugs/bug.php?id=19414
+[pear-19417]: https://pear.php.net/bugs/bug.php?id=19417
 
 ## [1.3.3] - 2012-02-07
+
 ### Changed
 - Added new Generic FixmeSniff that shows error messages for all FIXME comments left in your code
     - Thanks to [Sam Graham][@illusori] for the contribution
@@ -4480,25 +6211,37 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to [Sebastian Bergmann][@sebastianbergmann] for the patch
 - Added PHP_CodeSniffer_Tokens::$bracketTokens to give sniff writers fast access to open and close bracket tokens
 - Fixed an issue in AbstractPatternSniff where EOL tokens were not being correctly checked in some cases
-- PHP_CodeSniffer_File::getTokensAsString() now detects incorrect length value (request #19313)
+- PHP_CodeSniffer_File::getTokensAsString() now detects incorrect length value (request [#19313][pear-19313])
 
 ### Fixed
-- Fixed bug #19114 : CodeSniffer checks extension even for single file
-- Fixed bug #19171 : Show sniff codes option is ignored by some report types
+- Fixed bug [#19114][pear-19114] : CodeSniffer checks extension even for single file
+- Fixed bug [#19171][pear-19171] : Show sniff codes option is ignored by some report types
     - Thanks to [Dominic Scheirlinck][@dominics] for the patch
-- Fixed bug #19188 : Lots of PHP Notices when analyzing the Symfony framework
+- Fixed bug [#19188][pear-19188] : Lots of PHP Notices when analyzing the Symfony framework
     - First issue was list-style.. lines in CSS files not properly adjusting open/close bracket positions
-    - Second issue was notices caused by bug #19137
-- Fixed bug #19208 : UpperCaseConstantName reports class members
+    - Second issue was notices caused by bug [#19137][pear-19137]
+- Fixed bug [#19208][pear-19208] : UpperCaseConstantName reports class members
     - Was also a problem with LowerCaseConstantName as well
-- Fixed bug #19256 : T_DOC_COMMENT in CSS files breaks ClassDefinitionNameSpacingSniff
+- Fixed bug [#19256][pear-19256] : T_DOC_COMMENT in CSS files breaks ClassDefinitionNameSpacingSniff
     - Thanks to [Klaus Purer][@klausi] for the patch
-- Fixed bug #19264 : Squiz.PHP.NonExecutableCode does not handle RETURN in CASE without BREAK
-- Fixed bug #19270 : DuplicateClassName does not handle namespaces correctly
-- Fixed bug #19283 : CSS @media rules cause false positives
+- Fixed bug [#19264][pear-19264] : Squiz.PHP.NonExecutableCode does not handle RETURN in CASE without BREAK
+- Fixed bug [#19270][pear-19270] : DuplicateClassName does not handle namespaces correctly
+- Fixed bug [#19283][pear-19283] : CSS @media rules cause false positives
     - Thanks to [Klaus Purer][@klausi] for the patch
 
+[pear-19114]: https://pear.php.net/bugs/bug.php?id=19114
+[pear-19137]: https://pear.php.net/bugs/bug.php?id=19137
+[pear-19171]: https://pear.php.net/bugs/bug.php?id=19171
+[pear-19188]: https://pear.php.net/bugs/bug.php?id=19188
+[pear-19208]: https://pear.php.net/bugs/bug.php?id=19208
+[pear-19256]: https://pear.php.net/bugs/bug.php?id=19256
+[pear-19264]: https://pear.php.net/bugs/bug.php?id=19264
+[pear-19270]: https://pear.php.net/bugs/bug.php?id=19270
+[pear-19283]: https://pear.php.net/bugs/bug.php?id=19283
+[pear-19313]: https://pear.php.net/bugs/bug.php?id=19313
+
 ## [1.3.2] - 2011-12-01
+
 ### Changed
 - Added Generic JSHintSniff to run jshint.js over a JS file and report warnings
     - Set jshint path using phpcs --config-set jshint_path /path/to/jshint-rhino.js
@@ -4517,36 +6260,42 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 ### Fixed
 - Fixed unit tests not running under Windows
     - Thanks to [Jaroslav Hanslík][@kukulich] for the patch
-- Fixed bug #18964 : "$stackPtr must be of type T_VARIABLE" on heredocs and nowdocs
-- Fixed bug #18973 : phpcs is looking for variables in a nowdoc
-- Fixed bug #18974 : Blank line causes "Multi-line function call not indented correctly"
+- Fixed bug [#18964][pear-18964] : "$stackPtr must be of type T_VARIABLE" on heredocs and nowdocs
+- Fixed bug [#18973][pear-18973] : phpcs is looking for variables in a nowdoc
+- Fixed bug [#18974][pear-18974] : Blank line causes "Multi-line function call not indented correctly"
     - Adds new error message to ban empty lines in multi-line function calls
-- Fixed bug #18975 : "Closing parenthesis must be on a line by itself" also causes indentation error
+- Fixed bug [#18975][pear-18975] : "Closing parenthesis must be on a line by itself" also causes indentation error
+
+[pear-18964]: https://pear.php.net/bugs/bug.php?id=18964
+[pear-18973]: https://pear.php.net/bugs/bug.php?id=18973
+[pear-18974]: https://pear.php.net/bugs/bug.php?id=18974
+[pear-18975]: https://pear.php.net/bugs/bug.php?id=18975
 
 ## 1.3.1 - 2011-11-03
+
 ### Changed
-- All report file command line arguments now work with relative paths (request #17240)
-- The extensions command line argument now supports multi-part file extensions (request #17227)
+- All report file command line arguments now work with relative paths (request [#17240][pear-17240])
+- The extensions command line argument now supports multi-part file extensions (request [#17227][pear-17227])
 - Added report type --report=hgblame to show number of errors/warnings committed by authors in a Mercurial repository
     - Has the same functionality as the svnblame report
     - Thanks to [Ben Selby][@benmatselby] for the patch
-- Added T_BACKTICK token type to make detection of backticks easier (request #18799)
+- Added T_BACKTICK token type to make detection of backticks easier (request [#18799][pear-18799])
 - Added pattern matching support to Generic ForbiddenFunctionsSniff
     - If you are extending it and overriding register() or addError() you will need to review your sniff
-- Namespaces are now recognised as scope openers, although they do not require braces (request #18043)
-- Added new ByteOrderMarkSniff to Generic standard (request #18194)
+- Namespaces are now recognised as scope openers, although they do not require braces (request [#18043][pear-18043])
+- Added new ByteOrderMarkSniff to Generic standard (request [#18194][pear-18194])
     - Throws an error if a byte order mark is found in any PHP file
     - Thanks to [Piotr Karas][pear-ryba] for the contribution
-- PHP_Timer output is no longer included in reports when being written to a file (request #18252)
+- PHP_Timer output is no longer included in reports when being written to a file (request [#18252][pear-18252])
     - Also now shown for all report types if nothing is being printed to the screen
-- Generic DeprecatedFunctionSniff now reports functions as deprecated and not simply forbidden (request #18288)
-- PHPCS now accepts file contents from STDIN (request #18447)
-    - Example usage: cat temp.php | phpcs [options]  -OR-  phpcs [options] < temp.php
+- Generic DeprecatedFunctionSniff now reports functions as deprecated and not simply forbidden (request [#18288][pear-18288])
+- PHPCS now accepts file contents from STDIN (request [#18447][pear-18447])
+    - Example usage: `cat temp.php | phpcs [options]`  -OR-  `phpcs [options] < temp.php`
     - Not every sniff will work correctly due to the lack of a valid file path
-- PHP_CodeSniffer_Exception no longer extends PEAR_Exception (request #18483)
+- PHP_CodeSniffer_Exception no longer extends PEAR_Exception (request [#18483][pear-18483])
     - PEAR_Exception added a requirement that PEAR had to be installed
     - PHP_CodeSniffer is not used as a library, so unlikely to have any impact
-- PEAR FileCommentSniff now allows GIT IDs in the version tag (request #14874)
+- PEAR FileCommentSniff now allows GIT IDs in the version tag (request [#14874][pear-14874])
 - AbstractVariableSniff now supports heredocs
     - Also includes some variable detection fixes
     - Thanks to [Sam Graham][@illusori] for the patch
@@ -4555,42 +6304,73 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - PEAR ClassDeclaration sniff now supports indentation checks when using the alternate namespace syntax
     - PEAR.Classes.ClassDeclaration.SpaceBeforeBrace message now contains 2 variables instead of 1
     - Sniff allows overriding of the default indent level, which is set to 4
-    - Fixes bug #18933 : Alternative namespace declaration syntax confuses scope sniffs
+    - Fixes bug [#18933][pear-18933] : Alternative namespace declaration syntax confuses scope sniffs
 
 ### Fixed
 - Fixed issue in Squiz FileCommentSniff where suggested package name was the same as the incorrect package name
 - Fixed some issues with Squiz ArrayDeclarationSniff when using function calls in array values
 - Fixed doc generation so it actually works again
     - Also now works when being run from an SVN checkout as well as when installed as a PEAR package
-    - Should fix bug #18949 : Call to private method from static
-- Fixed bug #18465 : "self::" does not work in lambda functions
+    - Should fix bug [#18949][pear-18949] : Call to private method from static
+- Fixed bug [#18465][pear-18465] : "self::" does not work in lambda functions
     - Also corrects conversion of T_FUNCTION tokens to T_CLOSURE, which was not fixing token condition arrays
-- Fixed bug #18543 : CSS Tokenizer deletes too many #
-- Fixed bug #18624 : @throws namespace problem
+- Fixed bug [#18543][pear-18543] : CSS Tokenizer deletes too many #
+- Fixed bug [#18624][pear-18624] : @throws namespace problem
     - Thanks to [Gavin Davies][pear-boxgav] for the patch
-- Fixed bug #18628 : Generic.Files.LineLength gives incorrect results with Windows line-endings
-- Fixed bug #18633 : CSS Tokenizer doesn't replace T_LIST tokens inside some styles
-- Fixed bug #18657 : anonymous functions wrongly indented
-- Fixed bug #18670 : UpperCaseConstantNameSniff fails on dynamic retrieval of class constant
-- Fixed bug #18709 : Code sniffer sniffs file if even if it's in --ignore
+- Fixed bug [#18628][pear-18628] : Generic.Files.LineLength gives incorrect results with Windows line-endings
+- Fixed bug [#18633][pear-18633] : CSS Tokenizer doesn't replace T_LIST tokens inside some styles
+- Fixed bug [#18657][pear-18657] : anonymous functions wrongly indented
+- Fixed bug [#18670][pear-18670] : UpperCaseConstantNameSniff fails on dynamic retrieval of class constant
+- Fixed bug [#18709][pear-18709] : Code sniffer sniffs file even if it's in --ignore
     - Thanks to [Artem Lopata][@biozshock] for the patch
-- Fixed bug #18762 : Incorrect handling of define and constant in UpperCaseConstantNameSniff
+- Fixed bug [#18762][pear-18762] : Incorrect handling of define and constant in UpperCaseConstantNameSniff
     - Thanks to [Thomas Baker][pear-bakert] for the patch
-- Fixed bug #18769 : CSS Tokenizer doesn't replace T_BREAK tokens inside some styles
-- Fixed bug #18835 : Unreachable errors of inline returns of closure functions
+- Fixed bug [#18769][pear-18769] : CSS Tokenizer doesn't replace T_BREAK tokens inside some styles
+- Fixed bug [#18835][pear-18835] : Unreachable errors of inline returns of closure functions
     - Thanks to [Patrick Schmidt][pear-woellchen] for the patch
-- Fixed bug #18839 : Fix miscount of warnings in AbstractSniffUnitTest.php
+- Fixed bug [#18839][pear-18839] : Fix miscount of warnings in `AbstractSniffUnitTest.php`
     - Thanks to [Sam Graham][@illusori] for the patch
-- Fixed bug #18844 : Generic_Sniffs_CodeAnalysis_UnusedFunctionParameterSniff with empty body
+- Fixed bug [#18844][pear-18844] : Generic_Sniffs_CodeAnalysis_UnusedFunctionParameterSniff with empty body
     - Thanks to [Dmitri Medvedev][pear-dvino] for the patch
-- Fixed bug #18847 : Running Squiz_Sniffs_Classes_ClassDeclarationSniff results in PHP notice
-- Fixed bug #18868 : jslint+rhino: errors/warnings not detected
+- Fixed bug [#18847][pear-18847] : Running Squiz_Sniffs_Classes_ClassDeclarationSniff results in PHP notice
+- Fixed bug [#18868][pear-18868] : jslint+rhino: errors/warnings not detected
     - Thanks to [Christian Weiske][@cweiske] for the patch
-- Fixed bug #18879 : phpcs-svn-pre-commit requires escapeshellarg
+- Fixed bug [#18879][pear-18879] : phpcs-svn-pre-commit requires escapeshellarg
     - Thanks to [Bjorn Katuin][pear-bjorn] for the patch
-- Fixed bug #18951 : weird behaviour with closures and multi-line use () params
+- Fixed bug [#18951][pear-18951] : weird behaviour with closures and multi-line use () params
+
+[pear-14874]: https://pear.php.net/bugs/bug.php?id=14874
+[pear-17227]: https://pear.php.net/bugs/bug.php?id=17227
+[pear-17240]: https://pear.php.net/bugs/bug.php?id=17240
+[pear-18043]: https://pear.php.net/bugs/bug.php?id=18043
+[pear-18194]: https://pear.php.net/bugs/bug.php?id=18194
+[pear-18252]: https://pear.php.net/bugs/bug.php?id=18252
+[pear-18288]: https://pear.php.net/bugs/bug.php?id=18288
+[pear-18447]: https://pear.php.net/bugs/bug.php?id=18447
+[pear-18465]: https://pear.php.net/bugs/bug.php?id=18465
+[pear-18483]: https://pear.php.net/bugs/bug.php?id=18483
+[pear-18543]: https://pear.php.net/bugs/bug.php?id=18543
+[pear-18624]: https://pear.php.net/bugs/bug.php?id=18624
+[pear-18628]: https://pear.php.net/bugs/bug.php?id=18628
+[pear-18633]: https://pear.php.net/bugs/bug.php?id=18633
+[pear-18657]: https://pear.php.net/bugs/bug.php?id=18657
+[pear-18670]: https://pear.php.net/bugs/bug.php?id=18670
+[pear-18709]: https://pear.php.net/bugs/bug.php?id=18709
+[pear-18762]: https://pear.php.net/bugs/bug.php?id=18762
+[pear-18769]: https://pear.php.net/bugs/bug.php?id=18769
+[pear-18799]: https://pear.php.net/bugs/bug.php?id=18799
+[pear-18835]: https://pear.php.net/bugs/bug.php?id=18835
+[pear-18839]: https://pear.php.net/bugs/bug.php?id=18839
+[pear-18844]: https://pear.php.net/bugs/bug.php?id=18844
+[pear-18847]: https://pear.php.net/bugs/bug.php?id=18847
+[pear-18868]: https://pear.php.net/bugs/bug.php?id=18868
+[pear-18879]: https://pear.php.net/bugs/bug.php?id=18879
+[pear-18933]: https://pear.php.net/bugs/bug.php?id=18933
+[pear-18949]: https://pear.php.net/bugs/bug.php?id=18949
+[pear-18951]: https://pear.php.net/bugs/bug.php?id=18951
 
 ## 1.3.0 - 2011-03-17
+
 ### Changed
 - Add a new token T_CLOSURE that replaces T_FUNCTION if the function keyword is anonymous
 - Many Squiz sniffs no longer report errors when checking closures; they are now ignored
@@ -4599,26 +6379,37 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - PEAR FunctionDeclarationSniff now ignores arrays in argument default values when checking multi-line declarations
 
 ### Fixed
-- Fixed bug #18200 : Using custom named ruleset file as standard no longer works
-- Fixed bug #18196 : PEAR MultiLineCondition.SpaceBeforeOpenBrace not consistent with newline chars
-- Fixed bug #18204 : FunctionCommentThrowTag picks wrong exception type when throwing function call
-- Fixed bug #18222 : Add __invoke method to PEAR standard
-- Fixed bug #18235 : Invalid error generation in Squiz.Commenting.FunctionCommentThrowTag
-- Fixed bug #18250 : --standard with relative path skips Standards' "implicit" sniffs
-- Fixed bug #18274 : Multi-line IF and function call indent rules conflict
-- Fixed bug #18282 : Squiz doesn't handle final keyword before function comments
+- Fixed bug [#18200][pear-18200] : Using custom named ruleset file as standard no longer works
+- Fixed bug [#18196][pear-18196] : PEAR MultiLineCondition.SpaceBeforeOpenBrace not consistent with newline chars
+- Fixed bug [#18204][pear-18204] : FunctionCommentThrowTag picks wrong exception type when throwing function call
+- Fixed bug [#18222][pear-18222] : Add __invoke method to PEAR standard
+- Fixed bug [#18235][pear-18235] : Invalid error generation in Squiz.Commenting.FunctionCommentThrowTag
+- Fixed bug [#18250][pear-18250] : --standard with relative path skips Standards' "implicit" sniffs
+- Fixed bug [#18274][pear-18274] : Multi-line IF and function call indent rules conflict
+- Fixed bug [#18282][pear-18282] : Squiz doesn't handle final keyword before function comments
     - Thanks to [Dave Perrett][pear-recurser] for the patch
-- Fixed bug #18336 : Function isUnderscoreName gives php notices
+- Fixed bug [#18336][pear-18336] : Function isUnderscoreName gives PHP notices
+
+[pear-18196]: https://pear.php.net/bugs/bug.php?id=18196
+[pear-18200]: https://pear.php.net/bugs/bug.php?id=18200
+[pear-18204]: https://pear.php.net/bugs/bug.php?id=18204
+[pear-18222]: https://pear.php.net/bugs/bug.php?id=18222
+[pear-18235]: https://pear.php.net/bugs/bug.php?id=18235
+[pear-18250]: https://pear.php.net/bugs/bug.php?id=18250
+[pear-18274]: https://pear.php.net/bugs/bug.php?id=18274
+[pear-18282]: https://pear.php.net/bugs/bug.php?id=18282
+[pear-18336]: https://pear.php.net/bugs/bug.php?id=18336
 
 ## 1.3.0RC2 - 2011-01-14
+
 ### Changed
-- You can now print multiple reports for each run and print each to the screen or a file (request #12434)
-    - Format is --report-[report][=file] (e.g., --report-xml=out.xml)
-    - Printing to screen is done by leaving [file] empty (e.g., --report-xml)
-    - Multiple reports can be specified in this way (e.g., --report-summary --report-xml=out.xml)
-    - The standard --report and --report-file command line arguments are unchanged
-- Added -d command line argument to set php.ini settings while running (request #17244)
-    - Usage is: phpcs -d memory_limit=32M -d ...
+- You can now print multiple reports for each run and print each to the screen or a file (request [#12434][pear-12434])
+    - Format is `--report-[report][=file]` (e.g., `--report-xml=out.xml`)
+    - Printing to screen is done by leaving `[file]` empty (e.g., `--report-xml`)
+    - Multiple reports can be specified in this way (e.g., `--report-summary --report-xml=out.xml`)
+    - The standard `--report` and `--report-file` command line arguments are unchanged
+- Added `-d` command line argument to set `php.ini` settings while running (request [#17244][pear-17244])
+    - Usage is: `phpcs -d memory_limit=32M -d ...`
     - Thanks to [Ben Selby][@benmatselby] for the patch
 - Added -p command line argument to show progress during a run
     - Dot means pass, E means errors found, W means only warnings found and S means skipped file
@@ -4626,22 +6417,22 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Enable by default with --config-set show_progress 1
     - Will not print anything if you are already printing verbose output
     - This has caused a big change in the way PHP_CodeSniffer processes files (API changes around processing)
-- You can now add exclude rules for individual sniffs or error messages (request #17903)
+- You can now add exclude rules for individual sniffs or error messages (request [#17903][pear-17903])
     - Only available when using a ruleset.xml file to specify rules
     - Uses the same exclude-pattern tags as normal but allows them inside rule tags
 - Using the -vvv option will now print a list of sniffs executed for each file and how long they took to process
 - Added Generic ClosureLinterSniff to run Google's gjslint over your JS files
-- The XML and CSV reports now include the severity of the error (request #18165)
+- The XML and CSV reports now include the severity of the error (request [#18165][pear-18165])
     - The Severity column in the CSV report has been renamed to Type, and a new Severity column added for this
 - Fixed issue with Squiz FunctionCommentSniff reporting incorrect type hint when default value uses namespace
     - Thanks to Anti Veeranna for the patch
-- Generic FileLengthSniff now uses iconv_strlen to check line length if an encoding is specified (request #14237)
+- Generic FileLengthSniff now uses iconv_strlen to check line length if an encoding is specified (request [#14237][pear-14237])
 - Generic UnnecessaryStringConcatSniff now allows strings to be combined to form a PHP open or close tag
 - Squiz SwitchDeclarationSniff no longer reports indentation errors for BREAK statements inside IF conditions
 - Interactive mode now always prints the full error report (ignores command line)
 - Improved regular expression detection in JavaScript files
     - Added new T_TYPEOF token that can be used to target the typeof JS operator
-    - Fixes bug #17611 : Regular expression tokens not recognised
+    - Fixes bug [#17611][pear-17611] : Regular expression tokens not recognised
 - Squiz ScopeIndentSniff removed
     - Squiz standard no longer requires additional indents between ob_* methods
     - Also removed Squiz OutputBufferingIndentSniff that was checking the same thing
@@ -4657,74 +6448,111 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Can override the warnings using the code Internal.DetectLineEndings
 
 ### Fixed
-- Fixed bug #17693 : issue with pre-commit hook script with filenames that start with v
-- Fixed bug #17860 : isReference function fails with references in array
+- Fixed bug [#17693][pear-17693] : issue with pre-commit hook script with filenames that start with v
+- Fixed bug [#17860][pear-17860] : isReference function fails with references in array
     - Thanks to [Lincoln Maskey][pear-ljmaskey] for the patch
-- Fixed bug #17902 : Cannot run tests when tests are symlinked into tests dir
+- Fixed bug [#17902][pear-17902] : Cannot run tests when tests are symlinked into tests dir
     - Thanks to [Matt Button][@BRMatt] for the patch
-- Fixed bug #17928 : Improve error message for Generic_Sniffs_PHP_UpperCaseConstantSniff
+- Fixed bug [#17928][pear-17928] : Improve error message for Generic_Sniffs_PHP_UpperCaseConstantSniff
     - Thanks to [Stefano Kowalke][@Konafets] for the patch
-- Fixed bug #18039 : JS Tokenizer crash when ] is last character in file
-- Fixed bug #18047 : Incorrect handling of namespace aliases as constants
+- Fixed bug [#18039][pear-18039] : JS Tokenizer crash when ] is last character in file
+- Fixed bug [#18047][pear-18047] : Incorrect handling of namespace aliases as constants
     - Thanks to [Dmitri Medvedev][pear-dvino] for the patch
-- Fixed bug #18072 : Impossible to exclude path from processing when symlinked
-- Fixed bug #18073 : Squiz.PHP.NonExecutableCode fault
-- Fixed bug #18117 : PEAR coding standard: Method constructor not sniffed as a function
-- Fixed bug #18135 : Generic FunctionCallArgumentSpacingSniff reports function declaration errors
-- Fixed bug #18140 : Generic scope indent in exact mode: strange expected/found values for switch
-- Fixed bug #18145 : Sniffs are not loaded for custom ruleset file
+- Fixed bug [#18072][pear-18072] : Impossible to exclude path from processing when symlinked
+- Fixed bug [#18073][pear-18073] : Squiz.PHP.NonExecutableCode fault
+- Fixed bug [#18117][pear-18117] : PEAR coding standard: Method constructor not sniffed as a function
+- Fixed bug [#18135][pear-18135] : Generic FunctionCallArgumentSpacingSniff reports function declaration errors
+- Fixed bug [#18140][pear-18140] : Generic scope indent in exact mode: strange expected/found values for switch
+- Fixed bug [#18145][pear-18145] : Sniffs are not loaded for custom ruleset file
     - Thanks to [Scott McCammon][pear-mccammos] for the patch
-- Fixed bug #18152 : While and do-while with AbstractPatternSniff
-- Fixed bug #18191 : Squiz.PHP.LowercasePHPFunctions does not work with new Date()
-- Fixed bug #18193 : CodeSniffer doesn't reconize CR (\r) line endings
+- Fixed bug [#18152][pear-18152] : While and do-while with AbstractPatternSniff
+- Fixed bug [#18191][pear-18191] : Squiz.PHP.LowercasePHPFunctions does not work with new Date()
+- Fixed bug [#18193][pear-18193] : CodeSniffer doesn't reconize CR (\r) line endings
+
+[pear-12434]: https://pear.php.net/bugs/bug.php?id=12434
+[pear-14237]: https://pear.php.net/bugs/bug.php?id=14237
+[pear-17244]: https://pear.php.net/bugs/bug.php?id=17244
+[pear-17611]: https://pear.php.net/bugs/bug.php?id=17611
+[pear-17693]: https://pear.php.net/bugs/bug.php?id=17693
+[pear-17860]: https://pear.php.net/bugs/bug.php?id=17860
+[pear-17902]: https://pear.php.net/bugs/bug.php?id=17902
+[pear-17903]: https://pear.php.net/bugs/bug.php?id=17903
+[pear-17928]: https://pear.php.net/bugs/bug.php?id=17928
+[pear-18039]: https://pear.php.net/bugs/bug.php?id=18039
+[pear-18047]: https://pear.php.net/bugs/bug.php?id=18047
+[pear-18072]: https://pear.php.net/bugs/bug.php?id=18072
+[pear-18073]: https://pear.php.net/bugs/bug.php?id=18073
+[pear-18117]: https://pear.php.net/bugs/bug.php?id=18117
+[pear-18135]: https://pear.php.net/bugs/bug.php?id=18135
+[pear-18140]: https://pear.php.net/bugs/bug.php?id=18140
+[pear-18145]: https://pear.php.net/bugs/bug.php?id=18145
+[pear-18152]: https://pear.php.net/bugs/bug.php?id=18152
+[pear-18165]: https://pear.php.net/bugs/bug.php?id=18165
+[pear-18191]: https://pear.php.net/bugs/bug.php?id=18191
+[pear-18193]: https://pear.php.net/bugs/bug.php?id=18193
 
 ## 1.3.0RC1 - 2010-09-03
+
 ### Changed
-- Added exclude pattern support to ruleset.xml file so you can specify ignore patterns in a standard (request #17683)
+- Added exclude pattern support to ruleset.xml file so you can specify ignore patterns in a standard (request [#17683][pear-17683])
     - Use new exclude-pattern tags to include the ignore rules into your ruleset.xml file
     - See CodeSniffer/Standards/PHPCS/ruleset.xml for an example
 - Added new --encoding command line argument to specify the encoding of the files being checked
     - When set to utf-8, stops the XML-based reports from double-encoding
     - When set to something else, helps the XML-based reports encode to utf-8
-    - Default value is iso-8859-1 but can be changed with --config-set encoding [value]
-- The report is no longer printed to screen when using the --report-file command line option (request #17467)
+    - Default value is iso-8859-1 but can be changed with `--config-set encoding [value]`
+- The report is no longer printed to screen when using the --report-file command line option (request [#17467][pear-17467])
     - If you want to print it to screen as well, use the -v command line argument
-- The SVN and GIT blame reports now also show percentage of reported errors per author (request #17606)
+- The SVN and GIT blame reports now also show percentage of reported errors per author (request [#17606][pear-17606])
     - Thanks to [Ben Selby][@benmatselby] for the patch
 - Updated the SVN pre-commit hook to work with the new severity levels feature
-- Generic SubversionPropertiesSniff now allows properties to have NULL values (request #17682)
+- Generic SubversionPropertiesSniff now allows properties to have NULL values (request [#17682][pear-17682])
     - A null value indicates that the property should exist but the value should not be checked
-- Generic UpperCaseConstantName Sniff now longer complains about the PHPUnit_MAIN_METHOD constant (request #17798)
+- Generic UpperCaseConstantName Sniff now longer complains about the PHPUnit_MAIN_METHOD constant (request [#17798][pear-17798])
 - Squiz FileComment sniff now checks JS files as well as PHP files
 - Squiz FunctionCommentSniff now supports namespaces in type hints
 
 ### Fixed
 - Fixed a problem in Squiz OutputBufferingIndentSniff where block comments were reported as not indented
-- Fixed bug #17092 : Problems with utf8_encode and htmlspecialchars with non-ascii chars
+- Fixed bug [#17092][pear-17092] : Problems with utf8_encode and htmlspecialchars with non-ascii chars
     - Use the new --encoding=utf-8 command line argument if your files are utf-8 encoded
-- Fixed bug #17629 : PHP_CodeSniffer_Tokens::$booleanOperators missing T_LOGICAL_XOR
+- Fixed bug [#17629][pear-17629] : PHP_CodeSniffer_Tokens::$booleanOperators missing T_LOGICAL_XOR
     - Thanks to [Matthew Turland][@elazar] for the patch
-- Fixed bug #17699 : Fatal error generating code coverage with PHPUnit 5.3.0RC1
-- Fixed bug #17718 : Namespace 'use' statement: used global class name is recognized as constant
-- Fixed bug #17734 : Generic SubversionPropertiesSniff complains on non SVN files
-- Fixed bug #17742 : EmbeddedPhpSniff reacts negatively to file without closing php tag
-- Fixed bug #17823 : Notice: Please no longer include PHPUnit/Framework.php
+- Fixed bug [#17699][pear-17699] : Fatal error generating code coverage with PHPUnit 5.3.0RC1
+- Fixed bug [#17718][pear-17718] : Namespace 'use' statement: used global class name is recognized as constant
+- Fixed bug [#17734][pear-17734] : Generic SubversionPropertiesSniff complains on non SVN files
+- Fixed bug [#17742][pear-17742] : EmbeddedPhpSniff reacts negatively to file without closing PHP tag
+- Fixed bug [#17823][pear-17823] : Notice: Please no longer include `PHPUnit/Framework.php`
+
+[pear-17092]: https://pear.php.net/bugs/bug.php?id=17092
+[pear-17467]: https://pear.php.net/bugs/bug.php?id=17467
+[pear-17606]: https://pear.php.net/bugs/bug.php?id=17606
+[pear-17629]: https://pear.php.net/bugs/bug.php?id=17629
+[pear-17682]: https://pear.php.net/bugs/bug.php?id=17682
+[pear-17683]: https://pear.php.net/bugs/bug.php?id=17683
+[pear-17699]: https://pear.php.net/bugs/bug.php?id=17699
+[pear-17718]: https://pear.php.net/bugs/bug.php?id=17718
+[pear-17734]: https://pear.php.net/bugs/bug.php?id=17734
+[pear-17742]: https://pear.php.net/bugs/bug.php?id=17742
+[pear-17798]: https://pear.php.net/bugs/bug.php?id=17798
+[pear-17823]: https://pear.php.net/bugs/bug.php?id=17823
 
 ## 1.3.0a1 - 2010-07-15
+
 ### Changed
-- All CodingStandard.php files have been replaced by ruleset.xml files
+- All `CodingStandard.php` files have been replaced by `ruleset.xml` files
     - Custom standards will need to be converted over to this new format to continue working
 - You can specify a path to your own custom ruleset.xml file by using the --standard command line arg
     - e.g., phpcs --standard=/path/to/my/ruleset.xml
 - Added a new report type --report=gitblame to show how many errors and warnings were committed by each author
     - Has the same functionality as the svnblame report
     - Thanks to [Ben Selby][@benmatselby] for the patch
-- A new token type T_DOLLAR has been added to allow you to sniff for variable variables (feature request #17095)
+- A new token type T_DOLLAR has been added to allow you to sniff for variable variables (feature request [#17095][pear-17095])
     - Thanks to [Ian Young][pear-youngian] for the patch
-- JS tokenizer now supports T_POWER (^) and T_MOD_EQUAL (%=) tokens (feature request #17441)
+- JS tokenizer now supports T_POWER (^) and T_MOD_EQUAL (%=) tokens (feature request [#17441][pear-17441])
 - If you have PHP_Timer installed, you'll now get a time/memory summary at the end of a script run
     - Only happens when printing reports that are designed to be read on the command line
-- Added Generic DeprecatedFunctionsSniff to warn about the use of deprecated functions (feature request #16694)
+- Added Generic DeprecatedFunctionsSniff to warn about the use of deprecated functions (feature request [#16694][pear-16694])
     - Thanks to [Sebastian Bergmann][@sebastianbergmann] for the patch
 - Added Squiz LogicalOperatorSniff to ensure that logical operators are surrounded by single spaces
 - Added MySource ChannelExceptionSniff to ensure action files only throw ChannelException
@@ -4742,22 +6570,38 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 ### Fixed
 - Fixed a problem where Generic CodeAnalysisSniff could show warnings if checking multi-line strings
 - Fixed error messages in Squiz ArrayDeclarationSniff reporting incorrect number of found and expected spaces
-- Fixed bug #17048 : False positive in Squiz_WhiteSpace_ScopeKeywordSpacingSniff
-- Fixed bug #17054 : phpcs more strict than PEAR CS regarding function parameter spacing
-- Fixed bug #17096 : Notice: Undefined index: scope_condition in ScopeClosingBraceSniff.php
+- Fixed bug [#17048][pear-17048] : False positive in Squiz_WhiteSpace_ScopeKeywordSpacingSniff
+- Fixed bug [#17054][pear-17054] : phpcs more strict than PEAR CS regarding function parameter spacing
+- Fixed bug [#17096][pear-17096] : Notice: Undefined index: `scope_condition` in `ScopeClosingBraceSniff.php`
     - Moved PEAR.Functions.FunctionCallArgumentSpacing to Generic.Functions.FunctionCallArgumentSpacing
-- Fixed bug #17144 : Deprecated: Function eregi() is deprecated
-- Fixed bug #17236 : PHP Warning due to token_get_all() in DoubleQuoteUsageSniff
-- Fixed bug #17243 : Alternate Switch Syntax causes endless loop of Notices in SwitchDeclaration
-- Fixed bug #17313 : Bug with switch case structure
-- Fixed bug #17331 : Possible parse error: interfaces may not include member vars
-- Fixed bug #17337 : CSS tokenizer fails on quotes urls
-- Fixed bug #17420 : Uncaught exception when comment before function brace
-- Fixed bug #17503 : closures formatting is not supported
+- Fixed bug [#17144][pear-17144] : Deprecated: Function eregi() is deprecated
+- Fixed bug [#17236][pear-17236] : PHP Warning due to token_get_all() in DoubleQuoteUsageSniff
+- Fixed bug [#17243][pear-17243] : Alternate Switch Syntax causes endless loop of Notices in SwitchDeclaration
+- Fixed bug [#17313][pear-17313] : Bug with switch case structure
+- Fixed bug [#17331][pear-17331] : Possible parse error: interfaces may not include member vars
+- Fixed bug [#17337][pear-17337] : CSS tokenizer fails on quotes urls
+- Fixed bug [#17420][pear-17420] : Uncaught exception when comment before function brace
+- Fixed bug [#17503][pear-17503] : closures formatting is not supported
+
+[pear-16694]: https://pear.php.net/bugs/bug.php?id=16694
+[pear-17048]: https://pear.php.net/bugs/bug.php?id=17048
+[pear-17054]: https://pear.php.net/bugs/bug.php?id=17054
+[pear-17095]: https://pear.php.net/bugs/bug.php?id=17095
+[pear-17096]: https://pear.php.net/bugs/bug.php?id=17096
+[pear-17144]: https://pear.php.net/bugs/bug.php?id=17144
+[pear-17236]: https://pear.php.net/bugs/bug.php?id=17236
+[pear-17243]: https://pear.php.net/bugs/bug.php?id=17243
+[pear-17313]: https://pear.php.net/bugs/bug.php?id=17313
+[pear-17331]: https://pear.php.net/bugs/bug.php?id=17331
+[pear-17337]: https://pear.php.net/bugs/bug.php?id=17337
+[pear-17420]: https://pear.php.net/bugs/bug.php?id=17420
+[pear-17441]: https://pear.php.net/bugs/bug.php?id=17441
+[pear-17503]: https://pear.php.net/bugs/bug.php?id=17503
 
 ## 1.2.2 - 2010-01-27
+
 ### Changed
-- The core PHP_CodeSniffer_File methods now understand the concept of closures (feature request #16866)
+- The core PHP_CodeSniffer_File methods now understand the concept of closures (feature request [#16866][pear-16866])
     - Thanks to [Christian Kaps][@akkie] for the sample code
 - Sniffs can now specify violation codes for each error and warning they add
     - Future versions will allow you to override messages and severities using these codes
@@ -4796,7 +6640,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Squiz VariableCommentSniff now ensures the open comment tag is the only content on the first line
 - Squiz NonExecutableCodeSniff now warns about empty return statements that are not required
 - Removed ForbiddenStylesSniff from Squiz standard
-    - It is now in in the MySource standard as BrowserSpecificStylesSniff
+    - It is now in the MySource standard as BrowserSpecificStylesSniff
     - New BrowserSpecificStylesSniff ignores files with browser-specific suffixes
 - MySource IncludeSystemSniff no longer throws errors when extending the Exception class
 - MySource IncludeSystemSniff no longer throws errors for the abstract widget class
@@ -4808,22 +6652,36 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 
 ### Fixed
 - Fixed a problem with the SVN pre-commit hook for PHP versions without vertical whitespace regex support
-- Fixed bug #16740 : False positives for heredoc strings and unused parameter sniff
-- Fixed bug #16794 : ValidLogicalOperatorsSniff doesn't report operators not in lowercase
-- Fixed bug #16804 : Report filename is shortened too much
-- Fixed bug #16821 : Bug in Squiz_Sniffs_WhiteSpace_OperatorSpacingSniff
+- Fixed bug [#16740][pear-16740] : False positives for heredoc strings and unused parameter sniff
+- Fixed bug [#16794][pear-16794] : ValidLogicalOperatorsSniff doesn't report operators not in lowercase
+- Fixed bug [#16804][pear-16804] : Report filename is shortened too much
+- Fixed bug [#16821][pear-16821] : Bug in Squiz_Sniffs_WhiteSpace_OperatorSpacingSniff
     - Thanks to [Jaroslav Hanslík][@kukulich] for the patch
-- Fixed bug #16836 : Notice raised when using semicolon to open case
-- Fixed bug #16855 : Generic standard sniffs incorrectly for define() method
-- Fixed bug #16865 : Two bugs in Squiz_Sniffs_WhiteSpace_OperatorSpacingSniff
+- Fixed bug [#16836][pear-16836] : Notice raised when using semicolon to open case
+- Fixed bug [#16855][pear-16855] : Generic standard sniffs incorrectly for define() method
+- Fixed bug [#16865][pear-16865] : Two bugs in Squiz_Sniffs_WhiteSpace_OperatorSpacingSniff
     - Thanks to [Jaroslav Hanslík][@kukulich] for the patch
-- Fixed bug #16902 : Inline If Declaration bug
-- Fixed bug #16960 : False positive for late static binding in Squiz/ScopeKeywordSpacingSniff
+- Fixed bug [#16902][pear-16902] : Inline If Declaration bug
+- Fixed bug [#16960][pear-16960] : False positive for late static binding in Squiz/ScopeKeywordSpacingSniff
     - Thanks to [Jakub Tománek][pear-thezero] for the patch
-- Fixed bug #16976 : The phpcs attempts to process symbolic links that don't resolve to files
-- Fixed bug #17017 : Including one file in the files sniffed alters errors reported for another file
+- Fixed bug [#16976][pear-16976] : The phpcs attempts to process symbolic links that don't resolve to files
+- Fixed bug [#17017][pear-17017] : Including one file in the files sniffed alters errors reported for another file
+
+[pear-16740]: https://pear.php.net/bugs/bug.php?id=16740
+[pear-16794]: https://pear.php.net/bugs/bug.php?id=16794
+[pear-16804]: https://pear.php.net/bugs/bug.php?id=16804
+[pear-16821]: https://pear.php.net/bugs/bug.php?id=16821
+[pear-16836]: https://pear.php.net/bugs/bug.php?id=16836
+[pear-16855]: https://pear.php.net/bugs/bug.php?id=16855
+[pear-16865]: https://pear.php.net/bugs/bug.php?id=16865
+[pear-16866]: https://pear.php.net/bugs/bug.php?id=16866
+[pear-16902]: https://pear.php.net/bugs/bug.php?id=16902
+[pear-16960]: https://pear.php.net/bugs/bug.php?id=16960
+[pear-16976]: https://pear.php.net/bugs/bug.php?id=16976
+[pear-17017]: https://pear.php.net/bugs/bug.php?id=17017
 
 ## 1.2.1 - 2009-11-17
+
 ### Changed
 - Added a new report type --report=svnblame to show how many errors and warnings were committed by each author
     - Also shows the percentage of their code that are errors and warnings
@@ -4832,10 +6690,10 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - You can also use the -s command line argument to see the different types of errors authors are committing
     - You can use the -v command line argument to see all authors, even if they have no errors or warnings
 - Added a new command line argument --report-width to allow you to set the column width of screen reports
-    - Reports wont accept values less than 70 or else they get too small
+    - Reports won't accept values less than 70 or else they get too small
     - Can also be set via a config var: phpcs --config-set report_width 100
 - You can now get PHP_CodeSniffer to ignore a whole file by adding @codingStandardsIgnoreFile in the content
-    - If you put it in the first two lines the file wont even be tokenized, so it will be much quicker
+    - If you put it in the first two lines the file won't even be tokenized, so it will be much quicker
 - Reports now print their file lists in alphabetical order
 - PEAR FunctionDeclarationSniff now reports error for incorrect closing bracket placement in multi-line definitions
 - Added Generic CallTimePassByReferenceSniff to prohibit the passing of variables into functions by reference
@@ -4860,25 +6718,41 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 
 ### Fixed
 - Fixed an issue with Generic UnnecessaryStringConcatSniff where it incorrectly suggested removing a concat
-- Fixed bug #16530 : ScopeIndentSniff reports false positive
-- Fixed bug #16533 : Duplicate errors and warnings
-- Fixed bug #16563 : Check file extensions problem in phpcs-svn-pre-commit
+- Fixed bug [#16530][pear-16530] : ScopeIndentSniff reports false positive
+- Fixed bug [#16533][pear-16533] : Duplicate errors and warnings
+- Fixed bug [#16563][pear-16563] : Check file extensions problem in phpcs-svn-pre-commit
     - Thanks to [Kaijung Chen][pear-et3w503] for the patch
-- Fixed bug #16592 : Object operator indentation incorrect when first operator is on a new line
-- Fixed bug #16641 : Notice output
-- Fixed bug #16682 : Squiz_Sniffs_Strings_DoubleQuoteUsageSniff reports string "\0" as invalid
-- Fixed bug #16683 : Typing error in PHP_CodeSniffer_CommentParser_AbstractParser
-- Fixed bug #16684 : Bug in Squiz_Sniffs_PHP_NonExecutableCodeSniff
-- Fixed bug #16692 : Spaces in paths in Squiz_Sniffs_Debug_JavaScriptLintSniff
+- Fixed bug [#16592][pear-16592] : Object operator indentation incorrect when first operator is on a new line
+- Fixed bug [#16641][pear-16641] : Notice output
+- Fixed bug [#16682][pear-16682] : Squiz_Sniffs_Strings_DoubleQuoteUsageSniff reports string "\0" as invalid
+- Fixed bug [#16683][pear-16683] : Typing error in PHP_CodeSniffer_CommentParser_AbstractParser
+- Fixed bug [#16684][pear-16684] : Bug in Squiz_Sniffs_PHP_NonExecutableCodeSniff
+- Fixed bug [#16692][pear-16692] : Spaces in paths in Squiz_Sniffs_Debug_JavaScriptLintSniff
     - Thanks to [Jaroslav Hanslík][@kukulich] for the patch
-- Fixed bug #16696 : Spelling error in MultiLineConditionSniff
-- Fixed bug #16697 : MultiLineConditionSniff incorrect result with inline IF
-- Fixed bug #16698 : Notice in JavaScript Tokenizer
-- Fixed bug #16736 : Multi-files sniffs aren't processed when FILE is a single directory
+- Fixed bug [#16696][pear-16696] : Spelling error in MultiLineConditionSniff
+- Fixed bug [#16697][pear-16697] : MultiLineConditionSniff incorrect result with inline IF
+- Fixed bug [#16698][pear-16698] : Notice in JavaScript Tokenizer
+- Fixed bug [#16736][pear-16736] : Multi-files sniffs aren't processed when FILE is a single directory
     - Thanks to [Alexey Shein][pear-conf] for the patch
-- Fixed bug #16792 : Bug in Generic_Sniffs_PHP_ForbiddenFunctionsSniff
+- Fixed bug [#16792][pear-16792] : Bug in Generic_Sniffs_PHP_ForbiddenFunctionsSniff
+
+[pear-16530]: https://pear.php.net/bugs/bug.php?id=16530
+[pear-16533]: https://pear.php.net/bugs/bug.php?id=16533
+[pear-16563]: https://pear.php.net/bugs/bug.php?id=16563
+[pear-16592]: https://pear.php.net/bugs/bug.php?id=16592
+[pear-16641]: https://pear.php.net/bugs/bug.php?id=16641
+[pear-16682]: https://pear.php.net/bugs/bug.php?id=16682
+[pear-16683]: https://pear.php.net/bugs/bug.php?id=16683
+[pear-16684]: https://pear.php.net/bugs/bug.php?id=16684
+[pear-16692]: https://pear.php.net/bugs/bug.php?id=16692
+[pear-16696]: https://pear.php.net/bugs/bug.php?id=16696
+[pear-16697]: https://pear.php.net/bugs/bug.php?id=16697
+[pear-16698]: https://pear.php.net/bugs/bug.php?id=16698
+[pear-16736]: https://pear.php.net/bugs/bug.php?id=16736
+[pear-16792]: https://pear.php.net/bugs/bug.php?id=16792
 
 ## 1.2.0 - 2009-08-17
+
 ### Changed
 - Installed standards are now favoured over custom standards when using the cmd line arg with relative paths
 - Unit tests now use a lot less memory while running
@@ -4887,34 +6761,55 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Removed unused ValidArrayIndexNameSniff from the Squiz standard
 
 ### Fixed
-- Fixed bug #16424 : SubversionPropertiesSniff print PHP Warning
-- Fixed bug #16450 : Constant PHP_CODESNIFFER_VERBOSITY already defined (unit tests)
-- Fixed bug #16453 : function declaration long line splitted error
-- Fixed bug #16482 : phpcs-svn-pre-commit ignores extensions parameter
+- Fixed bug [#16424][pear-16424] : SubversionPropertiesSniff print PHP Warning
+- Fixed bug [#16450][pear-16450] : Constant `PHP_CODESNIFFER_VERBOSITY` already defined (unit tests)
+- Fixed bug [#16453][pear-16453] : function declaration long line splitted error
+- Fixed bug [#16482][pear-16482] : phpcs-svn-pre-commit ignores extensions parameter
+
+[pear-16424]: https://pear.php.net/bugs/bug.php?id=16424
+[pear-16450]: https://pear.php.net/bugs/bug.php?id=16450
+[pear-16453]: https://pear.php.net/bugs/bug.php?id=16453
+[pear-16482]: https://pear.php.net/bugs/bug.php?id=16482
 
 ## 1.2.0RC3 - 2009-07-07
+
 ### Changed
-- You can now use @codingStandardsIgnoreStart and @...End comments to suppress messages (feature request #14002)
-- A warning is now included for files without any code when short_open_tag is set to Off (feature request #12952)
-- You can now use relative paths to your custom standards with the --standard cmd line arg (feature request #14967)
-- You can now override magic methods and functions in PEAR ValidFunctionNameSniff (feature request #15830)
+- You can now use @codingStandardsIgnoreStart and @...End comments to suppress messages (feature request [#14002][pear-14002])
+- A warning is now included for files without any code when short_open_tag is set to Off (feature request [#12952][pear-12952])
+- You can now use relative paths to your custom standards with the --standard cmd line arg (feature request [#14967][pear-14967])
+- You can now override magic methods and functions in PEAR ValidFunctionNameSniff (feature request [#15830][pear-15830])
 - MySource IncludeSystemSniff now recognises widget action classes
 - MySource IncludeSystemSniff now knows about unit test classes and changes rules accordingly
 
+[pear-12952]: https://pear.php.net/bugs/bug.php?id=12952
+[pear-14002]: https://pear.php.net/bugs/bug.php?id=14002
+[pear-14967]: https://pear.php.net/bugs/bug.php?id=14967
+[pear-15830]: https://pear.php.net/bugs/bug.php?id=15830
+
 ## 1.2.0RC2 - 2009-05-25
+
 ### Changed
-- Test suite can now be run using the full path to AllTests.php (feature request #16179)
+- Test suite can now be run using the full path to `AllTests.php` (feature request [#16179][pear-16179])
 
 ### Fixed
-- Fixed bug #15980 : PHP_CodeSniffer change php current directory
+- Fixed bug [#15980][pear-15980] : PHP_CodeSniffer change PHP current directory
     - Thanks to [Dolly Aswin Harahap][pear-dollyaswin] for the patch
-- Fixed bug #16001 : Notice triggered
-- Fixed bug #16054 : phpcs-svn-pre-commit not showing any errors
-- Fixed bug #16071 : Fatal error: Uncaught PHP_CodeSniffer_Exception
-- Fixed bug #16170 : Undefined Offset -1 in MultiLineConditionSniff.php on line 68
-- Fixed bug #16175 : Bug in Squiz-IncrementDecrementUsageSniff
+- Fixed bug [#16001][pear-16001] : Notice triggered
+- Fixed bug [#16054][pear-16054] : phpcs-svn-pre-commit not showing any errors
+- Fixed bug [#16071][pear-16071] : Fatal error: Uncaught PHP_CodeSniffer_Exception
+- Fixed bug [#16170][pear-16170] : Undefined Offset -1 in `MultiLineConditionSniff.php` on line 68
+- Fixed bug [#16175][pear-16175] : Bug in Squiz-IncrementDecrementUsageSniff
+
+[pear-15980]: https://pear.php.net/bugs/bug.php?id=15980
+[pear-16001]: https://pear.php.net/bugs/bug.php?id=16001
+[pear-16054]: https://pear.php.net/bugs/bug.php?id=16054
+[pear-16071]: https://pear.php.net/bugs/bug.php?id=16071
+[pear-16170]: https://pear.php.net/bugs/bug.php?id=16170
+[pear-16175]: https://pear.php.net/bugs/bug.php?id=16175
+[pear-16179]: https://pear.php.net/bugs/bug.php?id=16179
 
 ## 1.2.0RC1 - 2009-03-09
+
 ### Changed
 - Reports that are output to a file now include a trailing newline at the end of the file
 - Fixed sniff names not shown in -vvv token processing output
@@ -4931,23 +6826,32 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 
 ### Fixed
 - Fixed the incorrect tokenizing of multi-line block comments in CSS files
-- Fixed bug #15383 : Uncaught PHP_CodeSniffer_Exception
-- Fixed bug #15408 : An unexpected exception has been caught: Undefined offset: 2
-- Fixed bug #15519 : Uncaught PHP_CodeSniffer_Exception
-- Fixed bug #15624 : Pre-commit hook fails with PHP errors
-- Fixed bug #15661 : Uncaught PHP_CodeSniffer_Exception
-- Fixed bug #15722 : "declare(encoding = 'utf-8');" leads to "Missing file doc comment"
-- Fixed bug #15910 : Object operator indention not calculated correctly
+- Fixed bug [#15383][pear-15383] : Uncaught PHP_CodeSniffer_Exception
+- Fixed bug [#15408][pear-15408] : An unexpected exception has been caught: Undefined offset: 2
+- Fixed bug [#15519][pear-15519] : Uncaught PHP_CodeSniffer_Exception
+- Fixed bug [#15624][pear-15624] : Pre-commit hook fails with PHP errors
+- Fixed bug [#15661][pear-15661] : Uncaught PHP_CodeSniffer_Exception
+- Fixed bug [#15722][pear-15722] : "declare(encoding = 'utf-8');" leads to "Missing file doc comment"
+- Fixed bug [#15910][pear-15910] : Object operator indention not calculated correctly
+
+[pear-15383]: https://pear.php.net/bugs/bug.php?id=15383
+[pear-15408]: https://pear.php.net/bugs/bug.php?id=15408
+[pear-15519]: https://pear.php.net/bugs/bug.php?id=15519
+[pear-15624]: https://pear.php.net/bugs/bug.php?id=15624
+[pear-15661]: https://pear.php.net/bugs/bug.php?id=15661
+[pear-15722]: https://pear.php.net/bugs/bug.php?id=15722
+[pear-15910]: https://pear.php.net/bugs/bug.php?id=15910
 
 ## 1.2.0a1 - 2008-12-18
+
 ### Changed
 - PHP_CodeSniffer now has a CSS tokenizer for checking CSS files
 - Added support for a new multi-file sniff that sniffs all processed files at once
 - Added new output format --report=emacs to output errors using the emacs standard compile output format
     - Thanks to Len Trigg for the contribution
-- Reports can now be written to a file using the --report-file command line argument (feature request #14953)
+- Reports can now be written to a file using the --report-file command line argument (feature request [#14953][pear-14953])
     - The report is also written to screen when using this argument
-- The CheckStyle, CSV and XML reports now include a source for each error and warning (feature request #13242)
+- The CheckStyle, CSV and XML reports now include a source for each error and warning (feature request [#13242][pear-13242])
     - A new report type --report=source can be used to show you the most common errors in your files
 - Added new command line argument -s to show error sources in all reports
 - Added new command line argument --sniffs to specify a list of sniffs to restrict checking to
@@ -5022,7 +6926,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Squiz standard now uses Generic UnnecessaryStringConcatSniff
 - Squiz standard now uses PEAR MultiLineAssignmentSniff
 - Squiz standard now uses PEAR MultiLineConditionSniff
-- Zend standard now uses OpeningFunctionBraceBsdAllmanSniff (feature request #14647)
+- Zend standard now uses OpeningFunctionBraceBsdAllmanSniff (feature request [#14647][pear-14647])
 - MySource JoinStringsSniff now bans the use of inline array joins and suggests the + operator
 - Fixed incorrect errors that can be generated from abstract scope sniffs when moving to a new file
 - Core tokenizer now matches orphaned curly braces in the same way as square brackets
@@ -5035,21 +6939,36 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 
 ### Fixed
 - Fixed Squiz DoubleQuoteUsageSniff so it works correctly with short_open_tag=Off
-- Fixed bug #14409 : Output of warnings to log file
-- Fixed bug #14520 : Notice: Undefined offset: 1 in /usr/share/php/PHP/CodeSniffer/File.php on line
-- Fixed bug #14637 : Call to processUnknownArguments() misses second parameter $pos
+- Fixed bug [#14409][pear-14409] : Output of warnings to log file
+- Fixed bug [#14520][pear-14520] : Notice: Undefined offset: 1 in `CodeSniffer/File.php` on line
+- Fixed bug [#14637][pear-14637] : Call to processUnknownArguments() misses second parameter $pos
     - Thanks to [Peter Buri][pear-burci] for the patch
-- Fixed bug #14889 : Lack of clarity: licence or license
-- Fixed bug #15008 : Nested Parentheses in Control Structure Sniffs
-- Fixed bug #15091 : pre-commit hook attempts to sniff folders
+- Fixed bug [#14889][pear-14889] : Lack of clarity: licence or license
+- Fixed bug [#15008][pear-15008] : Nested Parentheses in Control Structure Sniffs
+- Fixed bug [#15091][pear-15091] : pre-commit hook attempts to sniff folders
     - Thanks to [Bruce Weirdan][pear-weirdan] for the patch
-- Fixed bug #15124 : AbstractParser.php uses deprecated split() function
+- Fixed bug [#15124][pear-15124] : `AbstractParser.php` uses deprecated `split()` function
     - Thanks to [Sebastian Bergmann][@sebastianbergmann] for the patch
-- Fixed bug #15188 : PHPCS vs HEREDOC strings
-- Fixed bug #15231 : Notice: Uninitialized string offset: 0 in FileCommentSniff.php on line 555
-- Fixed bug #15336 : Notice: Undefined offset: 2 in /usr/share/php/PHP/CodeSniffer/File.php on line
+- Fixed bug [#15188][pear-15188] : PHPCS vs HEREDOC strings
+- Fixed bug [#15231][pear-15231] : Notice: Uninitialized string offset: 0 in `FileCommentSniff.php` on line 555
+- Fixed bug [#15336][pear-15336] : Notice: Undefined offset: 2 in `CodeSniffer/File.php` on line
+
+[pear-13242]: https://pear.php.net/bugs/bug.php?id=13242
+[pear-14409]: https://pear.php.net/bugs/bug.php?id=14409
+[pear-14520]: https://pear.php.net/bugs/bug.php?id=14520
+[pear-14637]: https://pear.php.net/bugs/bug.php?id=14637
+[pear-14647]: https://pear.php.net/bugs/bug.php?id=14647
+[pear-14889]: https://pear.php.net/bugs/bug.php?id=14889
+[pear-14953]: https://pear.php.net/bugs/bug.php?id=14953
+[pear-15008]: https://pear.php.net/bugs/bug.php?id=15008
+[pear-15091]: https://pear.php.net/bugs/bug.php?id=15091
+[pear-15124]: https://pear.php.net/bugs/bug.php?id=15124
+[pear-15188]: https://pear.php.net/bugs/bug.php?id=15188
+[pear-15231]: https://pear.php.net/bugs/bug.php?id=15231
+[pear-15336]: https://pear.php.net/bugs/bug.php?id=15336
 
 ## 1.1.0 - 2008-07-14
+
 ### Changed
 - PEAR FileCommentSniff now allows tag orders to be overridden in child classes
     - Thanks to Jeff Hodsdon for the patch
@@ -5058,14 +6977,15 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 
 ### Fixed
 - Fixed error in Zend ValidVariableNameSniff when checking vars in form: $class->{$var}
-- Fixed bug #14077 : Fatal error: Uncaught PHP_CodeSniffer_Exception: $stackPtr is not a class member
-- Fixed bug #14168 : Global Function -> Static Method and __autoload()
-- Fixed bug #14238 : Line length not checked at last line of a file
-- Fixed bug #14249 : wrong detection of scope_opener
-- Fixed bug #14250 : ArrayDeclarationSniff emit warnings at malformed array
-- Fixed bug #14251 : --extensions option doesn't work
+- Fixed bug [#14077][pear-14077] : Fatal error: Uncaught PHP_CodeSniffer_Exception: $stackPtr is not a class member
+- Fixed bug [#14168][pear-14168] : Global Function -> Static Method and __autoload()
+- Fixed bug [#14238][pear-14238] : Line length not checked at last line of a file
+- Fixed bug [#14249][pear-14249] : wrong detection of scope_opener
+- Fixed bug [#14250][pear-14250] : ArrayDeclarationSniff emit warnings at malformed array
+- Fixed bug [#14251][pear-14251] : --extensions option doesn't work
 
 ## 1.1.0RC3 - 2008-07-03
+
 ### Changed
 - PEAR FileCommentSniff now allows tag orders to be overridden in child classes
     - Thanks to Jeff Hodsdon for the patch
@@ -5074,33 +6994,46 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 
 ### Fixed
 - Fixed error in Zend ValidVariableNameSniff when checking vars in form: $class->{$var}
-- Fixed bug #14077 : Fatal error: Uncaught PHP_CodeSniffer_Exception: $stackPtr is not a class member
-- Fixed bug #14168 : Global Function -> Static Method and __autoload()
-- Fixed bug #14238 : Line length not checked at last line of a file
-- Fixed bug #14249 : wrong detection of scope_opener
-- Fixed bug #14250 : ArrayDeclarationSniff emit warnings at malformed array
-- Fixed bug #14251 : --extensions option doesn't work
+- Fixed bug [#14077][pear-14077] : Fatal error: Uncaught PHP_CodeSniffer_Exception: $stackPtr is not a class member
+- Fixed bug [#14168][pear-14168] : Global Function -> Static Method and __autoload()
+- Fixed bug [#14238][pear-14238] : Line length not checked at last line of a file
+- Fixed bug [#14249][pear-14249] : wrong detection of scope_opener
+- Fixed bug [#14250][pear-14250] : ArrayDeclarationSniff emit warnings at malformed array
+- Fixed bug [#14251][pear-14251] : --extensions option doesn't work
+
+[pear-14077]: https://pear.php.net/bugs/bug.php?id=14077
+[pear-14168]: https://pear.php.net/bugs/bug.php?id=14168
+[pear-14238]: https://pear.php.net/bugs/bug.php?id=14238
+[pear-14249]: https://pear.php.net/bugs/bug.php?id=14249
+[pear-14250]: https://pear.php.net/bugs/bug.php?id=14250
+[pear-14251]: https://pear.php.net/bugs/bug.php?id=14251
 
 ## 1.1.0RC2 - 2008-06-13
+
 ### Changed
-- Permission denied errors now stop script execution but still display current errors (feature request #14076)
+- Permission denied errors now stop script execution but still display current errors (feature request [#14076][pear-14076])
 - Added Squiz ValidArrayIndexNameSniff to ensure array indexes do not use camel case
 - Squiz ArrayDeclarationSniff now ensures arrays are not declared with camel case index values
 - PEAR ValidVariableNameSniff now alerts about a possible parse error for member vars inside an interface
 
 ### Fixed
-- Fixed bug #13921 : js parsing fails for comments on last line of file
-- Fixed bug #13922 : crash in case of malformed (but tokenized) php file
+- Fixed bug [#13921][pear-13921] : js parsing fails for comments on last line of file
+- Fixed bug [#13922][pear-13922] : crash in case of malformed (but tokenized) PHP file
     - PEAR and Squiz ClassDeclarationSniff now throw warnings for possible parse errors
     - Squiz ValidClassNameSniff now throws warning for possible parse errors
     - Squiz ClosingDeclarationCommentSniff now throws additional warnings for parse errors
 
+[pear-13921]: https://pear.php.net/bugs/bug.php?id=13921
+[pear-13922]: https://pear.php.net/bugs/bug.php?id=13922
+[pear-14076]: https://pear.php.net/bugs/bug.php?id=14076
+
 ## 1.1.0RC1 - 2008-05-13
+
 ### Changed
 - Added support for multiple tokenizers so PHP_CodeSniffer can check more than just PHP files
     - PHP_CodeSniffer now has a JS tokenizer for checking JavaScript files
     - Sniffs need to be updated to work with additional tokenizers, or new sniffs written for them
-- phpcs now exits with status 2 if the tokenizer extension has been disabled (feature request #13269)
+- phpcs now exits with status 2 if the tokenizer extension has been disabled (feature request [#13269][pear-13269])
 - Added scripts/phpcs-svn-pre-commit that can be used as an SVN pre-commit hook
     - Also reworked the way the phpcs script works to make it easier to wrap it with other functionality
     - Thanks to Jack Bates for the contribution
@@ -5122,7 +7055,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Squiz IncrementDecrementUsageSniff now ensures inc/dec ops are not used in arithmetic operations
 - Squiz FunctionCommentSniff no longer throws errors if return value is mixed but function returns void somewhere
 - Squiz OperatorBracketSniff no allows function call brackets to count as operator brackets
-- Squiz DoubleQuoteUsageSniff now supports \x \f and \v (feature request #13365)
+- Squiz DoubleQuoteUsageSniff now supports \x \f and \v (feature request [#13365][pear-13365])
 - Squiz ComparisonOperatorUsageSniff now supports JS files
 - Squiz ControlSignatureSniff now supports JS files
 - Squiz ForLoopDeclarationSniff now supports JS files
@@ -5148,35 +7081,53 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Fixed error in Squiz BlockCommentSniff where comments for class constants were not ignored
 - Fixed error in Squiz OperatorBracketSniff where negative numbers were ignored during comparisons
 - Fixed error in Squiz FunctionSpacingSniff where functions after member vars reported incorrect spacing
-- Fixed bug #13062 : Interface comments aren't handled in PEAR standard
+- Fixed bug [#13062][pear-13062] : Interface comments aren't handled in PEAR standard
     - Thanks to [Manuel Pichler][@manuelpichler] for the path
-- Fixed bug #13119 : php minimum requirement need to be fix
-- Fixed bug #13156 : Bug in Squiz_Sniffs_PHP_NonExecutableCodeSniff
-- Fixed bug #13158 : Strange behaviour in AbstractPatternSniff
-- Fixed bug #13169 : Undefined variables
-- Fixed bug #13178 : Catch exception in File.php
-- Fixed bug #13254 : Notices output in checkstyle report causes XML issues
-- Fixed bug #13446 : crash with src of phpMyAdmin
+- Fixed bug [#13119][pear-13119] : PHP minimum requirement need to be fix
+- Fixed bug [#13156][pear-13156] : Bug in Squiz_Sniffs_PHP_NonExecutableCodeSniff
+- Fixed bug [#13158][pear-13158] : Strange behaviour in AbstractPatternSniff
+- Fixed bug [#13169][pear-13169] : Undefined variables
+- Fixed bug [#13178][pear-13178] : Catch exception in `File.php`
+- Fixed bug [#13254][pear-13254] : Notices output in checkstyle report causes XML issues
+- Fixed bug [#13446][pear-13446] : crash with src of phpMyAdmin
     - Thanks to [Manuel Pichler][@manuelpichler] for the path
 
+[pear-13062]: https://pear.php.net/bugs/bug.php?id=13062
+[pear-13119]: https://pear.php.net/bugs/bug.php?id=13119
+[pear-13156]: https://pear.php.net/bugs/bug.php?id=13156
+[pear-13158]: https://pear.php.net/bugs/bug.php?id=13158
+[pear-13169]: https://pear.php.net/bugs/bug.php?id=13169
+[pear-13178]: https://pear.php.net/bugs/bug.php?id=13178
+[pear-13254]: https://pear.php.net/bugs/bug.php?id=13254
+[pear-13269]: https://pear.php.net/bugs/bug.php?id=13269
+[pear-13365]: https://pear.php.net/bugs/bug.php?id=13365
+[pear-13446]: https://pear.php.net/bugs/bug.php?id=13446
+
 ## 1.0.1a1 - 2008-04-21
+
 ### Changed
 - Fixed error in PEAR ValidClassNameSniff when checking class names with double underscores
 - Moved Squiz InlineControlStructureSniff into Generic standard
 - PEAR standard now throws warnings for inline control structures
 - Squiz OutputBufferingIndentSniff now ignores the indentation of inline HTML
 - MySource IncludeSystemSniff now ignores usage of ZipArchive
-- Removed "function" from error messages for Generic function brace sniffs (feature request #13820)
+- Removed "function" from error messages for Generic function brace sniffs (feature request [#13820][pear-13820])
 - Generic UpperCaseConstantSniff no longer throws errors for declare(ticks = ...)
     - Thanks to Josh Snyder for the patch
 - Squiz ClosingDeclarationCommentSniff and AbstractVariableSniff now throw warnings for possible parse errors
 
 ### Fixed
-- Fixed bug #13827 : AbstractVariableSniff throws "undefined index"
-- Fixed bug #13846 : Bug in Squiz.NonExecutableCodeSniff
-- Fixed bug #13849 : infinite loop in PHP_CodeSniffer_File::findNext()
+- Fixed bug [#13827][pear-13827] : AbstractVariableSniff throws "undefined index"
+- Fixed bug [#13846][pear-13846] : Bug in Squiz.NonExecutableCodeSniff
+- Fixed bug [#13849][pear-13849] : infinite loop in PHP_CodeSniffer_File::findNext()
+
+[pear-13820]: https://pear.php.net/bugs/bug.php?id=13820
+[pear-13827]: https://pear.php.net/bugs/bug.php?id=13827
+[pear-13846]: https://pear.php.net/bugs/bug.php?id=13846
+[pear-13849]: https://pear.php.net/bugs/bug.php?id=13849
 
 ## 1.0.1 - 2008-02-04
+
 ### Changed
 - Squiz ArrayDeclarationSniff now throws error if the array keyword is followed by a space
 - Squiz ArrayDeclarationSniff now throws error for empty multi-line arrays
@@ -5195,24 +7146,32 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 
 ### Fixed
 - Fixed a problem that caused the parentheses map to sometimes contain incorrect values
-- Fixed bug #12767 : Cant run phpcs from dir with PEAR subdir
-- Fixed bug #12773 : Reserved variables are not detected in strings
+- Fixed bug [#12767][pear-12767] : Cant run phpcs from dir with PEAR subdir
+- Fixed bug [#12773][pear-12773] : Reserved variables are not detected in strings
     - Thanks to [Wilfried Loche][pear-wloche] for the patch
-- Fixed bug #12832 : Tab to space conversion does not work
-- Fixed bug #12888 : extra space indentation = Notice: Uninitialized string offset...
-- Fixed bug #12909 : Default generateDocs function does not work under linux
+- Fixed bug [#12832][pear-12832] : Tab to space conversion does not work
+- Fixed bug [#12888][pear-12888] : extra space indentation = Notice: Uninitialized string offset...
+- Fixed bug [#12909][pear-12909] : Default generateDocs function does not work under linux
     - Thanks to [Paul Smith][pear-thing2b] for the patch
-- Fixed bug #12957 : PHP 5.3 magic method __callStatic
+- Fixed bug [#12957][pear-12957] : PHP 5.3 magic method __callStatic
     - Thanks to [Manuel Pichler][@manuelpichler] for the patch
 
+[pear-12767]: https://pear.php.net/bugs/bug.php?id=12767
+[pear-12773]: https://pear.php.net/bugs/bug.php?id=12773
+[pear-12832]: https://pear.php.net/bugs/bug.php?id=12832
+[pear-12888]: https://pear.php.net/bugs/bug.php?id=12888
+[pear-12909]: https://pear.php.net/bugs/bug.php?id=12909
+[pear-12957]: https://pear.php.net/bugs/bug.php?id=12957
+
 ## 1.0.0 - 2007-12-21
+
 ### Changed
-- You can now specify the full path to a coding standard on the command line (feature request #11886)
+- You can now specify the full path to a coding standard on the command line (feature request [#11886][pear-11886])
     - This allows you to use standards that are stored outside of PHP_CodeSniffer's own Standard dir
-    - You can also specify full paths in the CodingStandard.php include and exclude methods
+    - You can also specify full paths in the `CodingStandard.php` include and exclude methods
     - Classes, dirs and files need to be names as if the standard was part of PHP_CodeSniffer
     - Thanks to Dirk Thomas for the doc generator patch and testing
-- Modified the scope map to keep checking after 3 lines for some tokens (feature request #12561)
+- Modified the scope map to keep checking after 3 lines for some tokens (feature request [#12561][pear-12561])
     - Those tokens that must have an opener (like T_CLASS) now keep looking until EOF
     - Other tokens (like T_FUNCTION) still stop after 3 lines for performance
 - You can now escape commas in ignore patterns so they can be matched in file names
@@ -5229,21 +7188,28 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - MySource IncludeSystemSniff no longer throws errors for the Util package
 
 ### Fixed
-- Fixed bug #12621 : "space after AS" check is wrong
+- Fixed bug [#12621][pear-12621] : "space after AS" check is wrong
     - Thanks to [Satoshi Oikawa][pear-renoiv] for the patch
-- Fixed bug #12645 : error message is wrong
+- Fixed bug [#12645][pear-12645] : error message is wrong
     - Thanks to [Satoshi Oikawa][pear-renoiv] for the patch
-- Fixed bug #12651 : Increment/Decrement Operators Usage at -1
+- Fixed bug [#12651][pear-12651] : Increment/Decrement Operators Usage at -1
+
+[pear-11886]: https://pear.php.net/bugs/bug.php?id=11886
+[pear-12561]: https://pear.php.net/bugs/bug.php?id=12561
+[pear-12621]: https://pear.php.net/bugs/bug.php?id=12621
+[pear-12645]: https://pear.php.net/bugs/bug.php?id=12645
+[pear-12651]: https://pear.php.net/bugs/bug.php?id=12651
 
 ## 1.0.0RC3 - 2007-11-30
+
 ### Changed
 - Added new command line argument --tab-width that will convert tabs to spaces before testing
     - This allows you to use the existing sniffs that check for spaces even when you use tabs
     - Can also be set via a config var: phpcs --config-set tab_width 4
     - A value of zero (the default) tells PHP_CodeSniffer not to replace tabs with spaces
 - You can now change the default report format from "full" to something else
-    - Run: phpcs --config-set report_format [format]
-- Improved performance by optimising the way the scope map is created during tokenising
+    - Run: phpcs `--config-set report_format [format]`
+- Improved performance by optimising the way the scope map is created during tokenizing
 - Added new Squiz DisallowInlineIfSniff to disallow the usage of inline IF statements
 - Fixed incorrect errors being thrown for nested switches in Squiz SwitchDeclarationSniff
 - PEAR FunctionCommentSniff no longer complains about missing comments for @throws tags
@@ -5256,14 +7222,21 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Squiz DisallowMultipleAssignmentsSniff no longer throws errors for assignments in inline IF statements
 
 ### Fixed
-- Fixed bug #12455 : CodeSniffer treats content inside heredoc as PHP code
-- Fixed bug #12471 : Checkstyle report is broken
-- Fixed bug #12476 : PHP4 destructors are reported as error
-- Fixed bug #12513 : Checkstyle XML messages need to be utf8_encode()d
+- Fixed bug [#12455][pear-12455] : CodeSniffer treats content inside heredoc as PHP code
+- Fixed bug [#12471][pear-12471] : Checkstyle report is broken
+- Fixed bug [#12476][pear-12476] : PHP4 destructors are reported as error
+- Fixed bug [#12513][pear-12513] : Checkstyle XML messages need to be utf8_encode()d
     - Thanks to [Sebastian Bergmann][@sebastianbergmann] for the patch.
-- Fixed bug #12517 : getNewlineAfter() and dos files
+- Fixed bug [#12517][pear-12517] : getNewlineAfter() and dos files
+
+[pear-12455]: https://pear.php.net/bugs/bug.php?id=12455
+[pear-12471]: https://pear.php.net/bugs/bug.php?id=12471
+[pear-12476]: https://pear.php.net/bugs/bug.php?id=12476
+[pear-12513]: https://pear.php.net/bugs/bug.php?id=12513
+[pear-12517]: https://pear.php.net/bugs/bug.php?id=12517
 
 ## 1.0.0RC2 - 2007-11-14
+
 ### Changed
 - Added a new Checkstyle report format
     - Like the current XML format but modified to look like Checkstyle output
@@ -5272,14 +7245,14 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Run: phpcs --config-set show_warnings 0
     - If warnings are hidden by default, use the new -w command line argument to override
 - Added new command line argument --config-delete to delete a config value and revert to the default
-- Improved overall performance by optimising tokenising and next/prev methods (feature request #12421)
+- Improved overall performance by optimising tokenizing and next/prev methods (feature request [#12421][pear-12421])
     - Thanks to [Christian Weiske][@cweiske] for the patch
 - Added FunctionCallSignatureSniff to Squiz standard
-- Added @subpackage support to file and class comment sniffs in PEAR standard (feature request #12382)
+- Added @subpackage support to file and class comment sniffs in PEAR standard (feature request [#12382][pear-12382])
     - Thanks to [Carsten Wiedmann][pear-cwiedmann] for the patch
-- An error is now displayed if you use a PHP version less than 5.1.0 (feature request #12380)
+- An error is now displayed if you use a PHP version less than 5.1.0 (feature request [#12380][pear-12380])
     - Thanks to [Carsten Wiedmann][pear-cwiedmann] for the patch
-- phpcs now exits with status 2 if it receives invalid input (feature request #12380)
+- phpcs now exits with status 2 if it receives invalid input (feature request [#12380][pear-12380])
     - This is distinct from status 1, which indicates errors or warnings were found
 - Added new Squiz LanguageConstructSpacingSniff to throw errors for additional whitespace after echo etc.
 - Removed Squiz ValidInterfaceNameSniff
@@ -5290,11 +7263,18 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Fixed incorrect function docblock detection in Squiz FunctionCommentSniff
 - Fixed incorrect errors for list() in Squiz DisallowMultipleAssignmentsSniff
 - Errors no longer thrown if control structure is followed by a CASE's BREAK in Squiz ControlStructureSpacingSniff
-- Fixed bug #12368 : Autoloader cannot be found due to include_path override
+- Fixed bug [#12368][pear-12368] : Autoloader cannot be found due to include_path override
     - Thanks to [Richard Quadling][pear-rquadling] for the patch
-- Fixed bug #12378 : equal sign alignments problem with while()
+- Fixed bug [#12378][pear-12378] : equal sign alignments problem with while()
+
+[pear-12368]: https://pear.php.net/bugs/bug.php?id=12368
+[pear-12378]: https://pear.php.net/bugs/bug.php?id=12378
+[pear-12380]: https://pear.php.net/bugs/bug.php?id=12380
+[pear-12382]: https://pear.php.net/bugs/bug.php?id=12382
+[pear-12421]: https://pear.php.net/bugs/bug.php?id=12421
 
 ## 1.0.0RC1 - 2007-11-01
+
 ### Changed
 - Main phpcs script can now be run from a CVS checkout without installing the package
 - Added a new CSV report format
@@ -5340,14 +7320,18 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Fixed error with multi-token array indexes in Squiz ArrayDeclarationSniff
 - Fixed error with checking shorthand IF statements without a semicolon in Squiz InlineIfDeclarationSniff
 - Fixed error where constants used as default values in function declarations were seen as type hints
-- Fixed bug #12316 : PEAR is no longer the default standard
-- Fixed bug #12321 : wrong detection of missing function docblock
+- Fixed bug [#12316][pear-12316] : PEAR is no longer the default standard
+- Fixed bug [#12321][pear-12321] : wrong detection of missing function docblock
+
+[pear-12316]: https://pear.php.net/bugs/bug.php?id=12316
+[pear-12321]: https://pear.php.net/bugs/bug.php?id=12321
 
 ## 0.9.0 - 2007-09-24
+
 ### Changed
 - Added a config system for setting config data across phpcs runs
 - You can now change the default coding standard from PEAR to something else
-    - Run: phpcs --config-set default_standard [standard]
+    - Run: phpcs `--config-set default_standard [standard]`
 - Added new Zend coding standard to check code against the Zend Framework standards
     - The complete standard is not yet implemented
     - Specify --standard=Zend to use
@@ -5355,46 +7339,55 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
     - Thanks to Holger Kral for the Code Analyzer sniff
 
 ## 0.8.0 - 2007-08-08
+
 ### Changed
-- Added new XML report format; --report=xml (feature request #11535)
+- Added new XML report format; --report=xml (feature request [#11535][pear-11535])
     - Thanks to [Brett Bieber][@saltybeagle] for the patch
-- Added new command line argument --ignore to specify a list of files to skip (feature request #11556)
+- Added new command line argument --ignore to specify a list of files to skip (feature request [#11556][pear-11556])
 - Added PHPCS and MySource coding standards into the core install
 - Scope map no longer gets confused by curly braces that act as string offsets
-- Removed CodeSniffer/SniffException.php as it is no longer used
+- Removed `CodeSniffer/SniffException.php` as it is no longer used
 - Unit tests can now be run directly from a CVS checkout
 - Made private vars and functions protected in PHP_CodeSniffer class so this package can be overridden
 - Added new Metrics category to Generic coding standard
     - Contains Cyclomatic Complexity and Nesting Level sniffs
     - Thanks to Johann-Peter Hartmann for the contribution
-- Added new Generic DisallowTabIndentSniff to throw errors if tabs are used for indentation (feature request #11738)
+- Added new Generic DisallowTabIndentSniff to throw errors if tabs are used for indentation (feature request [#11738][pear-11738])
     - PEAR and Squiz standards use this new sniff to throw more specific indentation errors
-- Generic MultipleStatementAlignmentSniff has new private var to set a padding size limit (feature request #11555)
-- Generic MultipleStatementAlignmentSniff can now handle assignments that span multiple lines (feature request #11561)
+- Generic MultipleStatementAlignmentSniff has new private var to set a padding size limit (feature request [#11555][pear-11555])
+- Generic MultipleStatementAlignmentSniff can now handle assignments that span multiple lines (feature request [#11561][pear-11561])
 - Generic LineLengthSniff now has a max line length after which errors are thrown instead of warnings
     - BC BREAK: Override the protected member var absoluteLineLimit and set it to zero in custom LineLength sniffs
     - Thanks to Johann-Peter Hartmann for the contribution
-- Comment sniff errors about incorrect tag orders are now more descriptive (feature request #11693)
+- Comment sniff errors about incorrect tag orders are now more descriptive (feature request [#11693][pear-11693])
 
 ### Fixed
-- Fixed bug #11473 : Invalid CamelCaps name when numbers used in names
+- Fixed bug [#11473][pear-11473] : Invalid CamelCaps name when numbers used in names
+
+[pear-11473]: https://pear.php.net/bugs/bug.php?id=11473
+[pear-11535]: https://pear.php.net/bugs/bug.php?id=11535
+[pear-11555]: https://pear.php.net/bugs/bug.php?id=11555
+[pear-11556]: https://pear.php.net/bugs/bug.php?id=11556
+[pear-11561]: https://pear.php.net/bugs/bug.php?id=11561
+[pear-11693]: https://pear.php.net/bugs/bug.php?id=11693
+[pear-11738]: https://pear.php.net/bugs/bug.php?id=11738
 
 ## 0.7.0 - 2007-07-02
+
 ### Changed
 - BC BREAK: EOL character is now auto-detected and used instead of hard-coded \n
     - Pattern sniffs must now specify "EOL" instead of "\n" or "\r\n" to use auto-detection
     - Please use $phpcsFile->eolChar to check for newlines instead of hard-coding "\n" or "\r\n"
     - Comment parser classes now require you to pass $phpcsFile as an additional argument
-- BC BREAK: Included and excluded sniffs now require .php extension
-    - Please update your coding standard classes and add ".php" to all sniff entries
-    - See CodeSniffer/Standards/PEAR/PEARCodingStandard.php for an example
-
+- BC BREAK: Included and excluded sniffs now require `.php` extension
+    - Please update your coding standard classes and add `.php` to all sniff entries
+    - See `CodeSniffer/Standards/PEAR/PEARCodingStandard.php` for an example
 - Fixed error where including a directory of sniffs in a coding standard class did not work
-- Coding standard classes can now specify a list of sniffs to exclude as well as include (feature request #11056)
+- Coding standard classes can now specify a list of sniffs to exclude as well as include (feature request [#11056][pear-11056])
 - Two uppercase characters can now be placed side-by-side in class names in Squiz ValidClassNameSniff
-- SVN tags now allowed in PEAR file doc blocks (feature request #11038)
+- SVN tags now allowed in PEAR file doc blocks (feature request [#11038][pear-11038])
     - Thanks to [Torsten Roehr][pear-troehr] for the patch
-- Private methods in commenting sniffs and comment parser are now protected (feature request #11087)
+- Private methods in commenting sniffs and comment parser are now protected (feature request [#11087][pear-11087])
 - Added Generic LineEndingsSniff to check the EOL character of a file
 - PEAR standard now only throws one error per file for incorrect line endings (eg. /r/n)
 - Command line arg -v now shows number of registered sniffs
@@ -5418,36 +7411,53 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Added Squiz LowercaseClassKeywordsSniff to ensure all class declaration keywords are lowercase
 - Added Squiz LowercaseFunctionKeywordsSniff to ensure all function declaration keywords are lowercase
 - Added Squiz LowercasePHPFunctionsSniff to ensure all calls to inbuilt PHP functions are lowercase
-- Added Squiz CastSpacingSniff to ensure cast statements dont contain whitespace
+- Added Squiz CastSpacingSniff to ensure cast statements don't contain whitespace
 - Errors no longer thrown when checking 0 length files with verbosity on
 
 ### Fixed
-- Fixed bug #11105 : getIncludedSniffs() not working anymore
+- Fixed bug [#11105][pear-11105] : getIncludedSniffs() not working anymore
     - Thanks to [Blair Robertson][pear-adviva] for the patch
-- Fixed bug #11120 : Uninitialized string offset in AbstractParser.php on line 200
+- Fixed bug [#11120][pear-11120] : Uninitialized string offset in `AbstractParser.php` on line 200
+
+[pear-11038]: https://pear.php.net/bugs/bug.php?id=11038
+[pear-11056]: https://pear.php.net/bugs/bug.php?id=11056
+[pear-11087]: https://pear.php.net/bugs/bug.php?id=11087
+[pear-11105]: https://pear.php.net/bugs/bug.php?id=11105
+[pear-11120]: https://pear.php.net/bugs/bug.php?id=11120
 
 ## 0.6.0 - 2007-05-15
+
 ### Changed
 - The number of errors and warnings found is now shown for each file while checking the file if verbosity is enabled
-- Now using PHP_EOL instead of hard-coded \n so output looks good on Windows (feature request #10761)
+- Now using PHP_EOL instead of hard-coded \n so output looks good on Windows (feature request [#10761][pear-10761])
     - Thanks to [Carsten Wiedmann][pear-cwiedmann] for the patch.
-- phpcs now exits with status 0 (no errors) or 1 (errors found) (feature request #10348)
-- Added new -l command line argument to stop recursion into directories (feature request #10979)
+- phpcs now exits with status 0 (no errors) or 1 (errors found) (feature request [#10348][pear-10348])
+- Added new -l command line argument to stop recursion into directories (feature request [#10979][pear-10979])
 
 ### Fixed
 - Fixed variable name error causing incorrect error message in Squiz ValidVariableNameSniff
-- Fixed bug #10757 : Error in ControlSignatureSniff
-- Fixed bugs #10751, #10777 : Sniffer class paths handled incorrectly in Windows
+- Fixed bug [#10757][pear-10757] : Error in ControlSignatureSniff
+- Fixed bugs [#10751][pear-10751], [#10777][pear-10777] : Sniffer class paths handled incorrectly in Windows
     - Thanks to [Carsten Wiedmann][pear-cwiedmann] for the patch.
-- Fixed bug #10961 : Error "Last parameter comment requires a blank newline after it" thrown
-- Fixed bug #10983 : phpcs outputs notices when checking invalid PHP
-- Fixed bug #10980 : Incorrect warnings for equals sign
+- Fixed bug [#10961][pear-10961] : Error "Last parameter comment requires a blank newline after it" thrown
+- Fixed bug [#10983][pear-10983] : phpcs outputs notices when checking invalid PHP
+- Fixed bug [#10980][pear-10980] : Incorrect warnings for equals sign
+
+[pear-10348]: https://pear.php.net/bugs/bug.php?id=10348
+[pear-10751]: https://pear.php.net/bugs/bug.php?id=10751
+[pear-10757]: https://pear.php.net/bugs/bug.php?id=10757
+[pear-10761]: https://pear.php.net/bugs/bug.php?id=10761
+[pear-10777]: https://pear.php.net/bugs/bug.php?id=10777
+[pear-10961]: https://pear.php.net/bugs/bug.php?id=10961
+[pear-10979]: https://pear.php.net/bugs/bug.php?id=10979
+[pear-10980]: https://pear.php.net/bugs/bug.php?id=10980
+[pear-10983]: https://pear.php.net/bugs/bug.php?id=10983
 
 ## 0.5.0 - 2007-04-17
+
 ### Changed
 - BC BREAK: Coding standards now require a class to be added so PHP_CodeSniffer can get information from them
     - Please read the end user docs for info about the new class required for all coding standards
-
 - Coding standards can now include sniffs from other standards, or whole standards, without writing new sniff files
 - PHP_CodeSniffer_File::isReference() now correctly returns for references in function declarations
 - PHP_CodeSniffer_File::isReference() now returns false if you don't pass it a T_BITWISE_AND token
@@ -5467,7 +7477,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Errors no longer thrown on __autoload functions in PEAR ValidFunctionNameSniff
 - Errors now thrown for __autoload methods in PEAR ValidFunctionNameSniff
 - Errors now thrown if constructors or destructors have @return tags in Squiz FunctionCommentSniff
-- Errors now thrown if @throws tags dont start with a capital and end with a full stop in Squiz FunctionCommentSniff
+- Errors now thrown if @throws tags don't start with a capital and end with a full stop in Squiz FunctionCommentSniff
 - Errors now thrown for invalid @var tag values in Squiz VariableCommentSniff
 - Errors now thrown for missing doc comment in Squiz VariableCommentSniff
 - Errors now thrown for unspaced operators in FOR loop declarations in Squiz OperatorSpacingSniff
@@ -5475,6 +7485,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Errors now thrown for all missing member variable comments in Squiz VariableCommentSniff
 
 ## 0.4.0 - 2007-02-19
+
 ### Changed
 - Standard name specified with --standard command line argument is no longer case sensitive
 - Long error and warning messages are now wrapped to 80 characters in the full error report (thanks Endre Czirbesz)
@@ -5489,9 +7500,12 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Fixed missing error when multiple statements are not aligned correctly with object operators
 - Fixed incorrect errors for some PHP special variables in Squiz ValidVariableNameSniff
 - Fixed incorrect errors for arrays that only contain other arrays in Squiz ArrayDeclarationSniff
-- Fixed bug #9844 : throw new Exception(\n accidentally reported as error but it ain't
+- Fixed bug [#9844][pear-9844] : throw new Exception(\n accidentally reported as error but it ain't
+
+[pear-9844]: https://pear.php.net/bugs/bug.php?id=9844
 
 ## 0.3.0 - 2007-01-11
+
 ### Changed
 - Updated package.xml to version 2
 - Specifying coding standard on command line is now optional, even if you have multiple standards installed
@@ -5513,14 +7527,20 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Updated file, class and method comments for all files
 
 ### Fixed
-- Fixed bug #9274 : nested_parenthesis element not set for open and close parenthesis tokens
-- Fixed bug #9411 : too few pattern characters cause incorrect error report
+- Fixed bug [#9274][pear-9274] : nested_parenthesis element not set for open and close parenthesis tokens
+- Fixed bug [#9411][pear-9411] : too few pattern characters cause incorrect error report
+
+[pear-9411]: https://pear.php.net/bugs/bug.php?id=9411
 
 ## 0.2.1 - 2006-11-09
+
 ### Fixed
-- Fixed bug #9274 : nested_parenthesis element not set for open and close parenthesis tokens
+- Fixed bug [#9274][pear-9274] : nested_parenthesis element not set for open and close parenthesis tokens
+
+[pear-9274]: https://pear.php.net/bugs/bug.php?id=9274
 
 ## 0.2.0 - 2006-10-13
+
 ### Changed
 - Added a generic standards package that will contain generic sniffs to be used in specific coding standards
     - thanks to Frederic Poeydomenge for the idea
@@ -5539,13 +7559,20 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 
 ### Fixed
 - Fixed some coding standard errors
-- Fixed bug #8834 : Massive memory consumption
-- Fixed bug #8836 : path case issues in package.xml
-- Fixed bug #8843 : confusion on nested switch()
-- Fixed bug #8841 : comments taken as whitespace
-- Fixed bug #8884 : another problem with nested switch() statements
+- Fixed bug [#8834][pear-8834] : Massive memory consumption
+- Fixed bug [#8836][pear-8836] : path case issues in package.xml
+- Fixed bug [#8843][pear-8843] : confusion on nested switch()
+- Fixed bug [#8841][pear-8841] : comments taken as whitespace
+- Fixed bug [#8884][pear-8884] : another problem with nested switch() statements
+
+[pear-8834]: https://pear.php.net/bugs/bug.php?id=8834
+[pear-8836]: https://pear.php.net/bugs/bug.php?id=8836
+[pear-8841]: https://pear.php.net/bugs/bug.php?id=8841
+[pear-8843]: https://pear.php.net/bugs/bug.php?id=8843
+[pear-8884]: https://pear.php.net/bugs/bug.php?id=8884
 
 ## 0.1.1 - 2006-09-25
+
 ### Changed
 - Added unit tests for all PEAR sniffs
 - Exception class now extends from PEAR_Exception
@@ -5554,16 +7581,19 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Fixed summary report so files without errors but with warnings are not shown when warnings are hidden
 
 ## 0.1.0 - 2006-09-19
+
 ### Changed
 - Reorganised package contents to conform to PEAR standards
 - Changed version numbering to conform to PEAR standards
-- Removed duplicate require_once() of Exception.php from CodeSniffer.php
+- Removed duplicate `require_once()` of `Exception.php` from `CodeSniffer.php`
 
 ## 0.0.5 - 2006-09-18
+
 ### Fixed
-- Fixed .bat file for situation where php.ini cannot be found so include_path is not set
+- Fixed `.bat` file for situation where `php.ini` cannot be found so `include_path` is not set
 
 ## 0.0.4 - 2006-08-28
+
 ### Changed
 - Added .bat file for easier running of PHP_CodeSniffer on Windows
 - Sniff that checks method names now works for PHP4 style code where there is no scope keyword
@@ -5582,6 +7612,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Sniff that checks control structure declarations now gives more descriptive error message
 
 ## 0.0.3 - 2006-08-22
+
 ### Changed
 - Added sniff to check for invalid class and interface names
 - Added sniff to check for invalid function and method names
@@ -5593,11 +7624,12 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Fixed error where comments were not allowed on the same line as a control structure declaration
 
 ## 0.0.2 - 2006-07-25
+
 ### Changed
 - Removed the including of checked files to stop errors caused by parsing them
 - Removed the use of reflection so checked files do not have to be included
 - Memory usage has been greatly reduced
-- Much faster tokenising and checking times
+- Much faster tokenizing and checking times
 - Reworked the PEAR coding standard sniffs (much faster now)
 - Fix some bugs with the PEAR scope indentation standard
 - Better checking for installed coding standards
@@ -5607,9 +7639,10 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 - Added an option to hide warnings from reports
 - Added an option to print verbose output (so you know what is going on)
 - Reordered command line args to put switches first (although order is not enforced)
-- Switches can now be specified together (eg. php -nv) as well as separately (phpcs -n -v)
+- Switches can now be specified together (e.g. `phpcs -nv`) as well as separately (`phpcs -n -v`)
 
 ## 0.0.1 - 2006-07-19
+
 ### Added
 - Initial preview release
 
@@ -5618,6 +7651,22 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 -->
 
 [Unreleased]: https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/master...HEAD
+[3.13.2]:     https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.13.1...3.13.2
+[3.13.1]:     https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.13.0...3.13.1
+[3.13.0]:     https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.12.2...3.13.0
+[3.12.2]:     https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.12.1...3.12.2
+[3.12.1]:     https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.12.0...3.12.1
+[3.12.0]:     https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.11.3...3.12.0
+[3.11.3]:     https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.11.2...3.11.3
+[3.11.2]:     https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.11.1...3.11.2
+[3.11.1]:     https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.11.0...3.11.1
+[3.11.0]:     https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.10.3...3.11.0
+[3.10.3]:     https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.10.2...3.10.3
+[3.10.2]:     https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.10.1...3.10.2
+[3.10.1]:     https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.10.0...3.10.1
+[3.10.0]:     https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.9.2...3.10.0
+[3.9.2]:      https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.9.1...3.9.2
+[3.9.1]:      https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.9.0...3.9.1
 [3.9.0]:      https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.8.1...3.9.0
 [3.8.1]:      https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.8.0...3.8.1
 [3.8.0]:      https://github.com/PHPCSStandards/PHP_CodeSniffer/compare/3.7.2...3.8.0
@@ -5732,6 +7781,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 [@annechko]:            https://github.com/annechko
 [@anomiex]:             https://github.com/anomiex
 [@arnested]:            https://github.com/arnested
+[@asispts]:             https://github.com/asispts
 [@asnyder]:             https://github.com/asnyder
 [@Astinus-Eberhard]:    https://github.com/Astinus-Eberhard
 [@axlon]:               https://github.com/axlon
@@ -5739,6 +7789,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 [@becoded]:             https://github.com/becoded
 [@Benjamin-Loison]:     https://github.com/Benjamin-Loison
 [@benmatselby]:         https://github.com/benmatselby
+[@biinari]:             https://github.com/biinari
 [@Billz95]:             https://github.com/Billz95
 [@biozshock]:           https://github.com/biozshock
 [@bkdotcom]:            https://github.com/bkdotcom
@@ -5747,16 +7798,19 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 [@blue32a]:             https://github.com/blue32a
 [@bondas83]:            https://github.com/bondas83
 [@boonkerz]:            https://github.com/boonkerz
+[@braindawg]:           https://github.com/braindawg
 [@BRMatt]:              https://github.com/BRMatt
 [@CandySunPlus]:        https://github.com/CandySunPlus
 [@ceeram]:              https://github.com/ceeram
 [@cixtor]:              https://github.com/cixtor
 [@claylo]:              https://github.com/claylo
 [@codebymikey]:         https://github.com/codebymikey
+[@costdev]:             https://github.com/costdev
 [@covex-nn]:            https://github.com/covex-nn
 [@cweiske]:             https://github.com/cweiske
 [@Daimona]:             https://github.com/Daimona
 [@danez]:               https://github.com/danez
+[@DanielEScherzer]:     https://github.com/DanielEScherzer
 [@DannyvdSluijs]:       https://github.com/DannyvdSluijs
 [@das-peter]:           https://github.com/das-peter
 [@datengraben]:         https://github.com/datengraben
@@ -5764,6 +7818,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 [@Decave]:              https://github.com/Decave
 [@dereuromark]:         https://github.com/dereuromark
 [@derrabus]:            https://github.com/derrabus
+[@devfrey]:             https://github.com/devfrey
 [@deviantintegral]:     https://github.com/deviantintegral
 [@dhensby]:             https://github.com/dhensby
 [@dingo-d]:             https://github.com/dingo-d
@@ -5806,6 +7861,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 [@ivuorinen]:           https://github.com/ivuorinen
 [@jasonmccreary]:       https://github.com/jasonmccreary
 [@javer]:               https://github.com/javer
+[@jaymcp]:              https://github.com/jaymcp
 [@JDGrimes]:            https://github.com/JDGrimes
 [@jedgell]:             https://github.com/jedgell
 [@jeffslofish]:         https://github.com/jeffslofish
@@ -5819,6 +7875,7 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 [@JorisDebonnet]:       https://github.com/JorisDebonnet
 [@josephzidell]:        https://github.com/josephzidell
 [@joshdavis11]:         https://github.com/joshdavis11
+[@jpoliveira08]:        https://github.com/jpoliveira08
 [@jpuck]:               https://github.com/jpuck
 [@jrfnl]:               https://github.com/jrfnl
 [@kdebisschop]:         https://github.com/kdebisschop
@@ -5841,14 +7898,17 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 [@MarkMaldaba]:         https://github.com/MarkMaldaba
 [@martinssipenko]:      https://github.com/martinssipenko
 [@marvasDE]:            https://github.com/marvasDE
+[@maryo]:               https://github.com/maryo
 [@MasterOdin]:          https://github.com/MasterOdin
 [@mathroc]:             https://github.com/mathroc
+[@MatmaRex]:            https://github.com/MatmaRex
 [@maxgalbu]:            https://github.com/maxgalbu
 [@mcuelenaere]:         https://github.com/mcuelenaere
 [@mhujer]:              https://github.com/mhujer
 [@michaelbutler]:       https://github.com/michaelbutler
 [@michalbundyra]:       https://github.com/michalbundyra
 [@Morerice]:            https://github.com/Morerice
+[@mbomb007]:            https://github.com/mbomb007
 [@morozov]:             https://github.com/morozov
 [@mrkrstphr]:           https://github.com/mrkrstphr
 [@mythril]:             https://github.com/mythril
@@ -5864,9 +7924,11 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 [@ondrejmirtes]:        https://github.com/ondrejmirtes
 [@orx0r]:               https://github.com/orx0r
 [@ostrolucky]:          https://github.com/ostrolucky
+[@peterwilsoncc]:       https://github.com/peterwilsoncc
 [@pfrenssen]:           https://github.com/pfrenssen
 [@phil-davis]:          https://github.com/phil-davis
 [@photodude]:           https://github.com/photodude
+[@przemekhernik]:       https://github.com/przemekhernik
 [@r3nat]:               https://github.com/r3nat
 [@raul338]:             https://github.com/raul338
 [@realmfoo]:            https://github.com/realmfoo
@@ -5948,4 +8010,3 @@ Additionally, thanks to [Alexander Turek][@derrabus] for consulting on the repo
 [pear-wloche]:          https://pear.php.net/user/wloche
 [pear-woellchen]:       https://pear.php.net/user/woellchen
 [pear-youngian]:        https://pear.php.net/user/youngian
-
diff --git a/app/vendor/squizlabs/php_codesniffer/README.md b/app/vendor/squizlabs/php_codesniffer/README.md
index d375015b4..6877929bc 100644
--- a/app/vendor/squizlabs/php_codesniffer/README.md
+++ b/app/vendor/squizlabs/php_codesniffer/README.md
@@ -1,16 +1,17 @@
-PHP_CodeSniffer
-=====================================================
+# PHP_CodeSniffer
 
 
 
@@ -47,7 +48,9 @@ php phpcbf.phar -h
 ```
 
 These Phars are signed with the official Release key for PHPCS with the
-fingerprint `95DE 904A B800 754A 11D8 0B60 5E6D DE99 8AB7 3B8E`.
+fingerprint `D91D 8696 3AF3 A29B 6520 4622 97B0 2DD8 E507 1466`.
+
+As of PHP_CodeSniffer 3.10.3, the provenance of PHAR files associated with a release can be verified via [GitHub Artifact Attestations](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds) using the [GitHub CLI tool](https://cli.github.com/) with the following command: `gh attestation verify [phpcs|phpcbf].phar -o PHPCSStandards`.
 
 ### Composer
 If you use Composer, you can install PHP_CodeSniffer system-wide with the following command:
@@ -71,17 +74,19 @@ You will then be able to run PHP_CodeSniffer from the vendor bin directory:
 ./vendor/bin/phpcs -h
 ./vendor/bin/phpcbf -h
 ```
+
 ### Phive
 If you use Phive, you can install PHP_CodeSniffer as a project tool using the following commands:
 ```bash
-phive install --trust-gpg-keys 95DE904AB800754A11D80B605E6DDE998AB73B8E phpcs
-phive install --trust-gpg-keys 95DE904AB800754A11D80B605E6DDE998AB73B8E phpcbf
+phive install --trust-gpg-keys D91D86963AF3A29B6520462297B02DD8E5071466 phpcs
+phive install --trust-gpg-keys D91D86963AF3A29B6520462297B02DD8E5071466 phpcbf
 ```
 You will then be able to run PHP_CodeSniffer from the `tools` directory:
 ```bash
 ./tools/phpcs -h
 ./tools/phpcbf -h
 ```
+
 ### Git Clone
 You can also download the PHP_CodeSniffer source and run the `phpcs` and `phpcbf` commands directly from the Git clone:
 ```bash
@@ -90,6 +95,7 @@ cd PHP_CodeSniffer
 php bin/phpcs -h
 php bin/phpcbf -h
 ```
+
 ## Getting Started
 
 The default coding standard used by PHP_CodeSniffer is the PEAR coding standard. To check a file against the PEAR coding standard, simply specify the file's location:
diff --git a/app/vendor/squizlabs/php_codesniffer/autoload.php b/app/vendor/squizlabs/php_codesniffer/autoload.php
index 7e546bb5b..c295b2ea7 100644
--- a/app/vendor/squizlabs/php_codesniffer/autoload.php
+++ b/app/vendor/squizlabs/php_codesniffer/autoload.php
@@ -16,6 +16,9 @@
 
 namespace PHP_CodeSniffer;
 
+use Composer\Autoload\ClassLoader;
+use Exception;
+
 if (class_exists('PHP_CodeSniffer\Autoload', false) === false) {
     class Autoload
     {
@@ -23,7 +26,8 @@ class Autoload
         /**
          * The composer autoloader.
          *
-         * @var \Composer\Autoload\ClassLoader
+         * @var \Composer\Autoload\ClassLoader|false|null The autoloader object or FALSE if no Composer autoloader could
+         *                                                be found. NULL when this hasn't been determined yet.
          */
         private static $composerAutoloader = null;
 
@@ -70,14 +74,14 @@ public static function load($class)
                 // Make sure we don't try to load any of Composer's classes
                 // while the autoloader is being setup.
                 if (strpos($class, 'Composer\\') === 0) {
-                    return;
+                    return false;
                 }
 
                 if (strpos(__DIR__, 'phar://') !== 0
                     && @file_exists(__DIR__.'/../../autoload.php') === true
                 ) {
                     self::$composerAutoloader = include __DIR__.'/../../autoload.php';
-                    if (self::$composerAutoloader instanceof \Composer\Autoload\ClassLoader) {
+                    if (self::$composerAutoloader instanceof ClassLoader) {
                         self::$composerAutoloader->unregister();
                         self::$composerAutoloader->register();
                     } else {
@@ -201,7 +205,7 @@ public static function determineLoadedClass($classesBeforeLoad, $classesAfterLoa
             }
 
             // Since PHP 7.4 get_declared_classes() does not guarantee any order, making
-            // it impossible to use order to determine which is the parent an which is the child.
+            // it impossible to use order to determine which is the parent and which is the child.
             // Let's reduce the list of candidates by removing all the classes known to be "parents".
             // That way, at the end, only the "main" class just included will remain.
             $newClasses = array_reduce(
@@ -282,7 +286,7 @@ public static function getSearchPaths()
         public static function getLoadedClassName($path)
         {
             if (isset(self::$loadedClasses[$path]) === false) {
-                throw new \Exception("Cannot get class name for $path; file has not been included");
+                throw new Exception("Cannot get class name for $path; file has not been included");
             }
 
             return self::$loadedClasses[$path];
@@ -295,13 +299,13 @@ public static function getLoadedClassName($path)
          *
          * @param string $class The name of the class.
          *
-         * @throws \Exception If the class name has not been loaded
+         * @throws \Exception If the class name has not been loaded.
          * @return string
          */
         public static function getLoadedFileName($class)
         {
             if (isset(self::$loadedFiles[$class]) === false) {
-                throw new \Exception("Cannot get file name for $class; class has not been included");
+                throw new Exception("Cannot get file name for $class; class has not been included");
             }
 
             return self::$loadedFiles[$class];
diff --git a/app/vendor/squizlabs/php_codesniffer/bin/phpcbf b/app/vendor/squizlabs/php_codesniffer/bin/phpcbf
index 2e86a40e6..c804bdf10 100755
--- a/app/vendor/squizlabs/php_codesniffer/bin/phpcbf
+++ b/app/vendor/squizlabs/php_codesniffer/bin/phpcbf
@@ -8,11 +8,7 @@
  * @license   https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
  */
 
-if (is_file(__DIR__.'/../autoload.php') === true) {
-    include_once __DIR__.'/../autoload.php';
-} else {
-    include_once 'PHP/CodeSniffer/autoload.php';
-}
+require_once __DIR__.'/../autoload.php';
 
 $runner   = new PHP_CodeSniffer\Runner();
 $exitCode = $runner->runPHPCBF();
diff --git a/app/vendor/squizlabs/php_codesniffer/bin/phpcs b/app/vendor/squizlabs/php_codesniffer/bin/phpcs
index e8e8b0289..d098bf878 100755
--- a/app/vendor/squizlabs/php_codesniffer/bin/phpcs
+++ b/app/vendor/squizlabs/php_codesniffer/bin/phpcs
@@ -8,11 +8,7 @@
  * @license   https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
  */
 
-if (is_file(__DIR__.'/../autoload.php') === true) {
-    include_once __DIR__.'/../autoload.php';
-} else {
-    include_once 'PHP/CodeSniffer/autoload.php';
-}
+require_once __DIR__.'/../autoload.php';
 
 $runner   = new PHP_CodeSniffer\Runner();
 $exitCode = $runner->runPHPCS();
diff --git a/app/vendor/squizlabs/php_codesniffer/composer.json b/app/vendor/squizlabs/php_codesniffer/composer.json
index ae7c7604a..28cdb07b7 100644
--- a/app/vendor/squizlabs/php_codesniffer/composer.json
+++ b/app/vendor/squizlabs/php_codesniffer/composer.json
@@ -42,6 +42,9 @@
         "bin/phpcbf",
         "bin/phpcs"
     ],
+    "config": {
+        "lock": false
+    },
     "extra": {
         "branch-alias": {
             "dev-master": "3.x-dev"
diff --git a/app/vendor/squizlabs/php_codesniffer/licence.txt b/app/vendor/squizlabs/php_codesniffer/licence.txt
index 9f95b6771..c7e8000d9 100644
--- a/app/vendor/squizlabs/php_codesniffer/licence.txt
+++ b/app/vendor/squizlabs/php_codesniffer/licence.txt
@@ -1,4 +1,5 @@
 Copyright (c) 2012, Squiz Pty Ltd (ABN 77 084 670 600)
+Copyright (c) 2023, PHPCSStandards and contributors
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
diff --git a/app/vendor/squizlabs/php_codesniffer/src/Config.php b/app/vendor/squizlabs/php_codesniffer/src/Config.php
index 25b3a4f43..e9eeace0b 100644
--- a/app/vendor/squizlabs/php_codesniffer/src/Config.php
+++ b/app/vendor/squizlabs/php_codesniffer/src/Config.php
@@ -12,9 +12,13 @@
 
 namespace PHP_CodeSniffer;
 
+use Exception;
+use Phar;
 use PHP_CodeSniffer\Exceptions\DeepExitException;
 use PHP_CodeSniffer\Exceptions\RuntimeException;
 use PHP_CodeSniffer\Util\Common;
+use PHP_CodeSniffer\Util\Help;
+use PHP_CodeSniffer\Util\Standards;
 
 /**
  * Stores the configuration used to run PHPCS and PHPCBF.
@@ -81,7 +85,7 @@ class Config
      *
      * @var string
      */
-    const VERSION = '3.9.0';
+    const VERSION = '3.13.2';
 
     /**
      * Package stability; either stable, beta or alpha.
@@ -166,6 +170,21 @@ class Config
      */
     private $cliArgs = [];
 
+    /**
+     * A list of valid generators.
+     *
+     * {@internal Once support for PHP < 5.6 is dropped, this property should be refactored into a
+     * class constant.}
+     *
+     * @var array Keys are the lowercase version of the generator name, while values
+     *                            are the associated PHP generator class.
+     */
+    private $validGenerators = [
+        'text'     => 'Text',
+        'html'     => 'HTML',
+        'markdown' => 'Markdown',
+    ];
+
     /**
      * Command line values that the user has supplied directly.
      *
@@ -265,7 +284,7 @@ public function __set($name, $value)
             $cleaned = [];
 
             // Check if the standard name is valid, or if the case is invalid.
-            $installedStandards = Util\Standards::getInstalledStandards();
+            $installedStandards = Standards::getInstalledStandards();
             foreach ($value as $standard) {
                 foreach ($installedStandards as $validStandard) {
                     if (strtolower($standard) === strtolower($validStandard)) {
@@ -420,7 +439,7 @@ public function __construct(array $cliArgs=[], $dieOnUnknownArg=true)
 
         // Check for content on STDIN.
         if ($this->stdin === true
-            || (Util\Common::isStdinATTY() === false
+            || (Common::isStdinATTY() === false
             && feof($handle) === false)
         ) {
             $readStreams = [$handle];
@@ -649,7 +668,7 @@ public function processShortArgument($arg, $pos)
             throw new DeepExitException($output, 0);
         case 'i' :
             ob_start();
-            Util\Standards::printInstalledStandards();
+            Standards::printInstalledStandards();
             $output = ob_get_contents();
             ob_end_clean();
             throw new DeepExitException($output, 0);
@@ -812,7 +831,7 @@ public function processLongArgument($arg, $pos)
 
             try {
                 $this->setConfigData($key, $value);
-            } catch (\Exception $e) {
+            } catch (Exception $e) {
                 throw new DeepExitException($e->getMessage().PHP_EOL, 3);
             }
 
@@ -840,7 +859,7 @@ public function processLongArgument($arg, $pos)
             } else {
                 try {
                     $this->setConfigData($key, null);
-                } catch (\Exception $e) {
+                } catch (Exception $e) {
                     throw new DeepExitException($e->getMessage().PHP_EOL, 3);
                 }
 
@@ -881,32 +900,14 @@ public function processLongArgument($arg, $pos)
                     break;
                 }
 
-                $sniffs = explode(',', substr($arg, 7));
-                foreach ($sniffs as $sniff) {
-                    if (substr_count($sniff, '.') !== 2) {
-                        $error  = 'ERROR: The specified sniff code "'.$sniff.'" is invalid'.PHP_EOL.PHP_EOL;
-                        $error .= $this->printShortUsage(true);
-                        throw new DeepExitException($error, 3);
-                    }
-                }
-
-                $this->sniffs = $sniffs;
+                $this->sniffs = $this->parseSniffCodes(substr($arg, 7), 'sniffs');
                 self::$overriddenDefaults['sniffs'] = true;
             } else if (substr($arg, 0, 8) === 'exclude=') {
                 if (isset(self::$overriddenDefaults['exclude']) === true) {
                     break;
                 }
 
-                $sniffs = explode(',', substr($arg, 8));
-                foreach ($sniffs as $sniff) {
-                    if (substr_count($sniff, '.') !== 2) {
-                        $error  = 'ERROR: The specified sniff code "'.$sniff.'" is invalid'.PHP_EOL.PHP_EOL;
-                        $error .= $this->printShortUsage(true);
-                        throw new DeepExitException($error, 3);
-                    }
-                }
-
-                $this->exclude = $sniffs;
+                $this->exclude = $this->parseSniffCodes(substr($arg, 8), 'exclude');
                 self::$overriddenDefaults['exclude'] = true;
             } else if (defined('PHP_CODESNIFFER_IN_TESTS') === false
                 && substr($arg, 0, 6) === 'cache='
@@ -922,7 +923,7 @@ public function processLongArgument($arg, $pos)
                 $this->cache = true;
                 self::$overriddenDefaults['cache'] = true;
 
-                $this->cacheFile = Util\Common::realpath(substr($arg, 6));
+                $this->cacheFile = Common::realpath(substr($arg, 6));
 
                 // It may not exist and return false instead.
                 if ($this->cacheFile === false) {
@@ -941,9 +942,9 @@ public function processLongArgument($arg, $pos)
                     } else {
                         if ($dir[0] === '/') {
                             // An absolute path.
-                            $dir = Util\Common::realpath($dir);
+                            $dir = Common::realpath($dir);
                         } else {
-                            $dir = Util\Common::realpath(getcwd().'/'.$dir);
+                            $dir = Common::realpath(getcwd().'/'.$dir);
                         }
 
                         if ($dir !== false) {
@@ -964,7 +965,7 @@ public function processLongArgument($arg, $pos)
                 $files     = explode(',', substr($arg, 10));
                 $bootstrap = [];
                 foreach ($files as $file) {
-                    $path = Util\Common::realpath($file);
+                    $path = Common::realpath($file);
                     if ($path === false) {
                         $error  = 'ERROR: The specified bootstrap file "'.$file.'" does not exist'.PHP_EOL.PHP_EOL;
                         $error .= $this->printShortUsage(true);
@@ -978,7 +979,7 @@ public function processLongArgument($arg, $pos)
                 self::$overriddenDefaults['bootstrap'] = true;
             } else if (substr($arg, 0, 10) === 'file-list=') {
                 $fileList = substr($arg, 10);
-                $path     = Util\Common::realpath($fileList);
+                $path     = Common::realpath($fileList);
                 if ($path === false) {
                     $error  = 'ERROR: The specified file list "'.$fileList.'" does not exist'.PHP_EOL.PHP_EOL;
                     $error .= $this->printShortUsage(true);
@@ -1001,7 +1002,7 @@ public function processLongArgument($arg, $pos)
                     break;
                 }
 
-                $this->stdinPath = Util\Common::realpath(substr($arg, 11));
+                $this->stdinPath = Common::realpath(substr($arg, 11));
 
                 // It may not exist and return false instead, so use whatever they gave us.
                 if ($this->stdinPath === false) {
@@ -1009,18 +1010,18 @@ public function processLongArgument($arg, $pos)
                 }
 
                 self::$overriddenDefaults['stdinPath'] = true;
-            } else if (PHP_CODESNIFFER_CBF === false && substr($arg, 0, 12) === 'report-file=') {
-                if (isset(self::$overriddenDefaults['reportFile']) === true) {
+            } else if (substr($arg, 0, 12) === 'report-file=') {
+                if (PHP_CODESNIFFER_CBF === true || isset(self::$overriddenDefaults['reportFile']) === true) {
                     break;
                 }
 
-                $this->reportFile = Util\Common::realpath(substr($arg, 12));
+                $this->reportFile = Common::realpath(substr($arg, 12));
 
                 // It may not exist and return false instead.
                 if ($this->reportFile === false) {
                     $this->reportFile = substr($arg, 12);
 
-                    $dir = Util\Common::realpath(dirname($this->reportFile));
+                    $dir = Common::realpath(dirname($this->reportFile));
                     if (is_dir($dir) === false) {
                         $error  = 'ERROR: The specified report file path "'.$this->reportFile.'" points to a non-existent directory'.PHP_EOL.PHP_EOL;
                         $error .= $this->printShortUsage(true);
@@ -1056,7 +1057,7 @@ public function processLongArgument($arg, $pos)
                     break;
                 }
 
-                $this->basepath = Util\Common::realpath(substr($arg, 9));
+                $this->basepath = Common::realpath(substr($arg, 9));
 
                 // It may not exist and return false instead.
                 if ($this->basepath === false) {
@@ -1083,7 +1084,7 @@ public function processLongArgument($arg, $pos)
                         if ($output === false) {
                             $output = null;
                         } else {
-                            $dir = Util\Common::realpath(dirname($output));
+                            $dir = Common::realpath(dirname($output));
                             if (is_dir($dir) === false) {
                                 $error  = 'ERROR: The specified '.$report.' report file path "'.$output.'" points to a non-existent directory'.PHP_EOL.PHP_EOL;
                                 $error .= $this->printShortUsage(true);
@@ -1140,21 +1141,24 @@ public function processLongArgument($arg, $pos)
                     break;
                 }
 
-                $extensions    = explode(',', substr($arg, 11));
-                $newExtensions = [];
-                foreach ($extensions as $ext) {
-                    $slash = strpos($ext, '/');
-                    if ($slash !== false) {
-                        // They specified the tokenizer too.
-                        list($ext, $tokenizer) = explode('/', $ext);
-                        $newExtensions[$ext]   = strtoupper($tokenizer);
-                        continue;
-                    }
+                $extensionsString = substr($arg, 11);
+                $newExtensions    = [];
+                if (empty($extensionsString) === false) {
+                    $extensions = explode(',', $extensionsString);
+                    foreach ($extensions as $ext) {
+                        $slash = strpos($ext, '/');
+                        if ($slash !== false) {
+                            // They specified the tokenizer too.
+                            list($ext, $tokenizer) = explode('/', $ext);
+                            $newExtensions[$ext]   = strtoupper($tokenizer);
+                            continue;
+                        }
 
-                    if (isset($this->extensions[$ext]) === true) {
-                        $newExtensions[$ext] = $this->extensions[$ext];
-                    } else {
-                        $newExtensions[$ext] = 'PHP';
+                        if (isset($this->extensions[$ext]) === true) {
+                            $newExtensions[$ext] = $this->extensions[$ext];
+                        } else {
+                            $newExtensions[$ext] = 'PHP';
+                        }
                     }
                 }
 
@@ -1229,7 +1233,22 @@ public function processLongArgument($arg, $pos)
                     break;
                 }
 
-                $this->generator = substr($arg, 10);
+                $generatorName          = substr($arg, 10);
+                $lowerCaseGeneratorName = strtolower($generatorName);
+
+                if (isset($this->validGenerators[$lowerCaseGeneratorName]) === false) {
+                    $validOptions = implode(', ', $this->validGenerators);
+                    $validOptions = substr_replace($validOptions, ' and', strrpos($validOptions, ','), 1);
+                    $error        = sprintf(
+                        'ERROR: "%s" is not a valid generator. The following generators are supported: %s.'.PHP_EOL.PHP_EOL,
+                        $generatorName,
+                        $validOptions
+                    );
+                    $error       .= $this->printShortUsage(true);
+                    throw new DeepExitException($error, 3);
+                }
+
+                $this->generator = $this->validGenerators[$lowerCaseGeneratorName];
                 self::$overriddenDefaults['generator'] = true;
             } else if (substr($arg, 0, 9) === 'encoding=') {
                 if (isset(self::$overriddenDefaults['encoding']) === true) {
@@ -1273,6 +1292,93 @@ public function processLongArgument($arg, $pos)
     }//end processLongArgument()
 
 
+    /**
+     * Parse supplied string into a list of validated sniff codes.
+     *
+     * @param string $input    Comma-separated string of sniff codes.
+     * @param string $argument The name of the argument which is being processed.
+     *
+     * @return array
+     * @throws \PHP_CodeSniffer\Exceptions\DeepExitException When any of the provided codes are not valid as sniff codes.
+     */
+    private function parseSniffCodes($input, $argument)
+    {
+        $errors = [];
+        $sniffs = [];
+
+        $possibleSniffs = array_filter(explode(',', $input));
+
+        if ($possibleSniffs === []) {
+            $errors[] = 'No codes specified / empty argument';
+        }
+
+        foreach ($possibleSniffs as $sniff) {
+            $sniff = trim($sniff);
+
+            $partCount = substr_count($sniff, '.');
+            if ($partCount === 2) {
+                // Correct number of parts.
+                $sniffs[] = $sniff;
+                continue;
+            }
+
+            if ($partCount === 0) {
+                $errors[] = 'Standard codes are not supported: '.$sniff;
+            } else if ($partCount === 1) {
+                $errors[] = 'Category codes are not supported: '.$sniff;
+            } else if ($partCount === 3) {
+                $errors[] = 'Message codes are not supported: '.$sniff;
+            } else {
+                $errors[] = 'Too many parts: '.$sniff;
+            }
+
+            if ($partCount > 2) {
+                $parts    = explode('.', $sniff, 4);
+                $sniffs[] = $parts[0].'.'.$parts[1].'.'.$parts[2];
+            }
+        }//end foreach
+
+        $sniffs = array_reduce(
+            $sniffs,
+            static function ($carry, $item) {
+                $lower = strtolower($item);
+
+                foreach ($carry as $found) {
+                    if ($lower === strtolower($found)) {
+                        // This sniff is already in our list.
+                        return $carry;
+                    }
+                }
+
+                $carry[] = $item;
+
+                return $carry;
+            },
+            []
+        );
+
+        if ($errors !== []) {
+            $error  = 'ERROR: The --'.$argument.' option only supports sniff codes.'.PHP_EOL;
+            $error .= 'Sniff codes are in the form "Standard.Category.Sniff".'.PHP_EOL;
+            $error .= PHP_EOL;
+            $error .= 'The following problems were detected:'.PHP_EOL;
+            $error .= '* '.implode(PHP_EOL.'* ', $errors).PHP_EOL;
+
+            if ($sniffs !== []) {
+                $error .= PHP_EOL;
+                $error .= 'Perhaps try --'.$argument.'="'.implode(',', $sniffs).'" instead.'.PHP_EOL;
+            }
+
+            $error .= PHP_EOL;
+            $error .= $this->printShortUsage(true);
+            throw new DeepExitException(ltrim($error), 3);
+        }
+
+        return $sniffs;
+
+    }//end parseSniffCodes()
+
+
     /**
      * Processes an unknown command line argument.
      *
@@ -1317,7 +1423,7 @@ public function processFilePath($path)
             return;
         }
 
-        $file = Util\Common::realpath($path);
+        $file = Common::realpath($path);
         if (file_exists($file) === false) {
             if ($this->dieOnUnknownArg === false) {
                 return;
@@ -1392,71 +1498,21 @@ public function printShortUsage($return=false)
      */
     public function printPHPCSUsage()
     {
-        echo 'Usage: phpcs [-nwlsaepqvi] [-d key[=value]] [--colors] [--no-colors]'.PHP_EOL;
-        echo '  [--cache[=]] [--no-cache] [--tab-width=]'.PHP_EOL;
-        echo '  [--report=] [--report-file=] [--report-=]'.PHP_EOL;
-        echo '  [--report-width=] [--basepath=] [--bootstrap=]'.PHP_EOL;
-        echo '  [--severity=] [--error-severity=] [--warning-severity=]'.PHP_EOL;
-        echo '  [--runtime-set key value] [--config-set key value] [--config-delete key] [--config-show]'.PHP_EOL;
-        echo '  [--standard=] [--sniffs=] [--exclude=]'.PHP_EOL;
-        echo '  [--encoding=] [--parallel=] [--generator=]'.PHP_EOL;
-        echo '  [--extensions=] [--ignore=] [--ignore-annotations]'.PHP_EOL;
-        echo '  [--stdin-path=] [--file-list=] [--filter=]  - ...'.PHP_EOL;
-        echo PHP_EOL;
-        echo ' -     Check STDIN instead of local files and directories'.PHP_EOL;
-        echo ' -n    Do not print warnings (shortcut for --warning-severity=0)'.PHP_EOL;
-        echo ' -w    Print both warnings and errors (this is the default)'.PHP_EOL;
-        echo ' -l    Local directory only, no recursion'.PHP_EOL;
-        echo ' -s    Show error codes in all reports'.PHP_EOL;
-        echo ' -a    Run interactively'.PHP_EOL;
-        echo ' -e    Explain a standard by showing the sniffs it includes'.PHP_EOL;
-        echo ' -p    Show progress of the run'.PHP_EOL;
-        echo ' -q    Quiet mode; disables progress and verbose output'.PHP_EOL;
-        echo ' -m    Stop error messages from being recorded'.PHP_EOL;
-        echo '       (saves a lot of memory, but stops many reports from being used)'.PHP_EOL;
-        echo ' -v    Print processed files'.PHP_EOL;
-        echo ' -vv   Print ruleset and token output'.PHP_EOL;
-        echo ' -vvv  Print sniff processing information'.PHP_EOL;
-        echo ' -i    Show a list of installed coding standards'.PHP_EOL;
-        echo ' -d    Set the [key] php.ini value to [value] or [true] if value is omitted'.PHP_EOL;
-        echo PHP_EOL;
-        echo ' --help                Print this help message'.PHP_EOL;
-        echo ' --version             Print version information'.PHP_EOL;
-        echo ' --colors              Use colors in output'.PHP_EOL;
-        echo ' --no-colors           Do not use colors in output (this is the default)'.PHP_EOL;
-        echo ' --cache               Cache results between runs'.PHP_EOL;
-        echo ' --no-cache            Do not cache results between runs (this is the default)'.PHP_EOL;
-        echo ' --ignore-annotations  Ignore all phpcs: annotations in code comments'.PHP_EOL;
-        echo PHP_EOL;
-        echo '     Use a specific file for caching (uses a temporary file by default)'.PHP_EOL;
-        echo '      A path to strip from the front of file paths inside reports'.PHP_EOL;
-        echo '     A comma separated list of files to run before processing begins'.PHP_EOL;
-        echo '      The encoding of the files being checked (default is utf-8)'.PHP_EOL;
-        echo '    A comma separated list of file extensions to check'.PHP_EOL;
-        echo '                The type of the file can be specified using: ext/type'.PHP_EOL;
-        echo '                e.g., module/php,es/js'.PHP_EOL;
-        echo '          One or more files and/or directories to check'.PHP_EOL;
-        echo '      A file containing a list of files and/or directories to check (one per line)'.PHP_EOL;
-        echo '        Use either the "GitModified" or "GitStaged" filter,'.PHP_EOL;
-        echo '                or specify the path to a custom filter class'.PHP_EOL;
-        echo '     Use either the "HTML", "Markdown" or "Text" generator'.PHP_EOL;
-        echo '                (forces documentation generation instead of checking)'.PHP_EOL;
-        echo '      A comma separated list of patterns to ignore files and directories'.PHP_EOL;
-        echo '     How many files should be checked simultaneously (default is 1)'.PHP_EOL;
-        echo '        Print either the "full", "xml", "checkstyle", "csv"'.PHP_EOL;
-        echo '                "json", "junit", "emacs", "source", "summary", "diff"'.PHP_EOL;
-        echo '                "svnblame", "gitblame", "hgblame", "notifysend" or "performance",'.PHP_EOL;
-        echo '                report or specify the path to a custom report class'.PHP_EOL;
-        echo '                (the "full" report is printed by default)'.PHP_EOL;
-        echo '    Write the report to the specified file path'.PHP_EOL;
-        echo '   How many columns wide screen reports should be printed'.PHP_EOL;
-        echo '                or set to "auto" to use current screen width, where supported'.PHP_EOL;
-        echo '      The minimum severity required to display an error or warning'.PHP_EOL;
-        echo '        A comma separated list of sniff codes to include or exclude from checking'.PHP_EOL;
-        echo '                (all sniffs must be part of the specified standard)'.PHP_EOL;
-        echo '      The name or path of the coding standard to use'.PHP_EOL;
-        echo '     If processing STDIN, the file path that STDIN will be processed as'.PHP_EOL;
-        echo '      The number of spaces each tab represents'.PHP_EOL;
+        $longOptions   = explode(',', Help::DEFAULT_LONG_OPTIONS);
+        $longOptions[] = 'cache';
+        $longOptions[] = 'no-cache';
+        $longOptions[] = 'report';
+        $longOptions[] = 'report-file';
+        $longOptions[] = 'report-report';
+        $longOptions[] = 'config-explain';
+        $longOptions[] = 'config-set';
+        $longOptions[] = 'config-delete';
+        $longOptions[] = 'config-show';
+        $longOptions[] = 'generator';
+
+        $shortOptions = Help::DEFAULT_SHORT_OPTIONS.'aems';
+
+        (new Help($this, $longOptions, $shortOptions))->display();
 
     }//end printPHPCSUsage()
 
@@ -1468,49 +1524,11 @@ public function printPHPCSUsage()
      */
     public function printPHPCBFUsage()
     {
-        echo 'Usage: phpcbf [-nwli] [-d key[=value]] [--ignore-annotations] [--bootstrap=]'.PHP_EOL;
-        echo '  [--standard=] [--sniffs=] [--exclude=] [--suffix=]'.PHP_EOL;
-        echo '  [--severity=] [--error-severity=] [--warning-severity=]'.PHP_EOL;
-        echo '  [--tab-width=] [--encoding=] [--parallel=]'.PHP_EOL;
-        echo '  [--basepath=] [--extensions=] [--ignore=]'.PHP_EOL;
-        echo '  [--stdin-path=] [--file-list=] [--filter=]  - ...'.PHP_EOL;
-        echo PHP_EOL;
-        echo ' -     Fix STDIN instead of local files and directories'.PHP_EOL;
-        echo ' -n    Do not fix warnings (shortcut for --warning-severity=0)'.PHP_EOL;
-        echo ' -w    Fix both warnings and errors (on by default)'.PHP_EOL;
-        echo ' -l    Local directory only, no recursion'.PHP_EOL;
-        echo ' -p    Show progress of the run'.PHP_EOL;
-        echo ' -q    Quiet mode; disables progress and verbose output'.PHP_EOL;
-        echo ' -v    Print processed files'.PHP_EOL;
-        echo ' -vv   Print ruleset and token output'.PHP_EOL;
-        echo ' -vvv  Print sniff processing information'.PHP_EOL;
-        echo ' -i    Show a list of installed coding standards'.PHP_EOL;
-        echo ' -d    Set the [key] php.ini value to [value] or [true] if value is omitted'.PHP_EOL;
-        echo PHP_EOL;
-        echo ' --help                Print this help message'.PHP_EOL;
-        echo ' --version             Print version information'.PHP_EOL;
-        echo ' --ignore-annotations  Ignore all phpcs: annotations in code comments'.PHP_EOL;
-        echo PHP_EOL;
-        echo '     A path to strip from the front of file paths inside reports'.PHP_EOL;
-        echo '    A comma separated list of files to run before processing begins'.PHP_EOL;
-        echo '     The encoding of the files being fixed (default is utf-8)'.PHP_EOL;
-        echo '   A comma separated list of file extensions to fix'.PHP_EOL;
-        echo '               The type of the file can be specified using: ext/type'.PHP_EOL;
-        echo '               e.g., module/php,es/js'.PHP_EOL;
-        echo '         One or more files and/or directories to fix'.PHP_EOL;
-        echo '     A file containing a list of files and/or directories to fix (one per line)'.PHP_EOL;
-        echo '       Use either the "GitModified" or "GitStaged" filter,'.PHP_EOL;
-        echo '               or specify the path to a custom filter class'.PHP_EOL;
-        echo '     A comma separated list of patterns to ignore files and directories'.PHP_EOL;
-        echo '    How many files should be fixed simultaneously (default is 1)'.PHP_EOL;
-        echo '     The minimum severity required to fix an error or warning'.PHP_EOL;
-        echo '       A comma separated list of sniff codes to include or exclude from fixing'.PHP_EOL;
-        echo '               (all sniffs must be part of the specified standard)'.PHP_EOL;
-        echo '     The name or path of the coding standard to use'.PHP_EOL;
-        echo '    If processing STDIN, the file path that STDIN will be processed as'.PHP_EOL;
-        echo '       Write modified files to a filename using this suffix'.PHP_EOL;
-        echo '               ("diff" and "patch" are not used in this mode)'.PHP_EOL;
-        echo '     The number of spaces each tab represents'.PHP_EOL;
+        $longOptions   = explode(',', Help::DEFAULT_LONG_OPTIONS);
+        $longOptions[] = 'suffix';
+        $shortOptions  = Help::DEFAULT_SHORT_OPTIONS;
+
+        (new Help($this, $longOptions, $shortOptions))->display();
 
     }//end printPHPCBFUsage()
 
@@ -1608,7 +1626,7 @@ public static function setConfigData($key, $value, $temp=false)
         if ($temp === false) {
             $path = '';
             if (is_callable('\Phar::running') === true) {
-                $path = \Phar::running(false);
+                $path = Phar::running(false);
             }
 
             if ($path !== '') {
@@ -1653,8 +1671,8 @@ public static function setConfigData($key, $value, $temp=false)
         // If the installed paths are being set, make sure all known
         // standards paths are added to the autoloader.
         if ($key === 'installed_paths') {
-            $installedStandards = Util\Standards::getInstalledStandardDetails();
-            foreach ($installedStandards as $name => $details) {
+            $installedStandards = Standards::getInstalledStandardDetails();
+            foreach ($installedStandards as $details) {
                 Autoload::addSearchPath($details['path'], $details['namespace']);
             }
         }
@@ -1679,18 +1697,13 @@ public static function getAllConfigData()
 
         $path = '';
         if (is_callable('\Phar::running') === true) {
-            $path = \Phar::running(false);
+            $path = Phar::running(false);
         }
 
         if ($path !== '') {
             $configFile = dirname($path).DIRECTORY_SEPARATOR.'CodeSniffer.conf';
         } else {
             $configFile = dirname(__DIR__).DIRECTORY_SEPARATOR.'CodeSniffer.conf';
-            if (is_file($configFile) === false
-                && strpos('@data_dir@', '@data_dir') === false
-            ) {
-                $configFile = '@data_dir@/PHP_CodeSniffer/CodeSniffer.conf';
-            }
         }
 
         if (is_file($configFile) === false) {
diff --git a/app/vendor/squizlabs/php_codesniffer/src/Exceptions/DeepExitException.php b/app/vendor/squizlabs/php_codesniffer/src/Exceptions/DeepExitException.php
index 7732c6da4..6943e033e 100644
--- a/app/vendor/squizlabs/php_codesniffer/src/Exceptions/DeepExitException.php
+++ b/app/vendor/squizlabs/php_codesniffer/src/Exceptions/DeepExitException.php
@@ -12,7 +12,9 @@
 
 namespace PHP_CodeSniffer\Exceptions;
 
-class DeepExitException extends \Exception
+use Exception;
+
+class DeepExitException extends Exception
 {
 
 }//end class
diff --git a/app/vendor/squizlabs/php_codesniffer/src/Exceptions/RuntimeException.php b/app/vendor/squizlabs/php_codesniffer/src/Exceptions/RuntimeException.php
index a3d590984..25eacd0b1 100644
--- a/app/vendor/squizlabs/php_codesniffer/src/Exceptions/RuntimeException.php
+++ b/app/vendor/squizlabs/php_codesniffer/src/Exceptions/RuntimeException.php
@@ -9,7 +9,9 @@
 
 namespace PHP_CodeSniffer\Exceptions;
 
-class RuntimeException extends \RuntimeException
+use RuntimeException as PHPRuntimeException;
+
+class RuntimeException extends PHPRuntimeException
 {
 
 }//end class
diff --git a/app/vendor/squizlabs/php_codesniffer/src/Exceptions/TokenizerException.php b/app/vendor/squizlabs/php_codesniffer/src/Exceptions/TokenizerException.php
index ad25ace19..1cf53d623 100644
--- a/app/vendor/squizlabs/php_codesniffer/src/Exceptions/TokenizerException.php
+++ b/app/vendor/squizlabs/php_codesniffer/src/Exceptions/TokenizerException.php
@@ -9,7 +9,9 @@
 
 namespace PHP_CodeSniffer\Exceptions;
 
-class TokenizerException extends \Exception
+use Exception;
+
+class TokenizerException extends Exception
 {
 
 }//end class
diff --git a/app/vendor/squizlabs/php_codesniffer/src/Files/DummyFile.php b/app/vendor/squizlabs/php_codesniffer/src/Files/DummyFile.php
index eb947fd2a..f5dc7cc7a 100644
--- a/app/vendor/squizlabs/php_codesniffer/src/Files/DummyFile.php
+++ b/app/vendor/squizlabs/php_codesniffer/src/Files/DummyFile.php
@@ -14,8 +14,8 @@
 
 namespace PHP_CodeSniffer\Files;
 
-use PHP_CodeSniffer\Ruleset;
 use PHP_CodeSniffer\Config;
+use PHP_CodeSniffer\Ruleset;
 
 class DummyFile extends File
 {
diff --git a/app/vendor/squizlabs/php_codesniffer/src/Files/File.php b/app/vendor/squizlabs/php_codesniffer/src/Files/File.php
index 7b54bea17..fe3b7b1c6 100644
--- a/app/vendor/squizlabs/php_codesniffer/src/Files/File.php
+++ b/app/vendor/squizlabs/php_codesniffer/src/Files/File.php
@@ -9,12 +9,13 @@
 
 namespace PHP_CodeSniffer\Files;
 
-use PHP_CodeSniffer\Ruleset;
 use PHP_CodeSniffer\Config;
-use PHP_CodeSniffer\Fixer;
-use PHP_CodeSniffer\Util;
 use PHP_CodeSniffer\Exceptions\RuntimeException;
 use PHP_CodeSniffer\Exceptions\TokenizerException;
+use PHP_CodeSniffer\Fixer;
+use PHP_CodeSniffer\Ruleset;
+use PHP_CodeSniffer\Util\Common;
+use PHP_CodeSniffer\Util\Tokens;
 
 class File
 {
@@ -276,7 +277,7 @@ public function setContent($content)
         $this->tokens  = [];
 
         try {
-            $this->eolChar = Util\Common::detectLineEndings($content);
+            $this->eolChar = Common::detectLineEndings($content);
         } catch (RuntimeException $e) {
             $this->addWarningOnLine($e->getMessage(), 1, 'Internal.DetectLineEndings');
             return;
@@ -345,7 +346,6 @@ public function process()
         $listenerIgnoreTo = [];
         $inTests          = defined('PHP_CODESNIFFER_IN_TESTS');
         $checkAnnotations = $this->config->annotations;
-        $annotationErrors = [];
 
         // Foreach of the listeners that have registered to listen for this
         // token, get them to process it.
@@ -414,15 +414,7 @@ public function process()
                                 'scope' => 'sniff',
                             ];
                             $listenerClass = $this->ruleset->sniffCodes[$listenerCode];
-                            try {
-                                $this->ruleset->setSniffProperty($listenerClass, $propertyCode, $settings);
-                            } catch (RuntimeException $e) {
-                                // Non-existant property being set via an inline annotation.
-                                // This is typically a PHPCS test case file, but we can't throw an error on the annotation
-                                // line as it would get ignored. We also don't want this error to block
-                                // the scan of the current file, so collect these and throw later.
-                                $annotationErrors[] = 'Line '.$token['line'].': '.str_replace('Ruleset invalid. ', '', $e->getMessage());
-                            }
+                            $this->ruleset->setSniffProperty($listenerClass, $propertyCode, $settings);
                         }
                     }
                 }//end if
@@ -430,7 +422,7 @@ public function process()
 
             if (PHP_CODESNIFFER_VERBOSITY > 2) {
                 $type    = $token['type'];
-                $content = Util\Common::prepareForOutput($token['content']);
+                $content = Common::prepareForOutput($token['content']);
                 echo "\t\tProcess token $stackPtr: $type => $content".PHP_EOL;
             }
 
@@ -552,13 +544,6 @@ public function process()
             }
         }
 
-        if ($annotationErrors !== []) {
-            $error  = 'Encountered invalid inline phpcs:set annotations. Found:'.PHP_EOL;
-            $error .= implode(PHP_EOL, $annotationErrors);
-
-            $this->addWarning($error, null, 'Internal.PropertyDoesNotExist');
-        }
-
         if (PHP_CODESNIFFER_VERBOSITY > 2) {
             echo "\t*** END TOKEN PROCESSING ***".PHP_EOL;
             echo "\t*** START SNIFF PROCESSING REPORT ***".PHP_EOL;
@@ -671,13 +656,13 @@ public function cleanUp()
     /**
      * Records an error against a specific token in the file.
      *
-     * @param string  $error    The error message.
-     * @param int     $stackPtr The stack position where the error occurred.
-     * @param string  $code     A violation code unique to the sniff message.
-     * @param array   $data     Replacements for the error message.
-     * @param int     $severity The severity level for this error. A value of 0
-     *                          will be converted into the default severity level.
-     * @param boolean $fixable  Can the error be fixed by the sniff?
+     * @param string   $error    The error message.
+     * @param int|null $stackPtr The stack position where the error occurred.
+     * @param string   $code     A violation code unique to the sniff message.
+     * @param array    $data     Replacements for the error message.
+     * @param int      $severity The severity level for this error. A value of 0
+     *                           will be converted into the default severity level.
+     * @param boolean  $fixable  Can the error be fixed by the sniff?
      *
      * @return boolean
      */
@@ -705,13 +690,13 @@ public function addError(
     /**
      * Records a warning against a specific token in the file.
      *
-     * @param string  $warning  The error message.
-     * @param int     $stackPtr The stack position where the error occurred.
-     * @param string  $code     A violation code unique to the sniff message.
-     * @param array   $data     Replacements for the warning message.
-     * @param int     $severity The severity level for this warning. A value of 0
-     *                          will be converted into the default severity level.
-     * @param boolean $fixable  Can the warning be fixed by the sniff?
+     * @param string   $warning  The error message.
+     * @param int|null $stackPtr The stack position where the error occurred.
+     * @param string   $code     A violation code unique to the sniff message.
+     * @param array    $data     Replacements for the warning message.
+     * @param int      $severity The severity level for this warning. A value of 0
+     *                           will be converted into the default severity level.
+     * @param boolean  $fixable  Can the warning be fixed by the sniff?
      *
      * @return boolean
      */
@@ -872,16 +857,20 @@ protected function addMessage($error, $message, $line, $column, $code, $data, $s
         $parts = explode('.', $code);
         if ($parts[0] === 'Internal') {
             // An internal message.
-            $listenerCode = Util\Common::getSniffCode($this->activeListener);
-            $sniffCode    = $code;
-            $checkCodes   = [$sniffCode];
+            $listenerCode = '';
+            if ($this->activeListener !== '') {
+                $listenerCode = Common::getSniffCode($this->activeListener);
+            }
+
+            $sniffCode  = $code;
+            $checkCodes = [$sniffCode];
         } else {
             if ($parts[0] !== $code) {
                 // The full message code has been passed in.
                 $sniffCode    = $code;
                 $listenerCode = substr($sniffCode, 0, strrpos($sniffCode, '.'));
             } else {
-                $listenerCode = Util\Common::getSniffCode($this->activeListener);
+                $listenerCode = Common::getSniffCode($this->activeListener);
                 $sniffCode    = $listenerCode.'.'.$code;
                 $parts        = explode('.', $sniffCode);
             }
@@ -1299,8 +1288,17 @@ public function getDeclarationName($stackPtr)
             return $this->tokens[$stackPtr]['content'];
         }
 
+        $stopPoint = $this->numTokens;
+        if (isset($this->tokens[$stackPtr]['parenthesis_opener']) === true) {
+            // For functions, stop searching at the parenthesis opener.
+            $stopPoint = $this->tokens[$stackPtr]['parenthesis_opener'];
+        } else if (isset($this->tokens[$stackPtr]['scope_opener']) === true) {
+            // For OO tokens, stop searching at the open curly.
+            $stopPoint = $this->tokens[$stackPtr]['scope_opener'];
+        }
+
         $content = null;
-        for ($i = $stackPtr; $i < $this->numTokens; $i++) {
+        for ($i = $stackPtr; $i < $stopPoint; $i++) {
             if ($this->tokens[$i]['code'] === T_STRING) {
                 $content = $this->tokens[$i]['content'];
                 break;
@@ -1356,6 +1354,10 @@ public function getDeclarationName($stackPtr)
      *         'readonly_token'      => integer,       // The stack pointer to the readonly modifier token.
      *                                                 // This index will only be set if the property is readonly.
      *
+     * ... and if the promoted property uses asymmetric visibility, these additional array indexes will also be available:
+     *         'set_visibility'       => string,       // The property set-visibility as declared.
+     *         'set_visibility_token' => integer,      // The stack pointer to the set-visibility modifier token.
+     *
      * @param int $stackPtr The position in the stack of the function token
      *                      to acquire the parameters for.
      *
@@ -1408,17 +1410,20 @@ public function getMethodParameters($stackPtr)
         $variadicToken   = false;
         $typeHint        = '';
         $typeHintToken   = false;
-        $typeHintEndToken = false;
-        $nullableType     = false;
-        $visibilityToken  = null;
-        $readonlyToken    = null;
+        $typeHintEndToken   = false;
+        $nullableType       = false;
+        $visibilityToken    = null;
+        $setVisibilityToken = null;
+        $readonlyToken      = null;
 
         for ($i = $paramStart; $i <= $closer; $i++) {
             // Check to see if this token has a parenthesis or bracket opener. If it does
             // it's likely to be an array which might have arguments in it. This
             // could cause problems in our parsing below, so lets just skip to the
             // end of it.
-            if (isset($this->tokens[$i]['parenthesis_opener']) === true) {
+            if ($this->tokens[$i]['code'] !== T_TYPE_OPEN_PARENTHESIS
+                && isset($this->tokens[$i]['parenthesis_opener']) === true
+            ) {
                 // Don't do this if it's the close parenthesis for the method.
                 if ($i !== $this->tokens[$i]['parenthesis_closer']) {
                     $i = $this->tokens[$i]['parenthesis_closer'];
@@ -1512,6 +1517,8 @@ public function getMethodParameters($stackPtr)
             case T_NS_SEPARATOR:
             case T_TYPE_UNION:
             case T_TYPE_INTERSECTION:
+            case T_TYPE_OPEN_PARENTHESIS:
+            case T_TYPE_CLOSE_PARENTHESIS:
             case T_FALSE:
             case T_TRUE:
             case T_NULL:
@@ -1539,6 +1546,13 @@ public function getMethodParameters($stackPtr)
                     $visibilityToken = $i;
                 }
                 break;
+            case T_PUBLIC_SET:
+            case T_PROTECTED_SET:
+            case T_PRIVATE_SET:
+                if ($defaultStart === null) {
+                    $setVisibilityToken = $i;
+                }
+                break;
             case T_READONLY:
                 if ($defaultStart === null) {
                     $readonlyToken = $i;
@@ -1573,16 +1587,21 @@ public function getMethodParameters($stackPtr)
                 $vars[$paramCount]['type_hint_end_token'] = $typeHintEndToken;
                 $vars[$paramCount]['nullable_type']       = $nullableType;
 
-                if ($visibilityToken !== null || $readonlyToken !== null) {
+                if ($visibilityToken !== null || $setVisibilityToken !== null || $readonlyToken !== null) {
                     $vars[$paramCount]['property_visibility'] = 'public';
                     $vars[$paramCount]['visibility_token']    = false;
-                    $vars[$paramCount]['property_readonly']   = false;
 
                     if ($visibilityToken !== null) {
                         $vars[$paramCount]['property_visibility'] = $this->tokens[$visibilityToken]['content'];
                         $vars[$paramCount]['visibility_token']    = $visibilityToken;
                     }
 
+                    if ($setVisibilityToken !== null) {
+                        $vars[$paramCount]['set_visibility']       = $this->tokens[$setVisibilityToken]['content'];
+                        $vars[$paramCount]['set_visibility_token'] = $setVisibilityToken;
+                    }
+
+                    $vars[$paramCount]['property_readonly'] = false;
                     if ($readonlyToken !== null) {
                         $vars[$paramCount]['property_readonly'] = true;
                         $vars[$paramCount]['readonly_token']    = $readonlyToken;
@@ -1596,26 +1615,27 @@ public function getMethodParameters($stackPtr)
                 }
 
                 // Reset the vars, as we are about to process the next parameter.
-                $currVar          = null;
-                $paramStart       = ($i + 1);
-                $defaultStart     = null;
-                $equalToken       = null;
-                $hasAttributes    = false;
-                $passByReference  = false;
-                $referenceToken   = false;
-                $variableLength   = false;
-                $variadicToken    = false;
-                $typeHint         = '';
-                $typeHintToken    = false;
-                $typeHintEndToken = false;
-                $nullableType     = false;
-                $visibilityToken  = null;
-                $readonlyToken    = null;
+                $currVar            = null;
+                $paramStart         = ($i + 1);
+                $defaultStart       = null;
+                $equalToken         = null;
+                $hasAttributes      = false;
+                $passByReference    = false;
+                $referenceToken     = false;
+                $variableLength     = false;
+                $variadicToken      = false;
+                $typeHint           = '';
+                $typeHintToken      = false;
+                $typeHintEndToken   = false;
+                $nullableType       = false;
+                $visibilityToken    = null;
+                $setVisibilityToken = null;
+                $readonlyToken      = null;
 
                 $paramCount++;
                 break;
             case T_EQUAL:
-                $defaultStart = $this->findNext(Util\Tokens::$emptyTokens, ($i + 1), null, true);
+                $defaultStart = $this->findNext(Tokens::$emptyTokens, ($i + 1), null, true);
                 $equalToken   = $i;
                 break;
             }//end switch
@@ -1734,18 +1754,20 @@ public function getMethodProperties($stackPtr)
             }
 
             $valid = [
-                T_STRING            => T_STRING,
-                T_CALLABLE          => T_CALLABLE,
-                T_SELF              => T_SELF,
-                T_PARENT            => T_PARENT,
-                T_STATIC            => T_STATIC,
-                T_FALSE             => T_FALSE,
-                T_TRUE              => T_TRUE,
-                T_NULL              => T_NULL,
-                T_NAMESPACE         => T_NAMESPACE,
-                T_NS_SEPARATOR      => T_NS_SEPARATOR,
-                T_TYPE_UNION        => T_TYPE_UNION,
-                T_TYPE_INTERSECTION => T_TYPE_INTERSECTION,
+                T_STRING                 => T_STRING,
+                T_CALLABLE               => T_CALLABLE,
+                T_SELF                   => T_SELF,
+                T_PARENT                 => T_PARENT,
+                T_STATIC                 => T_STATIC,
+                T_FALSE                  => T_FALSE,
+                T_TRUE                   => T_TRUE,
+                T_NULL                   => T_NULL,
+                T_NAMESPACE              => T_NAMESPACE,
+                T_NS_SEPARATOR           => T_NS_SEPARATOR,
+                T_TYPE_UNION             => T_TYPE_UNION,
+                T_TYPE_INTERSECTION      => T_TYPE_INTERSECTION,
+                T_TYPE_OPEN_PARENTHESIS  => T_TYPE_OPEN_PARENTHESIS,
+                T_TYPE_CLOSE_PARENTHESIS => T_TYPE_CLOSE_PARENTHESIS,
             ];
 
             for ($i = $this->tokens[$stackPtr]['parenthesis_closer']; $i < $this->numTokens; $i++) {
@@ -1756,6 +1778,20 @@ public function getMethodProperties($stackPtr)
                     break;
                 }
 
+                if ($this->tokens[$i]['code'] === T_USE) {
+                    // Skip over closure use statements.
+                    for ($j = ($i + 1); $j < $this->numTokens && isset(Tokens::$emptyTokens[$this->tokens[$j]['code']]) === true; $j++);
+                    if ($this->tokens[$j]['code'] === T_OPEN_PARENTHESIS) {
+                        if (isset($this->tokens[$j]['parenthesis_closer']) === false) {
+                            // Live coding/parse error, stop parsing.
+                            break;
+                        }
+
+                        $i = $this->tokens[$j]['parenthesis_closer'];
+                        continue;
+                    }
+                }
+
                 if ($this->tokens[$i]['code'] === T_NULLABLE) {
                     $nullableReturnType = true;
                 }
@@ -1809,8 +1845,12 @@ public function getMethodProperties($stackPtr)
      *   array(
      *    'scope'           => string,        // Public, private, or protected.
      *    'scope_specified' => boolean,       // TRUE if the scope was explicitly specified.
+     *    'set_scope'       => string|false,  // Scope for asymmetric visibility.
+     *                                        // Either public, private, or protected or
+     *                                        // FALSE if no set scope is specified.
      *    'is_static'       => boolean,       // TRUE if the static keyword was found.
      *    'is_readonly'     => boolean,       // TRUE if the readonly keyword was found.
+     *    'is_final'        => boolean,       // TRUE if the final keyword was found.
      *    'type'            => string,        // The type of the var (empty if no type specified).
      *    'type_token'      => integer|false, // The stack pointer to the start of the type
      *                                        // or FALSE if there is no type.
@@ -1877,20 +1917,21 @@ public function getMemberProperties($stackPtr)
         }
 
         $valid = [
-            T_PUBLIC    => T_PUBLIC,
-            T_PRIVATE   => T_PRIVATE,
-            T_PROTECTED => T_PROTECTED,
-            T_STATIC    => T_STATIC,
-            T_VAR       => T_VAR,
-            T_READONLY  => T_READONLY,
+            T_STATIC   => T_STATIC,
+            T_VAR      => T_VAR,
+            T_READONLY => T_READONLY,
+            T_FINAL    => T_FINAL,
         ];
 
-        $valid += Util\Tokens::$emptyTokens;
+        $valid += Tokens::$scopeModifiers;
+        $valid += Tokens::$emptyTokens;
 
         $scope          = 'public';
         $scopeSpecified = false;
+        $setScope       = false;
         $isStatic       = false;
         $isReadonly     = false;
+        $isFinal        = false;
 
         $startOfStatement = $this->findPrevious(
             [
@@ -1920,13 +1961,25 @@ public function getMemberProperties($stackPtr)
                 $scope          = 'protected';
                 $scopeSpecified = true;
                 break;
+            case T_PUBLIC_SET:
+                $setScope = 'public';
+                break;
+            case T_PROTECTED_SET:
+                $setScope = 'protected';
+                break;
+            case T_PRIVATE_SET:
+                $setScope = 'private';
+                break;
             case T_STATIC:
                 $isStatic = true;
                 break;
             case T_READONLY:
                 $isReadonly = true;
                 break;
-            }
+            case T_FINAL:
+                $isFinal = true;
+                break;
+            }//end switch
         }//end for
 
         $type         = '';
@@ -1937,17 +1990,19 @@ public function getMemberProperties($stackPtr)
         if ($i < $stackPtr) {
             // We've found a type.
             $valid = [
-                T_STRING            => T_STRING,
-                T_CALLABLE          => T_CALLABLE,
-                T_SELF              => T_SELF,
-                T_PARENT            => T_PARENT,
-                T_FALSE             => T_FALSE,
-                T_TRUE              => T_TRUE,
-                T_NULL              => T_NULL,
-                T_NAMESPACE         => T_NAMESPACE,
-                T_NS_SEPARATOR      => T_NS_SEPARATOR,
-                T_TYPE_UNION        => T_TYPE_UNION,
-                T_TYPE_INTERSECTION => T_TYPE_INTERSECTION,
+                T_STRING                 => T_STRING,
+                T_CALLABLE               => T_CALLABLE,
+                T_SELF                   => T_SELF,
+                T_PARENT                 => T_PARENT,
+                T_FALSE                  => T_FALSE,
+                T_TRUE                   => T_TRUE,
+                T_NULL                   => T_NULL,
+                T_NAMESPACE              => T_NAMESPACE,
+                T_NS_SEPARATOR           => T_NS_SEPARATOR,
+                T_TYPE_UNION             => T_TYPE_UNION,
+                T_TYPE_INTERSECTION      => T_TYPE_INTERSECTION,
+                T_TYPE_OPEN_PARENTHESIS  => T_TYPE_OPEN_PARENTHESIS,
+                T_TYPE_CLOSE_PARENTHESIS => T_TYPE_CLOSE_PARENTHESIS,
             ];
 
             for ($i; $i < $stackPtr; $i++) {
@@ -1978,8 +2033,10 @@ public function getMemberProperties($stackPtr)
         return [
             'scope'           => $scope,
             'scope_specified' => $scopeSpecified,
+            'set_scope'       => $setScope,
             'is_static'       => $isStatic,
             'is_readonly'     => $isReadonly,
+            'is_final'        => $isFinal,
             'type'            => $type,
             'type_token'      => $typeToken,
             'type_end_token'  => $typeEndToken,
@@ -2073,7 +2130,7 @@ public function isReference($stackPtr)
         }
 
         $tokenBefore = $this->findPrevious(
-            Util\Tokens::$emptyTokens,
+            Tokens::$emptyTokens,
             ($stackPtr - 1),
             null,
             true
@@ -2097,14 +2154,14 @@ public function isReference($stackPtr)
             return true;
         }
 
-        if (isset(Util\Tokens::$assignmentTokens[$this->tokens[$tokenBefore]['code']]) === true) {
+        if (isset(Tokens::$assignmentTokens[$this->tokens[$tokenBefore]['code']]) === true) {
             // This is directly after an assignment. It's a reference. Even if
             // it is part of an operation, the other tests will handle it.
             return true;
         }
 
         $tokenAfter = $this->findNext(
-            Util\Tokens::$emptyTokens,
+            Tokens::$emptyTokens,
             ($stackPtr + 1),
             null,
             true
@@ -2155,7 +2212,7 @@ public function isReference($stackPtr)
             if ($this->tokens[$tokenAfter]['code'] === T_VARIABLE) {
                 return true;
             } else {
-                $skip   = Util\Tokens::$emptyTokens;
+                $skip   = Tokens::$emptyTokens;
                 $skip[] = T_NS_SEPARATOR;
                 $skip[] = T_SELF;
                 $skip[] = T_PARENT;
@@ -2245,7 +2302,7 @@ public function getTokensAsString($start, $length, $origContent=false)
      *                                  be returned.
      * @param bool             $local   If true, tokens outside the current statement
      *                                  will not be checked. IE. checking will stop
-     *                                  at the previous semi-colon found.
+     *                                  at the previous semicolon found.
      *
      * @return int|false
      * @see    findNext()
@@ -2326,7 +2383,7 @@ public function findPrevious(
      *                                  be returned.
      * @param bool             $local   If true, tokens outside the current statement
      *                                  will not be checked. i.e., checking will stop
-     *                                  at the next semi-colon found.
+     *                                  at the next semicolon found.
      *
      * @return int|false
      * @see    findPrevious()
@@ -2382,7 +2439,7 @@ public function findNext(
      */
     public function findStartOfStatement($start, $ignore=null)
     {
-        $startTokens = Util\Tokens::$blockOpeners;
+        $startTokens = Tokens::$blockOpeners;
         $startTokens[T_OPEN_SHORT_ARRAY]   = true;
         $startTokens[T_OPEN_TAG]           = true;
         $startTokens[T_OPEN_TAG_WITH_ECHO] = true;
@@ -2412,51 +2469,88 @@ public function findStartOfStatement($start, $ignore=null)
         // If the start token is inside the case part of a match expression,
         // find the start of the condition. If it's in the statement part, find
         // the token that comes after the match arrow.
-        $matchExpression = $this->getCondition($start, T_MATCH);
-        if ($matchExpression !== false) {
-            for ($prevMatch = $start; $prevMatch > $this->tokens[$matchExpression]['scope_opener']; $prevMatch--) {
-                if ($prevMatch !== $start
-                    && ($this->tokens[$prevMatch]['code'] === T_MATCH_ARROW
-                    || $this->tokens[$prevMatch]['code'] === T_COMMA)
-                ) {
-                    break;
-                }
+        if (empty($this->tokens[$start]['conditions']) === false) {
+            $conditions         = $this->tokens[$start]['conditions'];
+            $lastConditionOwner = end($conditions);
+            $matchExpression    = key($conditions);
+
+            if ($lastConditionOwner === T_MATCH
+                // Check if the $start token is at the same parentheses nesting level as the match token.
+                && ((empty($this->tokens[$matchExpression]['nested_parenthesis']) === true
+                && empty($this->tokens[$start]['nested_parenthesis']) === true)
+                || ((empty($this->tokens[$matchExpression]['nested_parenthesis']) === false
+                && empty($this->tokens[$start]['nested_parenthesis']) === false)
+                && $this->tokens[$matchExpression]['nested_parenthesis'] === $this->tokens[$start]['nested_parenthesis']))
+            ) {
+                // Walk back to the previous match arrow (if it exists).
+                $lastComma          = null;
+                $inNestedExpression = false;
+                for ($prevMatch = $start; $prevMatch > $this->tokens[$matchExpression]['scope_opener']; $prevMatch--) {
+                    if ($prevMatch !== $start && $this->tokens[$prevMatch]['code'] === T_MATCH_ARROW) {
+                        break;
+                    }
 
-                // Skip nested statements.
-                if (isset($this->tokens[$prevMatch]['bracket_opener']) === true
-                    && $prevMatch === $this->tokens[$prevMatch]['bracket_closer']
-                ) {
-                    $prevMatch = $this->tokens[$prevMatch]['bracket_opener'];
-                } else if (isset($this->tokens[$prevMatch]['parenthesis_opener']) === true
-                    && $prevMatch === $this->tokens[$prevMatch]['parenthesis_closer']
-                ) {
-                    $prevMatch = $this->tokens[$prevMatch]['parenthesis_opener'];
-                }
-            }
+                    if ($prevMatch !== $start && $this->tokens[$prevMatch]['code'] === T_COMMA) {
+                        $lastComma = $prevMatch;
+                        continue;
+                    }
 
-            if ($prevMatch <= $this->tokens[$matchExpression]['scope_opener']) {
-                // We're before the arrow in the first case.
-                $next = $this->findNext(Util\Tokens::$emptyTokens, ($this->tokens[$matchExpression]['scope_opener'] + 1), null, true);
-                if ($next === false) {
-                    return $start;
-                }
+                    // Skip nested statements.
+                    if (isset($this->tokens[$prevMatch]['bracket_opener']) === true
+                        && $prevMatch === $this->tokens[$prevMatch]['bracket_closer']
+                    ) {
+                        $prevMatch = $this->tokens[$prevMatch]['bracket_opener'];
+                        continue;
+                    }
 
-                return $next;
-            }
+                    if (isset($this->tokens[$prevMatch]['parenthesis_opener']) === true
+                        && $prevMatch === $this->tokens[$prevMatch]['parenthesis_closer']
+                    ) {
+                        $prevMatch = $this->tokens[$prevMatch]['parenthesis_opener'];
+                        continue;
+                    }
 
-            if ($this->tokens[$prevMatch]['code'] === T_COMMA) {
-                // We're before the arrow, but not in the first case.
-                $prevMatchArrow = $this->findPrevious(T_MATCH_ARROW, ($prevMatch - 1), $this->tokens[$matchExpression]['scope_opener']);
-                if ($prevMatchArrow === false) {
-                    // We're before the arrow in the first case.
-                    $next = $this->findNext(Util\Tokens::$emptyTokens, ($this->tokens[$matchExpression]['scope_opener'] + 1), null, true);
-                    return $next;
-                }
+                    // Stop if we're _within_ a nested short array statement, which may contain comma's too.
+                    // No need to deal with parentheses, those are handled above via the `nested_parenthesis` checks.
+                    if (isset($this->tokens[$prevMatch]['bracket_opener']) === true
+                        && $this->tokens[$prevMatch]['bracket_closer'] > $start
+                    ) {
+                        $inNestedExpression = true;
+                        break;
+                    }
+                }//end for
+
+                if ($inNestedExpression === false) {
+                    // $prevMatch will now either be the scope opener or a match arrow.
+                    // If it is the scope opener, go the first non-empty token after. $start will have been part of the first condition.
+                    if ($prevMatch <= $this->tokens[$matchExpression]['scope_opener']) {
+                        // We're before the arrow in the first case.
+                        $next = $this->findNext(Tokens::$emptyTokens, ($this->tokens[$matchExpression]['scope_opener'] + 1), null, true);
+                        if ($next === false) {
+                            // Shouldn't be possible.
+                            return $start;
+                        }
 
-                $end  = $this->findEndOfStatement($prevMatchArrow);
-                $next = $this->findNext(Util\Tokens::$emptyTokens, ($end + 1), null, true);
-                return $next;
-            }
+                        return $next;
+                    }
+
+                    // Okay, so we found a match arrow.
+                    // If $start was part of the "next" condition, the last comma will be set.
+                    // Otherwise, $start must have been part of a return expression.
+                    if (isset($lastComma) === true && $lastComma > $prevMatch) {
+                        $prevMatch = $lastComma;
+                    }
+
+                    // In both cases, go to the first non-empty token after.
+                    $next = $this->findNext(Tokens::$emptyTokens, ($prevMatch + 1), null, true);
+                    if ($next === false) {
+                        // Shouldn't be possible.
+                        return $start;
+                    }
+
+                    return $next;
+                }//end if
+            }//end if
         }//end if
 
         $lastNotEmpty = $start;
@@ -2494,6 +2588,7 @@ public function findStartOfStatement($start, $ignore=null)
                 && $this->tokens[$i]['code'] !== T_CONTINUE
                 && $this->tokens[$i]['code'] !== T_THROW
                 && $this->tokens[$i]['code'] !== T_EXIT
+                && $this->tokens[$i]['code'] !== T_GOTO
             ) {
                 // Found the end of the previous scope block.
                 return $lastNotEmpty;
@@ -2515,7 +2610,7 @@ public function findStartOfStatement($start, $ignore=null)
                 }
             }//end if
 
-            if (isset(Util\Tokens::$emptyTokens[$this->tokens[$i]['code']]) === false) {
+            if (isset(Tokens::$emptyTokens[$this->tokens[$i]['code']]) === false) {
                 $lastNotEmpty = $i;
             }
         }//end for
@@ -2610,7 +2705,7 @@ public function findEndOfStatement($start, $ignore=null)
                     continue;
                 }
 
-                if ($i === $start && isset(Util\Tokens::$scopeOpeners[$this->tokens[$i]['code']]) === true) {
+                if ($i === $start && isset(Tokens::$scopeOpeners[$this->tokens[$i]['code']]) === true) {
                     return $this->tokens[$i]['scope_closer'];
                 }
 
@@ -2630,7 +2725,7 @@ public function findEndOfStatement($start, $ignore=null)
                 }
             }//end if
 
-            if (isset(Util\Tokens::$emptyTokens[$this->tokens[$i]['code']]) === false) {
+            if (isset(Tokens::$emptyTokens[$this->tokens[$i]['code']]) === false) {
                 $lastNotEmpty = $i;
             }
         }//end for
diff --git a/app/vendor/squizlabs/php_codesniffer/src/Files/FileList.php b/app/vendor/squizlabs/php_codesniffer/src/Files/FileList.php
index 13357ecde..ab52e3388 100644
--- a/app/vendor/squizlabs/php_codesniffer/src/Files/FileList.php
+++ b/app/vendor/squizlabs/php_codesniffer/src/Files/FileList.php
@@ -11,14 +11,20 @@
 
 namespace PHP_CodeSniffer\Files;
 
+use Countable;
+use FilesystemIterator;
+use Iterator;
 use PHP_CodeSniffer\Autoload;
-use PHP_CodeSniffer\Util;
-use PHP_CodeSniffer\Ruleset;
 use PHP_CodeSniffer\Config;
 use PHP_CodeSniffer\Exceptions\DeepExitException;
+use PHP_CodeSniffer\Ruleset;
+use PHP_CodeSniffer\Util\Common;
+use RecursiveArrayIterator;
+use RecursiveDirectoryIterator;
+use RecursiveIteratorIterator;
 use ReturnTypeWillChange;
 
-class FileList implements \Iterator, \Countable
+class FileList implements Iterator, Countable
 {
 
     /**
@@ -72,7 +78,7 @@ public function __construct(Config $config, Ruleset $ruleset)
 
         $paths = $config->files;
         foreach ($paths as $path) {
-            $isPharFile = Util\Common::isPharFile($path);
+            $isPharFile = Common::isPharFile($path);
             if (is_dir($path) === true || $isPharFile === true) {
                 if ($isPharFile === true) {
                     $path = 'phar://'.$path;
@@ -80,9 +86,9 @@ public function __construct(Config $config, Ruleset $ruleset)
 
                 $filterClass = $this->getFilterClass();
 
-                $di       = new \RecursiveDirectoryIterator($path, (\RecursiveDirectoryIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS));
+                $di       = new RecursiveDirectoryIterator($path, (RecursiveDirectoryIterator::SKIP_DOTS | FilesystemIterator::FOLLOW_SYMLINKS));
                 $filter   = new $filterClass($di, $path, $config, $ruleset);
-                $iterator = new \RecursiveIteratorIterator($filter);
+                $iterator = new RecursiveIteratorIterator($filter);
 
                 foreach ($iterator as $file) {
                     $this->files[$file->getPathname()] = null;
@@ -121,9 +127,9 @@ public function addFile($path, $file=null)
 
         $filterClass = $this->getFilterClass();
 
-        $di       = new \RecursiveArrayIterator([$path]);
+        $di       = new RecursiveArrayIterator([$path]);
         $filter   = new $filterClass($di, $path, $this->config, $this->ruleset);
-        $iterator = new \RecursiveIteratorIterator($filter);
+        $iterator = new RecursiveIteratorIterator($filter);
 
         foreach ($iterator as $path) {
             $this->files[$path] = $file;
diff --git a/app/vendor/squizlabs/php_codesniffer/src/Files/LocalFile.php b/app/vendor/squizlabs/php_codesniffer/src/Files/LocalFile.php
index c2af77c42..babfe69c3 100644
--- a/app/vendor/squizlabs/php_codesniffer/src/Files/LocalFile.php
+++ b/app/vendor/squizlabs/php_codesniffer/src/Files/LocalFile.php
@@ -9,8 +9,8 @@
 
 namespace PHP_CodeSniffer\Files;
 
-use PHP_CodeSniffer\Ruleset;
 use PHP_CodeSniffer\Config;
+use PHP_CodeSniffer\Ruleset;
 use PHP_CodeSniffer\Util\Cache;
 use PHP_CodeSniffer\Util\Common;
 
diff --git a/app/vendor/squizlabs/php_codesniffer/src/Filters/ExactMatch.php b/app/vendor/squizlabs/php_codesniffer/src/Filters/ExactMatch.php
index c929fe810..89517b838 100644
--- a/app/vendor/squizlabs/php_codesniffer/src/Filters/ExactMatch.php
+++ b/app/vendor/squizlabs/php_codesniffer/src/Filters/ExactMatch.php
@@ -11,7 +11,7 @@
 
 namespace PHP_CodeSniffer\Filters;
 
-use PHP_CodeSniffer\Util;
+use PHP_CodeSniffer\Util\Common;
 
 abstract class ExactMatch extends Filter
 {
@@ -64,7 +64,7 @@ public function accept()
             }
         }
 
-        $filePath = Util\Common::realpath($this->current());
+        $filePath = Common::realpath($this->current());
 
         // If a file is both disallowed and allowed, the disallowed files list takes precedence.
         if (isset($this->disallowedFiles[$filePath]) === true) {
diff --git a/app/vendor/squizlabs/php_codesniffer/src/Filters/Filter.php b/app/vendor/squizlabs/php_codesniffer/src/Filters/Filter.php
index c72518c66..12cafa7d0 100644
--- a/app/vendor/squizlabs/php_codesniffer/src/Filters/Filter.php
+++ b/app/vendor/squizlabs/php_codesniffer/src/Filters/Filter.php
@@ -9,12 +9,15 @@
 
 namespace PHP_CodeSniffer\Filters;
 
-use PHP_CodeSniffer\Util;
-use PHP_CodeSniffer\Ruleset;
+use FilesystemIterator;
 use PHP_CodeSniffer\Config;
+use PHP_CodeSniffer\Ruleset;
+use PHP_CodeSniffer\Util\Common;
+use RecursiveDirectoryIterator;
+use RecursiveFilterIterator;
 use ReturnTypeWillChange;
 
-class Filter extends \RecursiveFilterIterator
+class Filter extends RecursiveFilterIterator
 {
 
     /**
@@ -94,7 +97,7 @@ public function __construct($iterator, $basedir, Config $config, Ruleset $rulese
     public function accept()
     {
         $filePath = $this->current();
-        $realPath = Util\Common::realpath($filePath);
+        $realPath = Common::realpath($filePath);
 
         if ($realPath !== false) {
             // It's a real path somewhere, so record it
@@ -137,7 +140,7 @@ public function getChildren()
     {
         $filterClass = get_called_class();
         $children    = new $filterClass(
-            new \RecursiveDirectoryIterator($this->current(), (\RecursiveDirectoryIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS)),
+            new RecursiveDirectoryIterator($this->current(), (RecursiveDirectoryIterator::SKIP_DOTS | FilesystemIterator::FOLLOW_SYMLINKS)),
             $this->basedir,
             $this->config,
             $this->ruleset
@@ -176,7 +179,7 @@ protected function shouldProcessFile($path)
         // complete extension list and make sure one is allowed.
         $extensions = [];
         array_shift($fileParts);
-        foreach ($fileParts as $part) {
+        while (empty($fileParts) === false) {
             $extensions[implode('.', $fileParts)] = 1;
             array_shift($fileParts);
         }
@@ -244,13 +247,6 @@ protected function shouldIgnorePath($path)
         }
 
         foreach ($ignorePatterns as $pattern => $type) {
-            // Maintains backwards compatibility in case the ignore pattern does
-            // not have a relative/absolute value.
-            if (is_int($pattern) === true) {
-                $pattern = $type;
-                $type    = 'absolute';
-            }
-
             $replacements = [
                 '\\,' => ',',
                 '*'   => '.*',
diff --git a/app/vendor/squizlabs/php_codesniffer/src/Filters/GitModified.php b/app/vendor/squizlabs/php_codesniffer/src/Filters/GitModified.php
index dcd975281..3337287b9 100644
--- a/app/vendor/squizlabs/php_codesniffer/src/Filters/GitModified.php
+++ b/app/vendor/squizlabs/php_codesniffer/src/Filters/GitModified.php
@@ -9,7 +9,7 @@
 
 namespace PHP_CodeSniffer\Filters;
 
-use PHP_CodeSniffer\Util;
+use PHP_CodeSniffer\Util\Common;
 
 class GitModified extends ExactMatch
 {
@@ -65,7 +65,7 @@ protected function getAllowedFiles()
         }
 
         foreach ($output as $path) {
-            $path = Util\Common::realpath($path);
+            $path = Common::realpath($path);
 
             if ($path === false) {
                 continue;
diff --git a/app/vendor/squizlabs/php_codesniffer/src/Filters/GitStaged.php b/app/vendor/squizlabs/php_codesniffer/src/Filters/GitStaged.php
index 5e18359b0..7a764314a 100644
--- a/app/vendor/squizlabs/php_codesniffer/src/Filters/GitStaged.php
+++ b/app/vendor/squizlabs/php_codesniffer/src/Filters/GitStaged.php
@@ -11,7 +11,7 @@
 
 namespace PHP_CodeSniffer\Filters;
 
-use PHP_CodeSniffer\Util;
+use PHP_CodeSniffer\Util\Common;
 
 class GitStaged extends ExactMatch
 {
@@ -67,7 +67,7 @@ protected function getAllowedFiles()
         }
 
         foreach ($output as $path) {
-            $path = Util\Common::realpath($path);
+            $path = Common::realpath($path);
             if ($path === false) {
                 // Skip deleted files.
                 continue;
diff --git a/app/vendor/squizlabs/php_codesniffer/src/Fixer.php b/app/vendor/squizlabs/php_codesniffer/src/Fixer.php
index b54dde94b..3e1f482a7 100644
--- a/app/vendor/squizlabs/php_codesniffer/src/Fixer.php
+++ b/app/vendor/squizlabs/php_codesniffer/src/Fixer.php
@@ -12,6 +12,8 @@
 
 namespace PHP_CodeSniffer;
 
+use InvalidArgumentException;
+use PHP_CodeSniffer\Exceptions\RuntimeException;
 use PHP_CodeSniffer\Files\File;
 use PHP_CodeSniffer\Util\Common;
 
@@ -199,7 +201,7 @@ public function fixFile()
 
         $this->enabled = false;
 
-        if ($this->numFixes > 0) {
+        if ($this->numFixes > 0 || $this->inConflict === true) {
             if (PHP_CODESNIFFER_VERBOSITY > 1) {
                 if (ob_get_level() > 0) {
                     ob_end_clean();
@@ -226,6 +228,8 @@ public function fixFile()
      * @param boolean $colors   Print coloured output or not.
      *
      * @return string
+     *
+     * @throws \PHP_CodeSniffer\Exceptions\RuntimeException When the diff command fails.
      */
     public function generateDiff($filePath=null, $colors=true)
     {
@@ -246,19 +250,56 @@ public function generateDiff($filePath=null, $colors=true)
         $fixedFile = fopen($tempName, 'w');
         fwrite($fixedFile, $contents);
 
-        // We must use something like shell_exec() because whitespace at the end
+        // We must use something like shell_exec() or proc_open() because whitespace at the end
         // of lines is critical to diff files.
+        // Using proc_open() instead of shell_exec improves performance on Windows significantly,
+        // while the results are the same (though more code is needed to get the results).
+        // This is specifically due to proc_open allowing to set the "bypass_shell" option.
         $filename = escapeshellarg($filename);
         $cmd      = "diff -u -L$filename -LPHP_CodeSniffer $filename \"$tempName\"";
 
-        $diff = shell_exec($cmd);
+        // Stream 0 = STDIN, 1 = STDOUT, 2 = STDERR.
+        $descriptorspec = [
+            0 => [
+                'pipe',
+                'r',
+            ],
+            1 => [
+                'pipe',
+                'w',
+            ],
+            2 => [
+                'pipe',
+                'w',
+            ],
+        ];
+
+        $options = null;
+        if (stripos(PHP_OS, 'WIN') === 0) {
+            $options = ['bypass_shell' => true];
+        }
+
+        $process = proc_open($cmd, $descriptorspec, $pipes, $cwd, null, $options);
+        if (is_resource($process) === false) {
+            throw new RuntimeException('Could not obtain a resource to execute the diff command.');
+        }
+
+        // We don't need these.
+        fclose($pipes[0]);
+        fclose($pipes[2]);
+
+        // Stdout will contain the actual diff.
+        $diff = stream_get_contents($pipes[1]);
+        fclose($pipes[1]);
+
+        proc_close($process);
 
         fclose($fixedFile);
         if (is_file($tempName) === true) {
             unlink($tempName);
         }
 
-        if ($diff === null) {
+        if ($diff === false || $diff === '') {
             return '';
         }
 
@@ -362,7 +403,7 @@ public function beginChangeset()
             if ($bt[1]['class'] === __CLASS__) {
                 $sniff = 'Fixer';
             } else {
-                $sniff = Util\Common::getSniffCode($bt[1]['class']);
+                $sniff = $this->getSniffCodeForDebug($bt[1]['class']);
             }
 
             $line = $bt[0]['line'];
@@ -447,7 +488,7 @@ public function rollbackChangeset()
                     $line  = $bt[0]['line'];
                 }
 
-                $sniff = Util\Common::getSniffCode($sniff);
+                $sniff = $this->getSniffCodeForDebug($sniff);
 
                 $numChanges = count($this->changeset);
 
@@ -504,7 +545,7 @@ public function replaceToken($stackPtr, $content)
                 $line  = $bt[0]['line'];
             }
 
-            $sniff = Util\Common::getSniffCode($sniff);
+            $sniff = $this->getSniffCodeForDebug($sniff);
 
             $tokens     = $this->currentFile->getTokens();
             $type       = $tokens[$stackPtr]['type'];
@@ -619,7 +660,7 @@ public function revertToken($stackPtr)
                 $line  = $bt[0]['line'];
             }
 
-            $sniff = Util\Common::getSniffCode($sniff);
+            $sniff = $this->getSniffCodeForDebug($sniff);
 
             $tokens     = $this->currentFile->getTokens();
             $type       = $tokens[$stackPtr]['type'];
@@ -803,4 +844,24 @@ public function changeCodeBlockIndent($start, $end, $change)
     }//end changeCodeBlockIndent()
 
 
+    /**
+     * Get the sniff code for the current sniff or the class name if the passed class is not a sniff.
+     *
+     * @param string $className Class name.
+     *
+     * @return string
+     */
+    private function getSniffCodeForDebug($className)
+    {
+        try {
+            $sniffCode = Common::getSniffCode($className);
+            return $sniffCode;
+        } catch (InvalidArgumentException $e) {
+            // Sniff code could not be determined. This may be an abstract sniff class or a helper class.
+            return $className;
+        }
+
+    }//end getSniffCodeForDebug()
+
+
 }//end class
diff --git a/app/vendor/squizlabs/php_codesniffer/src/Generators/Generator.php b/app/vendor/squizlabs/php_codesniffer/src/Generators/Generator.php
index 483cae800..9878cc457 100644
--- a/app/vendor/squizlabs/php_codesniffer/src/Generators/Generator.php
+++ b/app/vendor/squizlabs/php_codesniffer/src/Generators/Generator.php
@@ -6,14 +6,18 @@
  * in a standard.
  *
  * @author    Greg Sherwood 
+ * @author    Juliette Reinders Folmer 
  * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
+ * @copyright 2024 PHPCSStandards and contributors
  * @license   https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
  */
 
 namespace PHP_CodeSniffer\Generators;
 
-use PHP_CodeSniffer\Ruleset;
+use DOMDocument;
+use DOMNode;
 use PHP_CodeSniffer\Autoload;
+use PHP_CodeSniffer\Ruleset;
 
 abstract class Generator
 {
@@ -44,20 +48,27 @@ public function __construct(Ruleset $ruleset)
     {
         $this->ruleset = $ruleset;
 
+        $find    = [
+            DIRECTORY_SEPARATOR.'Sniffs'.DIRECTORY_SEPARATOR,
+            'Sniff.php',
+        ];
+        $replace = [
+            DIRECTORY_SEPARATOR.'Docs'.DIRECTORY_SEPARATOR,
+            'Standard.xml',
+        ];
+
         foreach ($ruleset->sniffs as $className => $sniffClass) {
             $file    = Autoload::getLoadedFileName($className);
-            $docFile = str_replace(
-                DIRECTORY_SEPARATOR.'Sniffs'.DIRECTORY_SEPARATOR,
-                DIRECTORY_SEPARATOR.'Docs'.DIRECTORY_SEPARATOR,
-                $file
-            );
-            $docFile = str_replace('Sniff.php', 'Standard.xml', $docFile);
+            $docFile = str_replace($find, $replace, $file);
 
             if (is_file($docFile) === true) {
                 $this->docFiles[] = $docFile;
             }
         }
 
+        // Always present the docs in a consistent alphabetical order.
+        sort($this->docFiles, (SORT_NATURAL | SORT_FLAG_CASE));
+
     }//end __construct()
 
 
@@ -70,9 +81,24 @@ public function __construct(Ruleset $ruleset)
      *
      * @return string
      */
-    protected function getTitle(\DOMNode $doc)
+    protected function getTitle(DOMNode $doc)
     {
-        return $doc->getAttribute('title');
+        $title = $doc->getAttribute('title');
+
+        if (empty($title) === true) {
+            // Fall back to the sniff name if no title was supplied.
+            $fileName  = $doc->ownerDocument->documentURI;
+            $lastSlash = strrpos($fileName, '/');
+            if (is_int($lastSlash) === true) {
+                // Get the sniff name without "Standard.xml".
+                $title = substr($fileName, ($lastSlash + 1), -12);
+
+                // Split the sniff name to individual words.
+                $title = preg_replace('`[-._]|(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])`', '$1 $2', $title);
+            }
+        }
+
+        return $title;
 
     }//end getTitle()
 
@@ -90,7 +116,7 @@ protected function getTitle(\DOMNode $doc)
     public function generate()
     {
         foreach ($this->docFiles as $file) {
-            $doc = new \DOMDocument();
+            $doc = new DOMDocument();
             $doc->load($file);
             $documentation = $doc->getElementsByTagName('documentation')->item(0);
             $this->processSniff($documentation);
@@ -111,7 +137,7 @@ public function generate()
      * @return void
      * @see    generate()
      */
-    abstract protected function processSniff(\DOMNode $doc);
+    abstract protected function processSniff(DOMNode $doc);
 
 
 }//end class
diff --git a/app/vendor/squizlabs/php_codesniffer/src/Generators/HTML.php b/app/vendor/squizlabs/php_codesniffer/src/Generators/HTML.php
index 55acd9e17..7a8408f17 100644
--- a/app/vendor/squizlabs/php_codesniffer/src/Generators/HTML.php
+++ b/app/vendor/squizlabs/php_codesniffer/src/Generators/HTML.php
@@ -7,17 +7,119 @@
  * to each sniff.
  *
  * @author    Greg Sherwood 
+ * @author    Juliette Reinders Folmer 
  * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
+ * @copyright 2024 PHPCSStandards and contributors
  * @license   https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
  */
 
 namespace PHP_CodeSniffer\Generators;
 
+use DOMDocument;
+use DOMElement;
+use DOMNode;
 use PHP_CodeSniffer\Config;
 
 class HTML extends Generator
 {
 
+    /**
+     * Stylesheet for the HTML output.
+     *
+     * @var string
+     */
+    const STYLESHEET = '';
+
+    /**
+     * List of seen slugified anchors to ensure uniqueness.
+     *
+     * @var array
+     */
+    private $seenAnchors = [];
+
 
     /**
      * Generates the documentation for a standard.
@@ -27,23 +129,26 @@ class HTML extends Generator
      */
     public function generate()
     {
-        ob_start();
-        $this->printHeader();
-        $this->printToc();
-
-        foreach ($this->docFiles as $file) {
-            $doc = new \DOMDocument();
-            $doc->load($file);
-            $documentation = $doc->getElementsByTagName('documentation')->item(0);
-            $this->processSniff($documentation);
+        if (empty($this->docFiles) === true) {
+            return;
         }
 
-        $this->printFooter();
+        ob_start();
+        parent::generate();
 
         $content = ob_get_contents();
         ob_end_clean();
 
-        echo $content;
+        // Clear anchor cache after Documentation generation.
+        // The anchor generation for the TOC anchor links will use the same logic, so should end up with the same unique slugs.
+        $this->seenAnchors = [];
+
+        if (trim($content) !== '') {
+            echo $this->getFormattedHeader();
+            echo $this->getFormattedToc();
+            echo $content;
+            echo $this->getFormattedFooter();
+        }
 
     }//end generate()
 
@@ -51,132 +156,155 @@ public function generate()
     /**
      * Print the header of the HTML page.
      *
+     * @deprecated 3.12.0 Use HTML::getFormattedHeader() instead.
+     *
+     * @codeCoverageIgnore
+     *
      * @return void
      */
     protected function printHeader()
     {
-        $standard = $this->ruleset->name;
-        echo ''.PHP_EOL;
-        echo ' '.PHP_EOL;
-        echo "  $standard Coding Standards".PHP_EOL;
-        echo '  '.PHP_EOL;
-        echo ' '.PHP_EOL;
-        echo ' '.PHP_EOL;
-        echo "  

$standard Coding Standards

".PHP_EOL; + trigger_error( + 'The '.__METHOD__.'() method is deprecated. Use "echo '.__CLASS__.'::getFormattedHeader()" instead.', + E_USER_DEPRECATED + ); + + echo $this->getFormattedHeader(); }//end printHeader() + /** + * Format the header of the HTML page. + * + * @since 3.12.0 Replaces the deprecated HTML::printHeader() method. + * + * @return string + */ + protected function getFormattedHeader() + { + $standard = $this->ruleset->name; + $output = sprintf( + ' + + %1$s Coding Standards + %2$s + + +

%1$s Coding Standards

', + $standard, + self::STYLESHEET + ); + + // Use the correct line endings based on the OS. + return str_replace("\n", PHP_EOL, $output).PHP_EOL; + + }//end getFormattedHeader() + + /** * Print the table of contents for the standard. * - * The TOC is just an unordered list of bookmarks to sniffs on the page. + * @deprecated 3.12.0 Use HTML::getFormattedToc() instead. + * + * @codeCoverageIgnore * * @return void */ protected function printToc() { - echo '

Table of Contents

'.PHP_EOL; - echo '
    '.PHP_EOL; + trigger_error( + 'The '.__METHOD__.'() method is deprecated. Use "echo '.__CLASS__.'::getFormattedToc()" instead.', + E_USER_DEPRECATED + ); + + echo $this->getFormattedToc(); + + }//end printToc() + + + /** + * Format the table of contents for the standard. + * + * The TOC is just an unordered list of bookmarks to sniffs on the page. + * + * @since 3.12.0 Replaces the deprecated HTML::printToc() method. + * + * @return string + */ + protected function getFormattedToc() + { + // Only show a TOC when there are two or more docs to display. + if (count($this->docFiles) < 2) { + return ''; + } + + $output = '

    Table of Contents

    '.PHP_EOL; + $output .= '
      '.PHP_EOL; + + $listItemTemplate = '
    • %s
    • '.PHP_EOL; foreach ($this->docFiles as $file) { - $doc = new \DOMDocument(); + $doc = new DOMDocument(); $doc->load($file); $documentation = $doc->getElementsByTagName('documentation')->item(0); $title = $this->getTitle($documentation); - echo '
    • $title
    • ".PHP_EOL; + $output .= sprintf($listItemTemplate, $this->titleToAnchor($title), $title); } - echo '
    '.PHP_EOL; + $output .= '
'.PHP_EOL; - }//end printToc() + return $output; + + }//end getFormattedToc() /** * Print the footer of the HTML page. * + * @deprecated 3.12.0 Use HTML::getFormattedFooter() instead. + * + * @codeCoverageIgnore + * * @return void */ protected function printFooter() + { + trigger_error( + 'The '.__METHOD__.'() method is deprecated. Use "echo '.__CLASS__.'::getFormattedFooter()" instead.', + E_USER_DEPRECATED + ); + + echo $this->getFormattedFooter(); + + }//end printFooter() + + + /** + * Format the footer of the HTML page. + * + * @since 3.12.0 Replaces the deprecated HTML::printFooter() method. + * + * @return string + */ + protected function getFormattedFooter() { // Turn off errors so we don't get timezone warnings if people // don't have their timezone set. $errorLevel = error_reporting(0); - echo '
'; - echo 'Documentation generated on '.date('r'); - echo ' by PHP_CodeSniffer '.Config::VERSION.''; - echo '
'.PHP_EOL; + $output = sprintf( + '
Documentation generated on %s by PHP_CodeSniffer %s
+ +', + date('r'), + Config::VERSION + ); error_reporting($errorLevel); - echo ' '.PHP_EOL; - echo ''.PHP_EOL; + // Use the correct line endings based on the OS. + return str_replace("\n", PHP_EOL, $output).PHP_EOL; - }//end printFooter() + }//end getFormattedFooter() /** @@ -188,42 +316,132 @@ protected function printFooter() * * @return void */ - public function processSniff(\DOMNode $doc) + public function processSniff(DOMNode $doc) { - $title = $this->getTitle($doc); - echo ' '.PHP_EOL; - echo "

$title

".PHP_EOL; - + $content = ''; foreach ($doc->childNodes as $node) { if ($node->nodeName === 'standard') { - $this->printTextBlock($node); + $content .= $this->getFormattedTextBlock($node); } else if ($node->nodeName === 'code_comparison') { - $this->printCodeComparisonBlock($node); + $content .= $this->getFormattedCodeComparisonBlock($node); } } + if (trim($content) !== '') { + $title = $this->getTitle($doc); + printf( + '

%2$s §

'.PHP_EOL, + $this->titleToAnchor($title), + $title + ); + echo $content; + } + }//end processSniff() + /** + * Transform a title to a string which can be used as an HTML anchor. + * + * @param string $title The title. + * + * @since 3.12.0 + * + * @return string + */ + private function titleToAnchor($title) + { + // Slugify the text. + $title = strtolower($title); + $title = preg_replace('`[^a-z0-9\._-]`', '-', $title); + + if (isset($this->seenAnchors[$title]) === true) { + // Try to find a unique anchor for this title. + for ($i = 2; (isset($this->seenAnchors[$title.'-'.$i]) === true); $i++); + $title .= '-'.$i; + } + + // Add to "seen" list. + $this->seenAnchors[$title] = true; + + return $title; + + }//end titleToAnchor() + + /** * Print a text block found in a standard. * * @param \DOMNode $node The DOMNode object for the text block. * + * @deprecated 3.12.0 Use HTML::getFormattedTextBlock() instead. + * + * @codeCoverageIgnore + * * @return void */ - protected function printTextBlock(\DOMNode $node) + protected function printTextBlock(DOMNode $node) { - $content = trim($node->nodeValue); - $content = htmlspecialchars($content); + trigger_error( + 'The '.__METHOD__.'() method is deprecated. Use "echo '.__CLASS__.'::getFormattedTextBlock()" instead.', + E_USER_DEPRECATED + ); - // Allow em tags only. + echo $this->getFormattedTextBlock($node); + + }//end printTextBlock() + + + /** + * Format a text block found in a standard. + * + * @param \DOMNode $node The DOMNode object for the text block. + * + * @since 3.12.0 Replaces the deprecated HTML::printTextBlock() method. + * + * @return string + */ + protected function getFormattedTextBlock(DOMNode $node) + { + $content = $node->nodeValue; + if (empty($content) === true) { + return ''; + } + + $content = trim($content); + $content = htmlspecialchars($content, (ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401)); + + // Allow only em tags. $content = str_replace('<em>', '', $content); $content = str_replace('</em>', '', $content); - echo "

$content

".PHP_EOL; + $nodeLines = explode("\n", $content); + $lineCount = count($nodeLines); + $lines = []; + + for ($i = 0; $i < $lineCount; $i++) { + $currentLine = trim($nodeLines[$i]); + + if (isset($nodeLines[($i + 1)]) === false) { + // We're at the end of the text, just add the line. + $lines[] = $currentLine; + } else { + $nextLine = trim($nodeLines[($i + 1)]); + if ($nextLine === '') { + // Next line is a blank line, end the paragraph and start a new one. + // Also skip over the blank line. + $lines[] = $currentLine.'

'.PHP_EOL.'

'; + ++$i; + } else { + // Next line is not blank, so just add a line break. + $lines[] = $currentLine.'
'.PHP_EOL; + } + } + } + + return '

'.implode('', $lines).'

'.PHP_EOL; - }//end printTextBlock() + }//end getFormattedTextBlock() /** @@ -231,40 +449,116 @@ protected function printTextBlock(\DOMNode $node) * * @param \DOMNode $node The DOMNode object for the code comparison block. * + * @deprecated 3.12.0 Use HTML::getFormattedCodeComparisonBlock() instead. + * + * @codeCoverageIgnore + * * @return void */ - protected function printCodeComparisonBlock(\DOMNode $node) + protected function printCodeComparisonBlock(DOMNode $node) { - $codeBlocks = $node->getElementsByTagName('code'); - - $firstTitle = $codeBlocks->item(0)->getAttribute('title'); - $first = trim($codeBlocks->item(0)->nodeValue); - $first = str_replace('', $first); - $first = str_replace(' ', ' ', $first); - $first = str_replace('', '', $first); - $first = str_replace('', '', $first); - - $secondTitle = $codeBlocks->item(1)->getAttribute('title'); - $second = trim($codeBlocks->item(1)->nodeValue); - $second = str_replace('', $second); - $second = str_replace(' ', ' ', $second); - $second = str_replace('', '', $second); - $second = str_replace('', '', $second); - - echo '
'.PHP_EOL; - echo ' '.PHP_EOL; - echo " ".PHP_EOL; - echo " ".PHP_EOL; - echo ' '.PHP_EOL; - echo ' '.PHP_EOL; - echo " ".PHP_EOL; - echo " ".PHP_EOL; - echo ' '.PHP_EOL; - echo '
$firstTitle$secondTitle
$first$second
'.PHP_EOL; + trigger_error( + 'The '.__METHOD__.'() method is deprecated. Use "echo '.__CLASS__.'::getFormattedCodeComparisonBlock()" instead.', + E_USER_DEPRECATED + ); + + echo $this->getFormattedCodeComparisonBlock($node); }//end printCodeComparisonBlock() + /** + * Format a code comparison block found in a standard. + * + * @param \DOMNode $node The DOMNode object for the code comparison block. + * + * @since 3.12.0 Replaces the deprecated HTML::printCodeComparisonBlock() method. + * + * @return string + */ + protected function getFormattedCodeComparisonBlock(DOMNode $node) + { + $codeBlocks = $node->getElementsByTagName('code'); + $firstCodeElm = $codeBlocks->item(0); + $secondCodeElm = $codeBlocks->item(1); + + if (isset($firstCodeElm, $secondCodeElm) === false) { + // Missing at least one code block. + return ''; + } + + $firstTitle = $this->formatCodeTitle($firstCodeElm); + $first = $this->formatCodeSample($firstCodeElm); + + $secondTitle = $this->formatCodeTitle($secondCodeElm); + $second = $this->formatCodeSample($secondCodeElm); + + $titleRow = ''; + if ($firstTitle !== '' || $secondTitle !== '') { + $titleRow .= ' '.PHP_EOL; + $titleRow .= " $firstTitle".PHP_EOL; + $titleRow .= " $secondTitle".PHP_EOL; + $titleRow .= ' '.PHP_EOL; + } + + $codeRow = ''; + if ($first !== '' || $second !== '') { + $codeRow .= ' '.PHP_EOL; + $codeRow .= " $first".PHP_EOL; + $codeRow .= " $second".PHP_EOL; + $codeRow .= ' '.PHP_EOL; + } + + $output = ''; + if ($titleRow !== '' || $codeRow !== '') { + $output = ' '.PHP_EOL; + $output .= $titleRow; + $output .= $codeRow; + $output .= '
'.PHP_EOL; + } + + return $output; + + }//end getFormattedCodeComparisonBlock() + + + /** + * Retrieve a code block title and prepare it for output as HTML. + * + * @param \DOMElement $codeElm The DOMElement object for a code block. + * + * @since 3.12.0 + * + * @return string + */ + private function formatCodeTitle(DOMElement $codeElm) + { + $title = trim($codeElm->getAttribute('title')); + return str_replace(' ', '  ', $title); + + }//end formatCodeTitle() + + + /** + * Retrieve a code block contents and prepare it for output as HTML. + * + * @param \DOMElement $codeElm The DOMElement object for a code block. + * + * @since 3.12.0 + * + * @return string + */ + private function formatCodeSample(DOMElement $codeElm) + { + $code = (string) $codeElm->nodeValue; + $code = trim($code); + $code = str_replace('', ' '], $code); + $code = str_replace(['', ''], ['', ''], $code); + + return $code; + + }//end formatCodeSample() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Generators/Markdown.php b/app/vendor/squizlabs/php_codesniffer/src/Generators/Markdown.php index 23bed27e2..f73fcd935 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Generators/Markdown.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Generators/Markdown.php @@ -3,12 +3,16 @@ * A doc generator that outputs documentation in Markdown format. * * @author Stefano Kowalke + * @author Juliette Reinders Folmer * @copyright 2014 Arroba IT + * @copyright 2024 PHPCSStandards and contributors * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Generators; +use DOMElement; +use DOMNode; use PHP_CodeSniffer\Config; class Markdown extends Generator @@ -23,21 +27,21 @@ class Markdown extends Generator */ public function generate() { - ob_start(); - $this->printHeader(); - - foreach ($this->docFiles as $file) { - $doc = new \DOMDocument(); - $doc->load($file); - $documentation = $doc->getElementsByTagName('documentation')->item(0); - $this->processSniff($documentation); + if (empty($this->docFiles) === true) { + return; } - $this->printFooter(); + ob_start(); + parent::generate(); + $content = ob_get_contents(); ob_end_clean(); - echo $content; + if (trim($content) !== '') { + echo $this->getFormattedHeader(); + echo $content; + echo $this->getFormattedFooter(); + } }//end generate() @@ -45,31 +49,80 @@ public function generate() /** * Print the markdown header. * + * @deprecated 3.12.0 Use Markdown::getFormattedHeader() instead. + * + * @codeCoverageIgnore + * * @return void */ protected function printHeader() { - $standard = $this->ruleset->name; + trigger_error( + 'The '.__METHOD__.'() method is deprecated. Use "echo '.__CLASS__.'::getFormattedHeader()" instead.', + E_USER_DEPRECATED + ); - echo "# $standard Coding Standard".PHP_EOL; + echo $this->getFormattedHeader(); }//end printHeader() + /** + * Format the markdown header. + * + * @since 3.12.0 Replaces the deprecated Markdown::printHeader() method. + * + * @return string + */ + protected function getFormattedHeader() + { + $standard = $this->ruleset->name; + + return "# $standard Coding Standard".PHP_EOL; + + }//end getFormattedHeader() + + /** * Print the markdown footer. * + * @deprecated 3.12.0 Use Markdown::getFormattedFooter() instead. + * + * @codeCoverageIgnore + * * @return void */ protected function printFooter() + { + trigger_error( + 'The '.__METHOD__.'() method is deprecated. Use "echo '.__CLASS__.'::getFormattedFooter()" instead.', + E_USER_DEPRECATED + ); + + echo $this->getFormattedFooter(); + + }//end printFooter() + + + /** + * Format the markdown footer. + * + * @since 3.12.0 Replaces the deprecated Markdown::printFooter() method. + * + * @return string + */ + protected function getFormattedFooter() { // Turn off errors so we don't get timezone warnings if people // don't have their timezone set. - error_reporting(0); - echo 'Documentation generated on '.date('r'); - echo ' by [PHP_CodeSniffer '.Config::VERSION.'](https://github.com/PHPCSStandards/PHP_CodeSniffer)'.PHP_EOL; + $errorLevel = error_reporting(0); + $output = PHP_EOL.'Documentation generated on '.date('r'); + $output .= ' by [PHP_CodeSniffer '.Config::VERSION.'](https://github.com/PHPCSStandards/PHP_CodeSniffer)'.PHP_EOL; + error_reporting($errorLevel); - }//end printFooter() + return $output; + + }//end getFormattedFooter() /** @@ -81,19 +134,23 @@ protected function printFooter() * * @return void */ - protected function processSniff(\DOMNode $doc) + protected function processSniff(DOMNode $doc) { - $title = $this->getTitle($doc); - echo PHP_EOL."## $title".PHP_EOL; - + $content = ''; foreach ($doc->childNodes as $node) { if ($node->nodeName === 'standard') { - $this->printTextBlock($node); + $content .= $this->getFormattedTextBlock($node); } else if ($node->nodeName === 'code_comparison') { - $this->printCodeComparisonBlock($node); + $content .= $this->getFormattedCodeComparisonBlock($node); } } + if (trim($content) !== '') { + $title = $this->getTitle($doc); + echo PHP_EOL."## $title".PHP_EOL.PHP_EOL; + echo $content; + } + }//end processSniff() @@ -102,19 +159,72 @@ protected function processSniff(\DOMNode $doc) * * @param \DOMNode $node The DOMNode object for the text block. * + * @deprecated 3.12.0 Use Markdown::getFormattedTextBlock() instead. + * + * @codeCoverageIgnore + * * @return void */ - protected function printTextBlock(\DOMNode $node) + protected function printTextBlock(DOMNode $node) { - $content = trim($node->nodeValue); - $content = htmlspecialchars($content); + trigger_error( + 'The '.__METHOD__.'() method is deprecated. Use "echo '.__CLASS__.'::getFormattedTextBlock()" instead.', + E_USER_DEPRECATED + ); + + echo $this->getFormattedTextBlock($node); + + }//end printTextBlock() + + + /** + * Format a text block found in a standard. + * + * @param \DOMNode $node The DOMNode object for the text block. + * + * @since 3.12.0 Replaces the deprecated Markdown::printTextBlock() method. + * + * @return string + */ + protected function getFormattedTextBlock(DOMNode $node) + { + $content = $node->nodeValue; + if (empty($content) === true) { + return ''; + } + $content = trim($content); + $content = htmlspecialchars($content, (ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401)); $content = str_replace('<em>', '*', $content); $content = str_replace('</em>', '*', $content); - echo $content.PHP_EOL; + $nodeLines = explode("\n", $content); + $lineCount = count($nodeLines); + $lines = []; - }//end printTextBlock() + for ($i = 0; $i < $lineCount; $i++) { + $currentLine = trim($nodeLines[$i]); + if ($currentLine === '') { + // The text contained a blank line. Respect this. + $lines[] = ''; + continue; + } + + // Check if the _next_ line is blank. + if (isset($nodeLines[($i + 1)]) === false + || trim($nodeLines[($i + 1)]) === '' + ) { + // Next line is blank, just add the line. + $lines[] = $currentLine; + } else { + // Ensure that line breaks are respected in markdown. + $lines[] = $currentLine.' '; + } + } + + return implode(PHP_EOL, $lines).PHP_EOL; + + }//end getFormattedTextBlock() /** @@ -122,40 +232,119 @@ protected function printTextBlock(\DOMNode $node) * * @param \DOMNode $node The DOMNode object for the code comparison block. * + * @deprecated 3.12.0 Use Markdown::getFormattedCodeComparisonBlock() instead. + * + * @codeCoverageIgnore + * * @return void */ - protected function printCodeComparisonBlock(\DOMNode $node) + protected function printCodeComparisonBlock(DOMNode $node) { - $codeBlocks = $node->getElementsByTagName('code'); - - $firstTitle = $codeBlocks->item(0)->getAttribute('title'); - $first = trim($codeBlocks->item(0)->nodeValue); - $first = str_replace("\n", "\n ", $first); - $first = str_replace('', '', $first); - $first = str_replace('', '', $first); - - $secondTitle = $codeBlocks->item(1)->getAttribute('title'); - $second = trim($codeBlocks->item(1)->nodeValue); - $second = str_replace("\n", "\n ", $second); - $second = str_replace('', '', $second); - $second = str_replace('', '', $second); - - echo ' '.PHP_EOL; - echo ' '.PHP_EOL; - echo " ".PHP_EOL; - echo " ".PHP_EOL; - echo ' '.PHP_EOL; - echo ' '.PHP_EOL; - echo ''.PHP_EOL; - echo ''.PHP_EOL; - echo ' '.PHP_EOL; - echo '
$firstTitle$secondTitle
'.PHP_EOL.PHP_EOL; - echo " $first".PHP_EOL.PHP_EOL; - echo ''.PHP_EOL.PHP_EOL; - echo " $second".PHP_EOL.PHP_EOL; - echo '
'.PHP_EOL; + trigger_error( + 'The '.__METHOD__.'() method is deprecated. Use "echo '.__CLASS__.'::getFormattedCodeComparisonBlock()" instead.', + E_USER_DEPRECATED + ); + + echo $this->getFormattedCodeComparisonBlock($node); }//end printCodeComparisonBlock() + /** + * Format a code comparison block found in a standard. + * + * @param \DOMNode $node The DOMNode object for the code comparison block. + * + * @since 3.12.0 Replaces the deprecated Markdown::printCodeComparisonBlock() method. + * + * @return string + */ + protected function getFormattedCodeComparisonBlock(DOMNode $node) + { + $codeBlocks = $node->getElementsByTagName('code'); + $firstCodeElm = $codeBlocks->item(0); + $secondCodeElm = $codeBlocks->item(1); + + if (isset($firstCodeElm, $secondCodeElm) === false) { + // Missing at least one code block. + return ''; + } + + $firstTitle = $this->formatCodeTitle($firstCodeElm); + $first = $this->formatCodeSample($firstCodeElm); + + $secondTitle = $this->formatCodeTitle($secondCodeElm); + $second = $this->formatCodeSample($secondCodeElm); + + $titleRow = ''; + if ($firstTitle !== '' || $secondTitle !== '') { + $titleRow .= ' '.PHP_EOL; + $titleRow .= " $firstTitle".PHP_EOL; + $titleRow .= " $secondTitle".PHP_EOL; + $titleRow .= ' '.PHP_EOL; + } + + $codeRow = ''; + if ($first !== '' || $second !== '') { + $codeRow .= ' '.PHP_EOL; + $codeRow .= ''.PHP_EOL.PHP_EOL; + $codeRow .= " $first".PHP_EOL.PHP_EOL; + $codeRow .= ''.PHP_EOL; + $codeRow .= ''.PHP_EOL.PHP_EOL; + $codeRow .= " $second".PHP_EOL.PHP_EOL; + $codeRow .= ''.PHP_EOL; + $codeRow .= ' '.PHP_EOL; + } + + $output = ''; + if ($titleRow !== '' || $codeRow !== '') { + $output .= ' '.PHP_EOL; + $output .= $titleRow; + $output .= $codeRow; + $output .= '
'.PHP_EOL; + } + + return $output; + + }//end getFormattedCodeComparisonBlock() + + + /** + * Retrieve a code block title and prepare it for output as HTML. + * + * @param \DOMElement $codeElm The DOMElement object for a code block. + * + * @since 3.12.0 + * + * @return string + */ + private function formatCodeTitle(DOMElement $codeElm) + { + $title = trim($codeElm->getAttribute('title')); + return str_replace(' ', '  ', $title); + + }//end formatCodeTitle() + + + /** + * Retrieve a code block contents and prepare it for output as HTML. + * + * @param \DOMElement $codeElm The DOMElement object for a code block. + * + * @since 3.12.0 + * + * @return string + */ + private function formatCodeSample(DOMElement $codeElm) + { + $code = (string) $codeElm->nodeValue; + $code = trim($code); + $code = str_replace("\n", PHP_EOL.' ', $code); + $code = str_replace(['', ''], '', $code); + + return $code; + + }//end formatCodeSample() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Generators/Text.php b/app/vendor/squizlabs/php_codesniffer/src/Generators/Text.php index 7ec95ec9c..5dae8c1ab 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Generators/Text.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Generators/Text.php @@ -5,12 +5,17 @@ * Output is designed to be displayed in a terminal and is wrapped to 100 characters. * * @author Greg Sherwood + * @author Juliette Reinders Folmer * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) + * @copyright 2024 PHPCSStandards and contributors * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ namespace PHP_CodeSniffer\Generators; +use DOMElement; +use DOMNode; + class Text extends Generator { @@ -24,18 +29,21 @@ class Text extends Generator * * @return void */ - public function processSniff(\DOMNode $doc) + public function processSniff(DOMNode $doc) { - $this->printTitle($doc); - + $content = ''; foreach ($doc->childNodes as $node) { if ($node->nodeName === 'standard') { - $this->printTextBlock($node); + $content .= $this->getFormattedTextBlock($node); } else if ($node->nodeName === 'code_comparison') { - $this->printCodeComparisonBlock($node); + $content .= $this->getFormattedCodeComparisonBlock($node); } } + if (trim($content) !== '') { + echo $this->getFormattedTitle($doc), $content; + } + }//end processSniff() @@ -46,74 +54,102 @@ public function processSniff(\DOMNode $doc) * It represents the "documentation" tag in the XML * standard file. * + * @deprecated 3.12.0 Use Text::getFormattedTitle() instead. + * + * @codeCoverageIgnore + * * @return void */ - protected function printTitle(\DOMNode $doc) + protected function printTitle(DOMNode $doc) { - $title = $this->getTitle($doc); - $standard = $this->ruleset->name; + trigger_error( + 'The '.__METHOD__.'() method is deprecated. Use "echo '.__CLASS__.'::getFormattedTitle()" instead.', + E_USER_DEPRECATED + ); - echo PHP_EOL; - echo str_repeat('-', (strlen("$standard CODING STANDARD: $title") + 4)); - echo strtoupper(PHP_EOL."| $standard CODING STANDARD: $title |".PHP_EOL); - echo str_repeat('-', (strlen("$standard CODING STANDARD: $title") + 4)); - echo PHP_EOL.PHP_EOL; + echo $this->getFormattedTitle($doc); }//end printTitle() + /** + * Format the title area for a single sniff. + * + * @param \DOMNode $doc The DOMNode object for the sniff. + * It represents the "documentation" tag in the XML + * standard file. + * + * @since 3.12.0 Replaces the deprecated Text::printTitle() method. + * + * @return string + */ + protected function getFormattedTitle(DOMNode $doc) + { + $title = $this->getTitle($doc); + $standard = $this->ruleset->name; + $displayTitle = "$standard CODING STANDARD: $title"; + $titleLength = strlen($displayTitle); + + $output = PHP_EOL; + $output .= str_repeat('-', ($titleLength + 4)); + $output .= strtoupper(PHP_EOL."| $displayTitle |".PHP_EOL); + $output .= str_repeat('-', ($titleLength + 4)); + $output .= PHP_EOL.PHP_EOL; + + return $output; + + }//end getFormattedTitle() + + /** * Print a text block found in a standard. * * @param \DOMNode $node The DOMNode object for the text block. * + * @deprecated 3.12.0 Use Text::getFormattedTextBlock() instead. + * + * @codeCoverageIgnore + * * @return void */ - protected function printTextBlock(\DOMNode $node) + protected function printTextBlock(DOMNode $node) { - $text = trim($node->nodeValue); - $text = str_replace('', '*', $text); - $text = str_replace('', '*', $text); + trigger_error( + 'The '.__METHOD__.'() method is deprecated. Use "echo '.__CLASS__.'::getFormattedTextBlock()" instead.', + E_USER_DEPRECATED + ); - $nodeLines = explode("\n", $text); - $lines = []; - - foreach ($nodeLines as $currentLine) { - $currentLine = trim($currentLine); - if ($currentLine === '') { - // The text contained a blank line. Respect this. - $lines[] = ''; - continue; - } + echo $this->getFormattedTextBlock($node); - $tempLine = ''; - $words = explode(' ', $currentLine); - - foreach ($words as $word) { - $currentLength = strlen($tempLine.$word); - if ($currentLength < 99) { - $tempLine .= $word.' '; - continue; - } - - if ($currentLength === 99 || $currentLength === 100) { - // We are already at the edge, so we are done. - $lines[] = $tempLine.$word; - $tempLine = ''; - } else { - $lines[] = rtrim($tempLine); - $tempLine = $word.' '; - } - }//end foreach - - if ($tempLine !== '') { - $lines[] = rtrim($tempLine); - } - }//end foreach + }//end printTextBlock() - echo implode(PHP_EOL, $lines).PHP_EOL.PHP_EOL; - }//end printTextBlock() + /** + * Format a text block found in a standard. + * + * @param \DOMNode $node The DOMNode object for the text block. + * + * @since 3.12.0 Replaces the deprecated Text::printTextBlock() method. + * + * @return string + */ + protected function getFormattedTextBlock(DOMNode $node) + { + $text = $node->nodeValue; + if (empty($text) === true) { + return ''; + } + + $text = trim($text); + $text = str_replace(['', ''], '*', $text); + + $nodeLines = explode("\n", $text); + $nodeLines = array_map('trim', $nodeLines); + $text = implode(PHP_EOL, $nodeLines); + + return wordwrap($text, 100, PHP_EOL).PHP_EOL.PHP_EOL; + + }//end getFormattedTextBlock() /** @@ -121,133 +157,157 @@ protected function printTextBlock(\DOMNode $node) * * @param \DOMNode $node The DOMNode object for the code comparison block. * + * @deprecated 3.12.0 Use Text::getFormattedCodeComparisonBlock() instead. + * + * @codeCoverageIgnore + * * @return void */ - protected function printCodeComparisonBlock(\DOMNode $node) + protected function printCodeComparisonBlock(DOMNode $node) { - $codeBlocks = $node->getElementsByTagName('code'); - $first = trim($codeBlocks->item(0)->nodeValue); - $firstTitle = $codeBlocks->item(0)->getAttribute('title'); - - $firstTitleLines = []; - $tempTitle = ''; - $words = explode(' ', $firstTitle); - - foreach ($words as $word) { - if (strlen($tempTitle.$word) >= 45) { - if (strlen($tempTitle.$word) === 45) { - // Adding the extra space will push us to the edge - // so we are done. - $firstTitleLines[] = $tempTitle.$word; - $tempTitle = ''; - } else if (strlen($tempTitle.$word) === 46) { - // We are already at the edge, so we are done. - $firstTitleLines[] = $tempTitle.$word; - $tempTitle = ''; - } else { - $firstTitleLines[] = $tempTitle; - $tempTitle = $word.' '; - } - } else { - $tempTitle .= $word.' '; - } - }//end foreach + trigger_error( + 'The '.__METHOD__.'() method is deprecated. Use "echo '.__CLASS__.'::getFormattedCodeComparisonBlock()" instead.', + E_USER_DEPRECATED + ); - if ($tempTitle !== '') { - $firstTitleLines[] = $tempTitle; + echo $this->getFormattedCodeComparisonBlock($node); + + }//end printCodeComparisonBlock() + + + /** + * Format a code comparison block found in a standard. + * + * @param \DOMNode $node The DOMNode object for the code comparison block. + * + * @since 3.12.0 Replaces the deprecated Text::printCodeComparisonBlock() method. + * + * @return string + */ + protected function getFormattedCodeComparisonBlock(DOMNode $node) + { + $codeBlocks = $node->getElementsByTagName('code'); + $firstCodeElm = $codeBlocks->item(0); + $secondCodeElm = $codeBlocks->item(1); + + if (isset($firstCodeElm, $secondCodeElm) === false) { + // Missing at least one code block. + return ''; } - $first = str_replace('', '', $first); - $first = str_replace('', '', $first); - $firstLines = explode("\n", $first); - - $second = trim($codeBlocks->item(1)->nodeValue); - $secondTitle = $codeBlocks->item(1)->getAttribute('title'); - - $secondTitleLines = []; - $tempTitle = ''; - $words = explode(' ', $secondTitle); - - foreach ($words as $word) { - if (strlen($tempTitle.$word) >= 45) { - if (strlen($tempTitle.$word) === 45) { - // Adding the extra space will push us to the edge - // so we are done. - $secondTitleLines[] = $tempTitle.$word; - $tempTitle = ''; - } else if (strlen($tempTitle.$word) === 46) { - // We are already at the edge, so we are done. - $secondTitleLines[] = $tempTitle.$word; - $tempTitle = ''; - } else { - $secondTitleLines[] = $tempTitle; - $tempTitle = $word.' '; - } - } else { - $tempTitle .= $word.' '; - } - }//end foreach + $firstTitleLines = $this->codeTitleToLines($firstCodeElm); + $firstLines = $this->codeToLines($firstCodeElm); + + $secondTitleLines = $this->codeTitleToLines($secondCodeElm); + $secondLines = $this->codeToLines($secondCodeElm); + + $titleRow = ''; + if ($firstTitleLines !== [] || $secondTitleLines !== []) { + $titleRow = $this->linesToTableRows($firstTitleLines, $secondTitleLines); + $titleRow .= str_repeat('-', 100).PHP_EOL; + }//end if + + $codeRow = ''; + if ($firstLines !== [] || $secondLines !== []) { + $codeRow = $this->linesToTableRows($firstLines, $secondLines); + $codeRow .= str_repeat('-', 100).PHP_EOL.PHP_EOL; + }//end if + + $output = ''; + if ($titleRow !== '' || $codeRow !== '') { + $output = str_repeat('-', 41); + $output .= ' CODE COMPARISON '; + $output .= str_repeat('-', 42).PHP_EOL; + $output .= $titleRow; + $output .= $codeRow; + } + + return $output; + + }//end getFormattedCodeComparisonBlock() - if ($tempTitle !== '') { - $secondTitleLines[] = $tempTitle; + + /** + * Retrieve a code block title and split it into lines for use in an ASCII table. + * + * @param \DOMElement $codeElm The DOMElement object for a code block. + * + * @since 3.12.0 + * + * @return array + */ + private function codeTitleToLines(DOMElement $codeElm) + { + $title = trim($codeElm->getAttribute('title')); + if ($title === '') { + return []; } - $second = str_replace('', '', $second); - $second = str_replace('', '', $second); - $secondLines = explode("\n", $second); + $title = wordwrap($title, 46, "\n"); - $maxCodeLines = max(count($firstLines), count($secondLines)); - $maxTitleLines = max(count($firstTitleLines), count($secondTitleLines)); + return explode("\n", $title); - echo str_repeat('-', 41); - echo ' CODE COMPARISON '; - echo str_repeat('-', 42).PHP_EOL; + }//end codeTitleToLines() - for ($i = 0; $i < $maxTitleLines; $i++) { - if (isset($firstTitleLines[$i]) === true) { - $firstLineText = $firstTitleLines[$i]; - } else { - $firstLineText = ''; - } - if (isset($secondTitleLines[$i]) === true) { - $secondLineText = $secondTitleLines[$i]; - } else { - $secondLineText = ''; - } + /** + * Retrieve a code block contents and split it into lines for use in an ASCII table. + * + * @param \DOMElement $codeElm The DOMElement object for a code block. + * + * @since 3.12.0 + * + * @return array + */ + private function codeToLines(DOMElement $codeElm) + { + $code = trim($codeElm->nodeValue); + if ($code === '') { + return []; + } + + $code = str_replace(['', ''], '', $code); + return explode("\n", $code); + + }//end codeToLines() - echo '| '; - echo $firstLineText.str_repeat(' ', (46 - strlen($firstLineText))); - echo ' | '; - echo $secondLineText.str_repeat(' ', (47 - strlen($secondLineText))); - echo ' |'.PHP_EOL; - }//end for - echo str_repeat('-', 100).PHP_EOL; + /** + * Transform two sets of text lines into rows for use in an ASCII table. + * + * The sets may not contains an equal amount of lines, while the resulting rows should. + * + * @param array $column1Lines Lines of text to place in column 1. + * @param array $column2Lines Lines of text to place in column 2. + * + * @return string + */ + private function linesToTableRows(array $column1Lines, array $column2Lines) + { + $maxLines = max(count($column1Lines), count($column2Lines)); - for ($i = 0; $i < $maxCodeLines; $i++) { - if (isset($firstLines[$i]) === true) { - $firstLineText = $firstLines[$i]; - } else { - $firstLineText = ''; + $rows = ''; + for ($i = 0; $i < $maxLines; $i++) { + $column1Text = ''; + if (isset($column1Lines[$i]) === true) { + $column1Text = $column1Lines[$i]; } - if (isset($secondLines[$i]) === true) { - $secondLineText = $secondLines[$i]; - } else { - $secondLineText = ''; + $column2Text = ''; + if (isset($column2Lines[$i]) === true) { + $column2Text = $column2Lines[$i]; } - echo '| '; - echo $firstLineText.str_repeat(' ', max(0, (47 - strlen($firstLineText)))); - echo '| '; - echo $secondLineText.str_repeat(' ', max(0, (48 - strlen($secondLineText)))); - echo '|'.PHP_EOL; + $rows .= '| '; + $rows .= $column1Text.str_repeat(' ', max(0, (47 - strlen($column1Text)))); + $rows .= '| '; + $rows .= $column2Text.str_repeat(' ', max(0, (48 - strlen($column2Text)))); + $rows .= '|'.PHP_EOL; }//end for - echo str_repeat('-', 100).PHP_EOL.PHP_EOL; + return $rows; - }//end printCodeComparisonBlock() + }//end linesToTableRows() }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Reporter.php b/app/vendor/squizlabs/php_codesniffer/src/Reporter.php index 3e3da3211..824031a48 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Reporter.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Reporter.php @@ -236,7 +236,7 @@ public function printReport($report) ob_end_clean(); if ($this->config->colors !== true || $reportFile !== null) { - $generatedReport = preg_replace('`\033\[[0-9;]+m`', '', $generatedReport); + $generatedReport = Common::stripColors($generatedReport); } if ($reportFile !== null) { @@ -329,7 +329,29 @@ public function cacheFileReport(File $phpcsFile) * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file that has been processed. * - * @return array + * @return array Prepared report data. + * The format of prepared data is as follows: + * ``` + * array( + * 'filename' => string The name of the current file. + * 'errors' => int The number of errors seen in the current file. + * 'warnings' => int The number of warnings seen in the current file. + * 'fixable' => int The number of fixable issues seen in the current file. + * 'messages' => array( + * int => array( + * int => array( + * int => array( + * 'message' => string The error/warning message. + * 'source' => string The full error code for the message. + * 'severity' => int The severity of the message. + * 'fixable' => bool Whether this error/warning is auto-fixable. + * 'type' => string The type of message. Either 'ERROR' or 'WARNING'. + * ) + * ) + * ) + * ) + * ) + * ``` */ public function prepareFileReport(File $phpcsFile) { @@ -342,7 +364,7 @@ public function prepareFileReport(File $phpcsFile) ]; if ($report['errors'] === 0 && $report['warnings'] === 0) { - // Prefect score! + // Perfect score! return $report; } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Reports/Cbf.php b/app/vendor/squizlabs/php_codesniffer/src/Reports/Cbf.php index b84f69f6c..9f2ba8406 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Reports/Cbf.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Reports/Cbf.php @@ -15,7 +15,7 @@ use PHP_CodeSniffer\Exceptions\DeepExitException; use PHP_CodeSniffer\Files\File; -use PHP_CodeSniffer\Util; +use PHP_CodeSniffer\Util\Timing; class Cbf implements Report { @@ -28,10 +28,11 @@ class Cbf implements Report * and FALSE if it ignored the file. Returning TRUE indicates that the file and * its data should be counted in the grand totals. * - * @param array $report Prepared report data. - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. - * @param bool $showSources Show sources? - * @param int $width Maximum allowed line width. + * @param array $report Prepared report data. + * See the {@see Report} interface for a detailed specification. + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. + * @param bool $showSources Show sources? + * @param int $width Maximum allowed line width. * * @return bool * @throws \PHP_CodeSniffer\Exceptions\DeepExitException @@ -148,7 +149,12 @@ public function generate( array_pop($lines); if (empty($lines) === true) { - echo PHP_EOL.'No fixable errors were found'.PHP_EOL; + if (($totalErrors + $totalWarnings) === 0) { + echo PHP_EOL.'No violations were found'.PHP_EOL; + } else { + echo PHP_EOL.'No fixable errors were found'.PHP_EOL; + } + return; } @@ -244,7 +250,7 @@ public function generate( echo PHP_EOL.str_repeat('-', $width).PHP_EOL.PHP_EOL; if ($toScreen === true && $interactive === false) { - Util\Timing::printRunTime(); + Timing::printRunTime(); } }//end generate() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Reports/Checkstyle.php b/app/vendor/squizlabs/php_codesniffer/src/Reports/Checkstyle.php index dc1f6cc7b..8640561fb 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Reports/Checkstyle.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Reports/Checkstyle.php @@ -11,6 +11,7 @@ use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Files\File; +use XMLWriter; class Checkstyle implements Report { @@ -23,16 +24,17 @@ class Checkstyle implements Report * and FALSE if it ignored the file. Returning TRUE indicates that the file and * its data should be counted in the grand totals. * - * @param array $report Prepared report data. - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. - * @param bool $showSources Show sources? - * @param int $width Maximum allowed line width. + * @param array $report Prepared report data. + * See the {@see Report} interface for a detailed specification. + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. + * @param bool $showSources Show sources? + * @param int $width Maximum allowed line width. * * @return bool */ public function generateFileReport($report, File $phpcsFile, $showSources=false, $width=80) { - $out = new \XMLWriter; + $out = new XMLWriter; $out->openMemory(); $out->setIndent(true); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Reports/Code.php b/app/vendor/squizlabs/php_codesniffer/src/Reports/Code.php index 238270581..18aaf1e14 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Reports/Code.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Reports/Code.php @@ -9,8 +9,10 @@ namespace PHP_CodeSniffer\Reports; +use Exception; use PHP_CodeSniffer\Files\File; -use PHP_CodeSniffer\Util; +use PHP_CodeSniffer\Util\Common; +use PHP_CodeSniffer\Util\Timing; class Code implements Report { @@ -23,10 +25,11 @@ class Code implements Report * and FALSE if it ignored the file. Returning TRUE indicates that the file and * its data should be counted in the grand totals. * - * @param array $report Prepared report data. - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. - * @param bool $showSources Show sources? - * @param int $width Maximum allowed line width. + * @param array $report Prepared report data. + * See the {@see Report} interface for a detailed specification. + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. + * @param bool $showSources Show sources? + * @param int $width Maximum allowed line width. * * @return bool */ @@ -37,7 +40,7 @@ public function generateFileReport($report, File $phpcsFile, $showSources=false, return false; } - // How many lines to show about and below the error line. + // How many lines to show above and below the error line. $surroundingLines = 2; $file = $report['filename']; @@ -52,7 +55,11 @@ public function generateFileReport($report, File $phpcsFile, $showSources=false, try { $phpcsFile->parse(); - } catch (\Exception $e) { + + // Make sure the fixer is aware of the reparsed file to prevent a race-condition + // with the Diff report also re-parsing the file. + $phpcsFile->fixer->startFile($phpcsFile); + } catch (Exception $e) { // This is a second parse, so ignore exceptions. // They would have been added to the file's error list already. } @@ -119,8 +126,8 @@ public function generateFileReport($report, File $phpcsFile, $showSources=false, // Determine the longest error message we will be showing. $maxErrorLength = 0; - foreach ($report['messages'] as $line => $lineErrors) { - foreach ($lineErrors as $column => $colErrors) { + foreach ($report['messages'] as $lineErrors) { + foreach ($lineErrors as $colErrors) { foreach ($colErrors as $error) { $length = strlen($error['message']); if ($showSources === true) { @@ -235,7 +242,7 @@ public function generateFileReport($report, File $phpcsFile, $showSources=false, $tokenContent = $token['content']; } - $tokenContent = Util\Common::prepareForOutput($tokenContent, ["\r", "\n", "\t"]); + $tokenContent = Common::prepareForOutput($tokenContent, ["\r", "\n", "\t"]); $tokenContent = str_replace("\000", ' ', $tokenContent); $underline = false; @@ -262,7 +269,7 @@ public function generateFileReport($report, File $phpcsFile, $showSources=false, echo str_repeat('-', $width).PHP_EOL; - foreach ($lineErrors as $column => $colErrors) { + foreach ($lineErrors as $colErrors) { foreach ($colErrors as $error) { $padding = ($maxLineNumLength - strlen($line)); echo 'LINE '.str_repeat(' ', $padding).$line.': '; @@ -353,7 +360,7 @@ public function generate( echo $cachedData; if ($toScreen === true && $interactive === false) { - Util\Timing::printRunTime(); + Timing::printRunTime(); } }//end generate() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Reports/Csv.php b/app/vendor/squizlabs/php_codesniffer/src/Reports/Csv.php index aef7d7e37..ed7caca38 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Reports/Csv.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Reports/Csv.php @@ -22,10 +22,11 @@ class Csv implements Report * and FALSE if it ignored the file. Returning TRUE indicates that the file and * its data should be counted in the grand totals. * - * @param array $report Prepared report data. - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. - * @param bool $showSources Show sources? - * @param int $width Maximum allowed line width. + * @param array $report Prepared report data. + * See the {@see Report} interface for a detailed specification. + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. + * @param bool $showSources Show sources? + * @param int $width Maximum allowed line width. * * @return bool */ diff --git a/app/vendor/squizlabs/php_codesniffer/src/Reports/Diff.php b/app/vendor/squizlabs/php_codesniffer/src/Reports/Diff.php index 03f7bf20d..9580b4e97 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Reports/Diff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Reports/Diff.php @@ -22,10 +22,11 @@ class Diff implements Report * and FALSE if it ignored the file. Returning TRUE indicates that the file and * its data should be counted in the grand totals. * - * @param array $report Prepared report data. - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. - * @param bool $showSources Show sources? - * @param int $width Maximum allowed line width. + * @param array $report Prepared report data. + * See the {@see Report} interface for a detailed specification. + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. + * @param bool $showSources Show sources? + * @param int $width Maximum allowed line width. * * @return bool */ diff --git a/app/vendor/squizlabs/php_codesniffer/src/Reports/Emacs.php b/app/vendor/squizlabs/php_codesniffer/src/Reports/Emacs.php index 3f0036576..076768a78 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Reports/Emacs.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Reports/Emacs.php @@ -22,10 +22,11 @@ class Emacs implements Report * and FALSE if it ignored the file. Returning TRUE indicates that the file and * its data should be counted in the grand totals. * - * @param array $report Prepared report data. - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. - * @param bool $showSources Show sources? - * @param int $width Maximum allowed line width. + * @param array $report Prepared report data. + * See the {@see Report} interface for a detailed specification. + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. + * @param bool $showSources Show sources? + * @param int $width Maximum allowed line width. * * @return bool */ diff --git a/app/vendor/squizlabs/php_codesniffer/src/Reports/Full.php b/app/vendor/squizlabs/php_codesniffer/src/Reports/Full.php index d0b01da24..9af4efaea 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Reports/Full.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Reports/Full.php @@ -10,7 +10,7 @@ namespace PHP_CodeSniffer\Reports; use PHP_CodeSniffer\Files\File; -use PHP_CodeSniffer\Util; +use PHP_CodeSniffer\Util\Timing; class Full implements Report { @@ -23,10 +23,11 @@ class Full implements Report * and FALSE if it ignored the file. Returning TRUE indicates that the file and * its data should be counted in the grand totals. * - * @param array $report Prepared report data. - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. - * @param bool $showSources Show sources? - * @param int $width Maximum allowed line width. + * @param array $report Prepared report data. + * See the {@see Report} interface for a detailed specification. + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. + * @param bool $showSources Show sources? + * @param int $width Maximum allowed line width. * * @return bool */ @@ -61,8 +62,8 @@ public function generateFileReport($report, File $phpcsFile, $showSources=false, // Make sure the report width isn't too big. $maxErrorLength = 0; - foreach ($report['messages'] as $line => $lineErrors) { - foreach ($lineErrors as $column => $colErrors) { + foreach ($report['messages'] as $lineErrors) { + foreach ($lineErrors as $colErrors) { foreach ($colErrors as $error) { // Start with the presumption of a single line error message. $length = strlen($error['message']); @@ -138,7 +139,7 @@ public function generateFileReport($report, File $phpcsFile, $showSources=false, $beforeAfterLength = strlen($beforeMsg.$afterMsg); foreach ($report['messages'] as $line => $lineErrors) { - foreach ($lineErrors as $column => $colErrors) { + foreach ($lineErrors as $colErrors) { foreach ($colErrors as $error) { $errorMsg = wordwrap( $error['message'], @@ -250,7 +251,7 @@ public function generate( echo $cachedData; if ($toScreen === true && $interactive === false) { - Util\Timing::printRunTime(); + Timing::printRunTime(); } }//end generate() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Reports/Info.php b/app/vendor/squizlabs/php_codesniffer/src/Reports/Info.php index 403905616..9f1f45aa5 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Reports/Info.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Reports/Info.php @@ -23,10 +23,11 @@ class Info implements Report * and FALSE if it ignored the file. Returning TRUE indicates that the file and * its data should be counted in the grand totals. * - * @param array $report Prepared report data. - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. - * @param bool $showSources Show sources? - * @param int $width Maximum allowed line width. + * @param array $report Prepared report data. + * See the {@see Report} interface for a detailed specification. + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. + * @param bool $showSources Show sources? + * @param int $width Maximum allowed line width. * * @return bool */ diff --git a/app/vendor/squizlabs/php_codesniffer/src/Reports/Json.php b/app/vendor/squizlabs/php_codesniffer/src/Reports/Json.php index 0b9ad34fa..67c8b5e63 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Reports/Json.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Reports/Json.php @@ -23,10 +23,11 @@ class Json implements Report * and FALSE if it ignored the file. Returning TRUE indicates that the file and * its data should be counted in the grand totals. * - * @param array $report Prepared report data. - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. - * @param bool $showSources Show sources? - * @param int $width Maximum allowed line width. + * @param array $report Prepared report data. + * See the {@see Report} interface for a detailed specification. + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. + * @param bool $showSources Show sources? + * @param int $width Maximum allowed line width. * * @return bool */ diff --git a/app/vendor/squizlabs/php_codesniffer/src/Reports/Junit.php b/app/vendor/squizlabs/php_codesniffer/src/Reports/Junit.php index 40145a717..aaeeb1774 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Reports/Junit.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Reports/Junit.php @@ -12,6 +12,7 @@ use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Files\File; +use XMLWriter; class Junit implements Report { @@ -24,16 +25,17 @@ class Junit implements Report * and FALSE if it ignored the file. Returning TRUE indicates that the file and * its data should be counted in the grand totals. * - * @param array $report Prepared report data. - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. - * @param bool $showSources Show sources? - * @param int $width Maximum allowed line width. + * @param array $report Prepared report data. + * See the {@see Report} interface for a detailed specification. + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. + * @param bool $showSources Show sources? + * @param int $width Maximum allowed line width. * * @return bool */ public function generateFileReport($report, File $phpcsFile, $showSources=false, $width=80) { - $out = new \XMLWriter; + $out = new XMLWriter; $out->openMemory(); $out->setIndent(true); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Reports/Notifysend.php b/app/vendor/squizlabs/php_codesniffer/src/Reports/Notifysend.php index 1c296958c..839d99036 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Reports/Notifysend.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Reports/Notifysend.php @@ -88,10 +88,11 @@ public function __construct() * and FALSE if it ignored the file. Returning TRUE indicates that the file and * its data should be counted in the grand totals. * - * @param array $report Prepared report data. - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. - * @param bool $showSources Show sources? - * @param int $width Maximum allowed line width. + * @param array $report Prepared report data. + * See the {@see Report} interface for a detailed specification. + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. + * @param bool $showSources Show sources? + * @param int $width Maximum allowed line width. * * @return bool */ diff --git a/app/vendor/squizlabs/php_codesniffer/src/Reports/Performance.php b/app/vendor/squizlabs/php_codesniffer/src/Reports/Performance.php index ea90d0a84..843698990 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Reports/Performance.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Reports/Performance.php @@ -24,10 +24,11 @@ class Performance implements Report * and FALSE if it ignored the file. Returning TRUE indicates that the file and * its data should be counted in the grand totals. * - * @param array $report Prepared report data. - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. - * @param bool $showSources Show sources? - * @param int $width Maximum allowed line width. + * @param array $report Prepared report data. + * See the {@see Report} interface for a detailed specification. + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. + * @param bool $showSources Show sources? + * @param int $width Maximum allowed line width. * * @return bool */ diff --git a/app/vendor/squizlabs/php_codesniffer/src/Reports/Report.php b/app/vendor/squizlabs/php_codesniffer/src/Reports/Report.php index eec5eb1d0..52d7883b5 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Reports/Report.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Reports/Report.php @@ -22,10 +22,33 @@ interface Report * and FALSE if it ignored the file. Returning TRUE indicates that the file and * its data should be counted in the grand totals. * - * @param array $report Prepared report data. - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. - * @param bool $showSources Show sources? - * @param int $width Maximum allowed line width. + * The format of the `$report` parameter the function receives is as follows: + * ``` + * array( + * 'filename' => string The name of the current file. + * 'errors' => int The number of errors seen in the current file. + * 'warnings' => int The number of warnings seen in the current file. + * 'fixable' => int The number of fixable issues seen in the current file. + * 'messages' => array( + * int => array( + * int => array( + * int => array( + * 'message' => string The error/warning message. + * 'source' => string The full error code for the message. + * 'severity' => int The severity of the message. + * 'fixable' => bool Whether this error/warning is auto-fixable. + * 'type' => string The type of message. Either 'ERROR' or 'WARNING'. + * ) + * ) + * ) + * ) + * ) + * ``` + * + * @param array $report Prepared report data. + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. + * @param bool $showSources Show sources? + * @param int $width Maximum allowed line width. * * @return bool */ diff --git a/app/vendor/squizlabs/php_codesniffer/src/Reports/Source.php b/app/vendor/squizlabs/php_codesniffer/src/Reports/Source.php index 6aa891a4b..deedb3ebd 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Reports/Source.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Reports/Source.php @@ -23,10 +23,11 @@ class Source implements Report * and FALSE if it ignored the file. Returning TRUE indicates that the file and * its data should be counted in the grand totals. * - * @param array $report Prepared report data. - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. - * @param bool $showSources Show sources? - * @param int $width Maximum allowed line width. + * @param array $report Prepared report data. + * See the {@see Report} interface for a detailed specification. + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. + * @param bool $showSources Show sources? + * @param int $width Maximum allowed line width. * * @return bool */ @@ -39,8 +40,8 @@ public function generateFileReport($report, File $phpcsFile, $showSources=false, $sources = []; - foreach ($report['messages'] as $line => $lineErrors) { - foreach ($lineErrors as $column => $colErrors) { + foreach ($report['messages'] as $lineErrors) { + foreach ($lineErrors as $colErrors) { foreach ($colErrors as $error) { $src = $error['source']; if (isset($sources[$src]) === false) { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Reports/Summary.php b/app/vendor/squizlabs/php_codesniffer/src/Reports/Summary.php index d2927a1c3..165ad64b0 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Reports/Summary.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Reports/Summary.php @@ -10,7 +10,7 @@ namespace PHP_CodeSniffer\Reports; use PHP_CodeSniffer\Files\File; -use PHP_CodeSniffer\Util; +use PHP_CodeSniffer\Util\Timing; class Summary implements Report { @@ -23,10 +23,11 @@ class Summary implements Report * and FALSE if it ignored the file. Returning TRUE indicates that the file and * its data should be counted in the grand totals. * - * @param array $report Prepared report data. - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. - * @param bool $showSources Show sources? - * @param int $width Maximum allowed line width. + * @param array $report Prepared report data. + * See the {@see Report} interface for a detailed specification. + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. + * @param bool $showSources Show sources? + * @param int $width Maximum allowed line width. * * @return bool */ @@ -174,7 +175,7 @@ function ($keyA, $keyB) { echo PHP_EOL.str_repeat('-', $width).PHP_EOL.PHP_EOL; if ($toScreen === true && $interactive === false) { - Util\Timing::printRunTime(); + Timing::printRunTime(); } }//end generate() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Reports/VersionControl.php b/app/vendor/squizlabs/php_codesniffer/src/Reports/VersionControl.php index e3ad74b84..296846c7d 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Reports/VersionControl.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Reports/VersionControl.php @@ -31,10 +31,11 @@ abstract class VersionControl implements Report * and FALSE if it ignored the file. Returning TRUE indicates that the file and * its data should be counted in the grand totals. * - * @param array $report Prepared report data. - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. - * @param bool $showSources Show sources? - * @param int $width Maximum allowed line width. + * @param array $report Prepared report data. + * See the {@see Report} interface for a detailed specification. + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. + * @param bool $showSources Show sources? + * @param int $width Maximum allowed line width. * * @return bool */ @@ -65,7 +66,7 @@ public function generateFileReport($report, File $phpcsFile, $showSources=false, $praiseCache[$author]['bad']++; - foreach ($lineErrors as $column => $colErrors) { + foreach ($lineErrors as $colErrors) { foreach ($colErrors as $error) { $authorCache[$author]++; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Reports/Xml.php b/app/vendor/squizlabs/php_codesniffer/src/Reports/Xml.php index dc25bba3f..68276d80d 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Reports/Xml.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Reports/Xml.php @@ -11,6 +11,7 @@ use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Files\File; +use XMLWriter; class Xml implements Report { @@ -23,16 +24,17 @@ class Xml implements Report * and FALSE if it ignored the file. Returning TRUE indicates that the file and * its data should be counted in the grand totals. * - * @param array $report Prepared report data. - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. - * @param bool $showSources Show sources? - * @param int $width Maximum allowed line width. + * @param array $report Prepared report data. + * See the {@see Report} interface for a detailed specification. + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being reported on. + * @param bool $showSources Show sources? + * @param int $width Maximum allowed line width. * * @return bool */ public function generateFileReport($report, File $phpcsFile, $showSources=false, $width=80) { - $out = new \XMLWriter; + $out = new XMLWriter; $out->openMemory(); $out->setIndent(true); $out->setIndentString(' '); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Ruleset.php b/app/vendor/squizlabs/php_codesniffer/src/Ruleset.php index b99d484fe..d1ef2a4d7 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Ruleset.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Ruleset.php @@ -13,7 +13,12 @@ use PHP_CodeSniffer\Exceptions\RuntimeException; use PHP_CodeSniffer\Sniffs\DeprecatedSniff; -use PHP_CodeSniffer\Util; +use PHP_CodeSniffer\Util\Common; +use PHP_CodeSniffer\Util\MessageCollector; +use PHP_CodeSniffer\Util\Standards; +use RecursiveDirectoryIterator; +use RecursiveIteratorIterator; +use ReflectionClass; use stdClass; class Ruleset @@ -127,6 +132,20 @@ class Ruleset */ private $deprecatedSniffs = []; + /** + * Message collector object. + * + * User-facing messages should be collected via this object for display once the ruleset processing has finished. + * + * The following type of errors should *NOT* be collected, but should still throw their own `RuntimeException`: + * - Errors which could cause other (uncollectable) errors further into the ruleset processing, like a missing autoload file. + * - Errors which are directly aimed at and only intended for sniff developers or integrators + * (in contrast to ruleset maintainers or end-users). + * + * @var \PHP_CodeSniffer\Util\MessageCollector + */ + private $msgCache; + /** * Initialise the ruleset that the run will use. @@ -134,24 +153,25 @@ class Ruleset * @param \PHP_CodeSniffer\Config $config The config data for the run. * * @return void - * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If no sniffs were registered. + * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If blocking errors were encountered when processing the ruleset. */ public function __construct(Config $config) { - $this->config = $config; - $restrictions = $config->sniffs; - $exclusions = $config->exclude; - $sniffs = []; + $this->config = $config; + $restrictions = $config->sniffs; + $exclusions = $config->exclude; + $sniffs = []; + $this->msgCache = new MessageCollector(); $standardPaths = []; foreach ($config->standards as $standard) { - $installed = Util\Standards::getInstalledStandardPath($standard); + $installed = Standards::getInstalledStandardPath($standard); if ($installed === null) { - $standard = Util\Common::realpath($standard); + $standard = Common::realpath($standard); if (is_dir($standard) === true - && is_file(Util\Common::realpath($standard.DIRECTORY_SEPARATOR.'ruleset.xml')) === true + && is_file(Common::realpath($standard.DIRECTORY_SEPARATOR.'ruleset.xml')) === true ) { - $standard = Util\Common::realpath($standard.DIRECTORY_SEPARATOR.'ruleset.xml'); + $standard = Common::realpath($standard.DIRECTORY_SEPARATOR.'ruleset.xml'); } } else { $standard = $installed; @@ -182,11 +202,11 @@ public function __construct(Config $config) if (defined('PHP_CODESNIFFER_IN_TESTS') === true && empty($restrictions) === false) { // In unit tests, only register the sniffs that the test wants and not the entire standard. - try { - foreach ($restrictions as $restriction) { - $sniffs = array_merge($sniffs, $this->expandRulesetReference($restriction, dirname($standard))); - } - } catch (RuntimeException $e) { + foreach ($restrictions as $restriction) { + $sniffs = array_merge($sniffs, $this->expandRulesetReference($restriction, dirname($standard))); + } + + if (empty($sniffs) === true) { // Sniff reference could not be expanded, which probably means this // is an installed standard. Let the unit test system take care of // setting the correct sniff for testing. @@ -235,9 +255,11 @@ public function __construct(Config $config) } if ($numSniffs === 0) { - throw new RuntimeException('No sniffs were registered'); + $this->msgCache->add('No sniffs were registered.', MessageCollector::ERROR); } + $this->displayCachedMessages(); + }//end __construct() @@ -310,7 +332,7 @@ public function explain() }//end foreach if (count($this->deprecatedSniffs) > 0) { - echo PHP_EOL.'* Sniffs marked with an asterix are deprecated.'.PHP_EOL; + echo PHP_EOL.'* Sniffs marked with an asterisk are deprecated.'.PHP_EOL; } }//end explain() @@ -362,7 +384,7 @@ public function showSniffDeprecations() $messages = []; $messageTemplate = 'This sniff has been deprecated since %s and will be removed in %s. %s'; - $errorTemplate = 'The %s::%s() method must return a %sstring, received %s'; + $errorTemplate = 'ERROR: The %s::%s() method must return a %sstring, received %s'; foreach ($this->deprecatedSniffs as $sniffCode => $className) { if (isset($this->sniffs[$className]) === false) { @@ -410,11 +432,7 @@ public function showSniffDeprecations() $sniffCode = substr($sniffCode, 0, ($maxMessageWidth - 3)).'...'; } - $message = '- '.$sniffCode.PHP_EOL; - if ($this->config->colors === true) { - $message = '- '."\033[36m".$sniffCode."\033[0m".PHP_EOL; - } - + $message = '- '."\033[36m".$sniffCode."\033[0m".PHP_EOL; $maxActualWidth = max($maxActualWidth, strlen($sniffCode)); // Normalize new line characters in custom message. @@ -447,8 +465,13 @@ public function showSniffDeprecations() echo $summaryLine.PHP_EOL; } + $messages = implode(PHP_EOL, $messages); + if ($this->config->colors === false) { + $messages = Common::stripColors($messages); + } + echo str_repeat('-', min(($maxActualWidth + 4), $reportWidth)).PHP_EOL; - echo implode(PHP_EOL, $messages); + echo $messages; $closer = wordwrap('Deprecated sniffs are still run, but will stop working at some point in the future.', $reportWidth, PHP_EOL); echo PHP_EOL.PHP_EOL.$closer.PHP_EOL.PHP_EOL; @@ -456,6 +479,35 @@ public function showSniffDeprecations() }//end showSniffDeprecations() + /** + * Print any notices encountered while processing the ruleset(s). + * + * Note: these messages aren't shown at the time they are encountered to avoid "one error hiding behind another". + * This way the (end-)user gets to see all of them in one go. + * + * @return void + * + * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If blocking errors were encountered. + */ + private function displayCachedMessages() + { + // Don't show deprecations/notices/warnings in quiet mode, in explain mode + // or when the documentation is being shown. + // Documentation and explain will call the Ruleset multiple times which + // would lead to duplicate display of the messages. + if ($this->msgCache->containsBlockingErrors() === false + && ($this->config->quiet === true + || $this->config->explain === true + || $this->config->generator !== null) + ) { + return; + } + + $this->msgCache->display(); + + }//end displayCachedMessages() + + /** * Processes a single ruleset and returns a list of the sniffs it represents. * @@ -472,16 +524,16 @@ public function showSniffDeprecations() */ public function processRuleset($rulesetPath, $depth=0) { - $rulesetPath = Util\Common::realpath($rulesetPath); + $rulesetPath = Common::realpath($rulesetPath); if (PHP_CODESNIFFER_VERBOSITY > 1) { echo str_repeat("\t", $depth); - echo 'Processing ruleset '.Util\Common::stripBasepath($rulesetPath, $this->config->basepath).PHP_EOL; + echo 'Processing ruleset '.Common::stripBasepath($rulesetPath, $this->config->basepath).PHP_EOL; } libxml_use_internal_errors(true); $ruleset = simplexml_load_string(file_get_contents($rulesetPath)); if ($ruleset === false) { - $errorMsg = "Ruleset $rulesetPath is not valid".PHP_EOL; + $errorMsg = "ERROR: Ruleset $rulesetPath is not valid".PHP_EOL; $errors = libxml_get_errors(); foreach ($errors as $error) { $errorMsg .= '- On line '.$error->line.', column '.$error->column.': '.$error->message; @@ -505,7 +557,7 @@ public function processRuleset($rulesetPath, $depth=0) if (is_dir($sniffDir) === true) { if (PHP_CODESNIFFER_VERBOSITY > 1) { echo str_repeat("\t", $depth); - echo "\tAdding sniff files from ".Util\Common::stripBasepath($sniffDir, $this->config->basepath).' directory'.PHP_EOL; + echo "\tAdding sniff files from ".Common::stripBasepath($sniffDir, $this->config->basepath).' directory'.PHP_EOL; } $ownSniffs = $this->expandSniffDirectory($sniffDir, $depth); @@ -520,12 +572,12 @@ public function processRuleset($rulesetPath, $depth=0) $autoloadPath = (string) $autoload; // Try relative autoload paths first. - $relativePath = Util\Common::realPath(dirname($rulesetPath).DIRECTORY_SEPARATOR.$autoloadPath); + $relativePath = Common::realpath(dirname($rulesetPath).DIRECTORY_SEPARATOR.$autoloadPath); if ($relativePath !== false && is_file($relativePath) === true) { $autoloadPath = $relativePath; } else if (is_file($autoloadPath) === false) { - throw new RuntimeException('The specified autoload file "'.$autoload.'" does not exist'); + throw new RuntimeException('ERROR: The specified autoload file "'.$autoload.'" does not exist'); } include_once $autoloadPath; @@ -710,7 +762,7 @@ public function processRuleset($rulesetPath, $depth=0) // Change the directory so all relative paths are worked // out based on the location of the ruleset instead of // the location of the user. - $inPhar = Util\Common::isPharFile($rulesetDir); + $inPhar = Common::isPharFile($rulesetDir); if ($inPhar === false) { $currentDir = getcwd(); chdir($rulesetDir); @@ -757,7 +809,7 @@ public function processRuleset($rulesetPath, $depth=0) if (in_array($sniff, $excludedSniffs, true) === true) { continue; } else { - $files[] = Util\Common::realpath($sniff); + $files[] = Common::realpath($sniff); } } @@ -779,8 +831,8 @@ private function expandSniffDirectory($directory, $depth=0) { $sniffs = []; - $rdi = new \RecursiveDirectoryIterator($directory, \RecursiveDirectoryIterator::FOLLOW_SYMLINKS); - $di = new \RecursiveIteratorIterator($rdi, 0, \RecursiveIteratorIterator::CATCH_GET_CHILD); + $rdi = new RecursiveDirectoryIterator($directory, RecursiveDirectoryIterator::FOLLOW_SYMLINKS); + $di = new RecursiveIteratorIterator($rdi, 0, RecursiveIteratorIterator::CATCH_GET_CHILD); $dirLen = strlen($directory); @@ -815,7 +867,7 @@ private function expandSniffDirectory($directory, $depth=0) if (PHP_CODESNIFFER_VERBOSITY > 1) { echo str_repeat("\t", $depth); - echo "\t\t=> ".Util\Common::stripBasepath($path, $this->config->basepath).PHP_EOL; + echo "\t\t=> ".Common::stripBasepath($path, $this->config->basepath).PHP_EOL; } $sniffs[] = $path; @@ -840,6 +892,13 @@ private function expandSniffDirectory($directory, $depth=0) */ private function expandRulesetReference($ref, $rulesetDir, $depth=0) { + // Naming an (external) standard "Internal" is deprecated. + if (strtolower($ref) === 'internal') { + $message = 'The name "Internal" is reserved for internal use. A PHP_CodeSniffer standard should not be called "Internal".'.PHP_EOL; + $message .= 'Contact the maintainer of the standard to fix this.'; + $this->msgCache->add($message, MessageCollector::DEPRECATED); + } + // Ignore internal sniffs codes as they are used to only // hide and change internal messages. if (substr($ref, 0, 9) === 'Internal.') { @@ -856,12 +915,12 @@ private function expandRulesetReference($ref, $rulesetDir, $depth=0) // to absolute paths. If this fails, let the reference run through // the normal checks and have it fail as normal. if (substr($ref, 0, 1) === '.') { - $realpath = Util\Common::realpath($rulesetDir.'/'.$ref); + $realpath = Common::realpath($rulesetDir.'/'.$ref); if ($realpath !== false) { $ref = $realpath; if (PHP_CODESNIFFER_VERBOSITY > 1) { echo str_repeat("\t", $depth); - echo "\t\t=> ".Util\Common::stripBasepath($ref, $this->config->basepath).PHP_EOL; + echo "\t\t=> ".Common::stripBasepath($ref, $this->config->basepath).PHP_EOL; } } } @@ -869,12 +928,12 @@ private function expandRulesetReference($ref, $rulesetDir, $depth=0) // As sniffs can't begin with a tilde, assume references in // this format are relative to the user's home directory. if (substr($ref, 0, 2) === '~/') { - $realpath = Util\Common::realpath($ref); + $realpath = Common::realpath($ref); if ($realpath !== false) { $ref = $realpath; if (PHP_CODESNIFFER_VERBOSITY > 1) { echo str_repeat("\t", $depth); - echo "\t\t=> ".Util\Common::stripBasepath($ref, $this->config->basepath).PHP_EOL; + echo "\t\t=> ".Common::stripBasepath($ref, $this->config->basepath).PHP_EOL; } } } @@ -887,8 +946,8 @@ private function expandRulesetReference($ref, $rulesetDir, $depth=0) } } else { // See if this is a whole standard being referenced. - $path = Util\Standards::getInstalledStandardPath($ref); - if ($path !== null && Util\Common::isPharFile($path) === true && strpos($path, 'ruleset.xml') === false) { + $path = Standards::getInstalledStandardPath($ref); + if ($path !== null && Common::isPharFile($path) === true && strpos($path, 'ruleset.xml') === false) { // If the ruleset exists inside the phar file, use it. if (file_exists($path.DIRECTORY_SEPARATOR.'ruleset.xml') === true) { $path .= DIRECTORY_SEPARATOR.'ruleset.xml'; @@ -901,7 +960,7 @@ private function expandRulesetReference($ref, $rulesetDir, $depth=0) $ref = $path; if (PHP_CODESNIFFER_VERBOSITY > 1) { echo str_repeat("\t", $depth); - echo "\t\t=> ".Util\Common::stripBasepath($ref, $this->config->basepath).PHP_EOL; + echo "\t\t=> ".Common::stripBasepath($ref, $this->config->basepath).PHP_EOL; } } else if (is_dir($ref) === false) { // Work out the sniff path. @@ -925,16 +984,16 @@ private function expandRulesetReference($ref, $rulesetDir, $depth=0) } $newRef = false; - $stdPath = Util\Standards::getInstalledStandardPath($stdName); + $stdPath = Standards::getInstalledStandardPath($stdName); if ($stdPath !== null && $path !== '') { - if (Util\Common::isPharFile($stdPath) === true + if (Common::isPharFile($stdPath) === true && strpos($stdPath, 'ruleset.xml') === false ) { // Phar files can only return the directory, // since ruleset can be omitted if building one standard. - $newRef = Util\Common::realpath($stdPath.$path); + $newRef = Common::realpath($stdPath.$path); } else { - $newRef = Util\Common::realpath(dirname($stdPath).$path); + $newRef = Common::realpath(dirname($stdPath).$path); } } @@ -949,7 +1008,7 @@ private function expandRulesetReference($ref, $rulesetDir, $depth=0) continue; } - $newRef = Util\Common::realpath($dir.$path); + $newRef = Common::realpath($dir.$path); if ($newRef !== false) { $ref = $newRef; @@ -961,7 +1020,7 @@ private function expandRulesetReference($ref, $rulesetDir, $depth=0) if (PHP_CODESNIFFER_VERBOSITY > 1) { echo str_repeat("\t", $depth); - echo "\t\t=> ".Util\Common::stripBasepath($ref, $this->config->basepath).PHP_EOL; + echo "\t\t=> ".Common::stripBasepath($ref, $this->config->basepath).PHP_EOL; } }//end if }//end if @@ -988,8 +1047,8 @@ private function expandRulesetReference($ref, $rulesetDir, $depth=0) } } else { if (is_file($ref) === false) { - $error = "Referenced sniff \"$ref\" does not exist"; - throw new RuntimeException($error); + $this->msgCache->add("Referenced sniff \"$ref\" does not exist.", MessageCollector::ERROR); + return []; } if (substr($ref, -9) === 'Sniff.php') { @@ -1078,18 +1137,19 @@ private function processRule($rule, $newSniffs, $depth=0) $type = strtolower((string) $rule->type); if ($type !== 'error' && $type !== 'warning') { - throw new RuntimeException("Message type \"$type\" is invalid; must be \"error\" or \"warning\""); - } + $message = "Message type \"$type\" for \"$code\" is invalid; must be \"error\" or \"warning\"."; + $this->msgCache->add($message, MessageCollector::ERROR); + } else { + $this->ruleset[$code]['type'] = $type; + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo str_repeat("\t", $depth); + echo "\t\t=> message type set to ".(string) $rule->type; + if ($code !== $ref) { + echo " for $code"; + } - $this->ruleset[$code]['type'] = $type; - if (PHP_CODESNIFFER_VERBOSITY > 1) { - echo str_repeat("\t", $depth); - echo "\t\t=> message type set to ".(string) $rule->type; - if ($code !== $ref) { - echo " for $code"; + echo PHP_EOL; } - - echo PHP_EOL; } }//end if @@ -1166,15 +1226,24 @@ private function processRule($rule, $newSniffs, $depth=0) } $printValue = rtrim($printValue, ','); - } else { + } else if (isset($prop['value']) === true) { + $message = 'Passing an array of values to a property using a comma-separated string'.PHP_EOL; + $message .= 'was deprecated in PHP_CodeSniffer 3.3.0. Support will be removed in PHPCS 4.0.0.'.PHP_EOL; + $message .= "The deprecated syntax was used for property \"$name\"".PHP_EOL; + $message .= "for sniff \"$code\".".PHP_EOL; + $message .= 'Pass array values via nodes instead.'; + $this->msgCache->add($message, MessageCollector::DEPRECATED); + $value = (string) $prop['value']; $printValue = $value; - foreach (explode(',', $value) as $val) { - list($k, $v) = explode('=>', $val.'=>'); - if ($v !== '') { - $values[trim($k)] = trim($v); - } else { - $values[] = trim($k); + if ($value !== '') { + foreach (explode(',', $value) as $val) { + list($k, $v) = explode('=>', $val.'=>'); + if ($v !== '') { + $values[trim($k)] = trim($v); + } else { + $values[] = trim($k); + } } } }//end if @@ -1330,7 +1399,7 @@ public function registerSniffs($files, $restrictions, $exclusions) } $className = Autoload::loadFile($file); - $compareName = Util\Common::cleanSniffClass($className); + $compareName = Common::cleanSniffClass($className); // If they have specified a list of sniffs to restrict to, check // to see if this sniff is allowed. @@ -1349,11 +1418,34 @@ public function registerSniffs($files, $restrictions, $exclusions) } // Skip abstract classes. - $reflection = new \ReflectionClass($className); + $reflection = new ReflectionClass($className); if ($reflection->isAbstract() === true) { continue; } + if ($reflection->implementsInterface('PHP_CodeSniffer\\Sniffs\\Sniff') === false) { + $message = 'All sniffs must implement the PHP_CodeSniffer\\Sniffs\\Sniff interface.'.PHP_EOL; + $message .= "Interface not implemented for sniff $className.".PHP_EOL; + $message .= 'Contact the sniff author to fix the sniff.'; + $this->msgCache->add($message, MessageCollector::DEPRECATED); + + // Skip classes which don't implement the register() or process() methods. + if (method_exists($className, 'register') === false + || method_exists($className, 'process') === false + ) { + $errorMsg = 'Sniff class %s is missing required method %s().'; + if (method_exists($className, 'register') === false) { + $this->msgCache->add(sprintf($errorMsg, $className, 'register'), MessageCollector::ERROR); + } + + if (method_exists($className, 'process') === false) { + $this->msgCache->add(sprintf($errorMsg, $className, 'process'), MessageCollector::ERROR); + } + + continue; + } + }//end if + $listeners[$className] = $className; if (PHP_CODESNIFFER_VERBOSITY > 2) { @@ -1381,10 +1473,25 @@ public function populateTokenListeners() $this->sniffs[$sniffClass] = null; $this->sniffs[$sniffClass] = new $sniffClass(); - $sniffCode = Util\Common::getSniffCode($sniffClass); + $sniffCode = Common::getSniffCode($sniffClass); + + if (substr($sniffCode, 0, 1) === '.' + || substr($sniffCode, -1) === '.' + || strpos($sniffCode, '..') !== false + || preg_match('`(^|\.)Sniffs\.`', $sniffCode) === 1 + || preg_match('`[^\s\.-]+\\\\Sniffs\\\\[^\s\.-]+\\\\[^\s\.-]+Sniff`', $sniffClass) !== 1 + ) { + $message = "The sniff $sniffClass does not comply with the PHP_CodeSniffer naming conventions."; + $message .= ' This will no longer be supported in PHPCS 4.0.'.PHP_EOL; + $message .= 'Contact the sniff author to fix the sniff.'; + $this->msgCache->add($message, MessageCollector::DEPRECATED); + } + $this->sniffCodes[$sniffCode] = $sniffClass; + $isDeprecated = false; if ($this->sniffs[$sniffClass] instanceof DeprecatedSniff) { + $isDeprecated = true; $this->deprecatedSniffs[$sniffCode] = $sniffClass; } @@ -1397,6 +1504,24 @@ public function populateTokenListeners() $tokenizers = []; $vars = get_class_vars($sniffClass); + if (empty($vars['supportedTokenizers']) === false + && $isDeprecated === false + && in_array('PHP', $vars['supportedTokenizers'], true) === false + ) { + if (in_array('CSS', $vars['supportedTokenizers'], true) === true + || in_array('JS', $vars['supportedTokenizers'], true) === true + ) { + $message = 'Scanning CSS/JS files is deprecated and support will be removed in PHP_CodeSniffer 4.0.'.PHP_EOL; + } else { + // Just in case someone has an integration with a custom tokenizer. + $message = 'Support for custom tokenizers will be removed in PHP_CodeSniffer 4.0.'.PHP_EOL; + } + + $message .= 'The %s sniff is listening for %s.'; + $message = sprintf($message, $sniffCode, implode(', ', $vars['supportedTokenizers'])); + $this->msgCache->add($message, MessageCollector::DEPRECATED); + } + if (isset($vars['supportedTokenizers']) === true) { foreach ($vars['supportedTokenizers'] as $tokenizer) { $tokenizers[$tokenizer] = $tokenizer; @@ -1407,8 +1532,12 @@ public function populateTokenListeners() $tokens = $this->sniffs[$sniffClass]->register(); if (is_array($tokens) === false) { - $msg = "Sniff $sniffClass register() method must return an array"; - throw new RuntimeException($msg); + $msg = "The sniff {$sniffClass}::register() method must return an array."; + $this->msgCache->add($msg, MessageCollector::ERROR); + + // Unregister the sniff. + unset($this->sniffs[$sniffClass], $this->sniffCodes[$sniffCode], $this->deprecatedSniffs[$sniffCode]); + continue; } $ignorePatterns = []; @@ -1518,9 +1647,9 @@ public function setSniffProperty($sniffClass, $name, $settings) if ($isSettable === false) { if ($settings['scope'] === 'sniff') { - $notice = "Ruleset invalid. Property \"$propertyName\" does not exist on sniff "; - $notice .= array_search($sniffClass, $this->sniffCodes, true); - throw new RuntimeException($notice); + $notice = "Property \"$propertyName\" does not exist on sniff "; + $notice .= array_search($sniffClass, $this->sniffCodes, true).'.'; + $this->msgCache->add($notice, MessageCollector::ERROR); } return; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Runner.php b/app/vendor/squizlabs/php_codesniffer/src/Runner.php index 57cfb0325..d527ea575 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Runner.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Runner.php @@ -12,6 +12,8 @@ namespace PHP_CodeSniffer; +use Exception; +use InvalidArgumentException; use PHP_CodeSniffer\Exceptions\DeepExitException; use PHP_CodeSniffer\Exceptions\RuntimeException; use PHP_CodeSniffer\Files\DummyFile; @@ -20,6 +22,8 @@ use PHP_CodeSniffer\Util\Cache; use PHP_CodeSniffer\Util\Common; use PHP_CodeSniffer\Util\Standards; +use PHP_CodeSniffer\Util\Timing; +use PHP_CodeSniffer\Util\Tokens; class Runner { @@ -56,7 +60,7 @@ public function runPHPCS() $this->registerOutOfMemoryShutdownMessage('phpcs'); try { - Util\Timing::startTiming(); + Timing::startTiming(); Runner::checkRequirements(); if (defined('PHP_CODESNIFFER_CBF') === false) { @@ -127,7 +131,7 @@ public function runPHPCS() && ($toScreen === false || (($this->reporter->totalErrors + $this->reporter->totalWarnings) === 0 && $this->config->showProgress === true)) ) { - Util\Timing::printRunTime(); + Timing::printRunTime(); } } catch (DeepExitException $e) { echo $e->getMessage(); @@ -162,7 +166,7 @@ public function runPHPCBF() } try { - Util\Timing::startTiming(); + Timing::startTiming(); Runner::checkRequirements(); // Creating the Config object populates it with all required settings @@ -213,7 +217,7 @@ public function runPHPCBF() $this->reporter->printReports(); echo PHP_EOL; - Util\Timing::printRunTime(); + Timing::printRunTime(); } catch (DeepExitException $e) { echo $e->getMessage(); return $e->getCode(); @@ -310,12 +314,12 @@ public function init() // Check that the standards are valid. foreach ($this->config->standards as $standard) { - if (Util\Standards::isInstalledStandard($standard) === false) { + if (Standards::isInstalledStandard($standard) === false) { // They didn't select a valid coding standard, so help them // out by letting them know which standards are installed. $error = 'ERROR: the "'.$standard.'" coding standard is not installed. '; ob_start(); - Util\Standards::printInstalledStandards(); + Standards::printInstalledStandards(); $error .= ob_get_contents(); ob_end_clean(); throw new DeepExitException($error, 3); @@ -330,11 +334,11 @@ public function init() // Create this class so it is autoloaded and sets up a bunch // of PHP_CodeSniffer-specific token type constants. - $tokens = new Util\Tokens(); + new Tokens(); // Allow autoloading of custom files inside installed standards. $installedStandards = Standards::getInstalledStandardDetails(); - foreach ($installedStandards as $name => $details) { + foreach ($installedStandards as $details) { Autoload::addSearchPath($details['path'], $details['namespace']); } @@ -347,7 +351,7 @@ public function init() $this->ruleset->showSniffDeprecations(); } } catch (RuntimeException $e) { - $error = 'ERROR: '.$e->getMessage().PHP_EOL.PHP_EOL; + $error = rtrim($e->getMessage(), "\r\n").PHP_EOL.PHP_EOL; $error .= $this->config->printShortUsage(true); throw new DeepExitException($error, 3); } @@ -662,7 +666,7 @@ public function processFile($file) echo " ($errors errors, $warnings warnings)".PHP_EOL; } } - } catch (\Exception $e) { + } catch (Exception $e) { $error = 'An error occurred during processing; checking has been aborted. The error message was: '.$e->getMessage(); // Determine which sniff caused the error. @@ -685,16 +689,23 @@ public function processFile($file) } if (empty($sniffStack) === false) { - if (empty($nextStack) === false - && isset($nextStack['class']) === true - && substr($nextStack['class'], -5) === 'Sniff' - ) { - $sniffCode = Common::getSniffCode($nextStack['class']); - } else { + $sniffCode = ''; + try { + if (empty($nextStack) === false + && isset($nextStack['class']) === true + && substr($nextStack['class'], -5) === 'Sniff' + ) { + $sniffCode = 'the '.Common::getSniffCode($nextStack['class']).' sniff'; + } + } catch (InvalidArgumentException $e) { + // Sniff code could not be determined. This may be an abstract sniff class. + } + + if ($sniffCode === '') { $sniffCode = substr(strrchr(str_replace('\\', '/', $sniffStack['file']), '/'), 1); } - $error .= sprintf(PHP_EOL.'The error originated in the %s sniff on line %s.', $sniffCode, $sniffStack['line']); + $error .= sprintf(PHP_EOL.'The error originated in %s on line %s.', $sniffCode, $sniffStack['line']); } $file->addErrorOnLine($error, 1, 'Internal.Exception'); @@ -845,9 +856,14 @@ public function printProgress(File $file, $numFiles, $numProcessed) return; } + $showColors = $this->config->colors; + $colorOpen = ''; + $progressDot = '.'; + $colorClose = ''; + // Show progress information. if ($file->ignored === true) { - echo 'S'; + $progressDot = 'S'; } else { $errors = $file->getErrorCount(); $warnings = $file->getWarningCount(); @@ -859,27 +875,19 @@ public function printProgress(File $file, $numFiles, $numProcessed) // Files with unfixable errors or warnings are E (red). // Files with no errors or warnings are . (black). if ($fixable > 0) { - if ($this->config->colors === true) { - echo "\033[31m"; - } - - echo 'E'; + $progressDot = 'E'; - if ($this->config->colors === true) { - echo "\033[0m"; + if ($showColors === true) { + $colorOpen = "\033[31m"; + $colorClose = "\033[0m"; } } else if ($fixed > 0) { - if ($this->config->colors === true) { - echo "\033[32m"; - } - - echo 'F'; + $progressDot = 'F'; - if ($this->config->colors === true) { - echo "\033[0m"; + if ($showColors === true) { + $colorOpen = "\033[32m"; + $colorClose = "\033[0m"; } - } else { - echo '.'; }//end if } else { // Files with errors are E (red). @@ -888,39 +896,35 @@ public function printProgress(File $file, $numFiles, $numProcessed) // Files with fixable warnings are W (green). // Files with no errors or warnings are . (black). if ($errors > 0) { - if ($this->config->colors === true) { + $progressDot = 'E'; + + if ($showColors === true) { if ($fixable > 0) { - echo "\033[32m"; + $colorOpen = "\033[32m"; } else { - echo "\033[31m"; + $colorOpen = "\033[31m"; } - } - echo 'E'; - - if ($this->config->colors === true) { - echo "\033[0m"; + $colorClose = "\033[0m"; } } else if ($warnings > 0) { - if ($this->config->colors === true) { + $progressDot = 'W'; + + if ($showColors === true) { if ($fixable > 0) { - echo "\033[32m"; + $colorOpen = "\033[32m"; } else { - echo "\033[33m"; + $colorOpen = "\033[33m"; } - } - - echo 'W'; - if ($this->config->colors === true) { - echo "\033[0m"; + $colorClose = "\033[0m"; } - } else { - echo '.'; }//end if }//end if }//end if + echo $colorOpen.$progressDot.$colorClose; + $numPerLine = 60; if ($numProcessed !== $numFiles && ($numProcessed % $numPerLine) !== 0) { return; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Sniffs/AbstractPatternSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Sniffs/AbstractPatternSniff.php index 86dc10d40..d9528dccf 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Sniffs/AbstractPatternSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Sniffs/AbstractPatternSniff.php @@ -9,10 +9,10 @@ namespace PHP_CodeSniffer\Sniffs; +use PHP_CodeSniffer\Exceptions\RuntimeException; use PHP_CodeSniffer\Files\File; -use PHP_CodeSniffer\Util\Tokens; use PHP_CodeSniffer\Tokenizers\PHP; -use PHP_CodeSniffer\Exceptions\RuntimeException; +use PHP_CodeSniffer\Util\Tokens; abstract class AbstractPatternSniff implements Sniff { @@ -416,6 +416,11 @@ protected function processPattern($patternInfo, File $phpcsFile, $stackPtr) $lastAddedStackPtr = null; $patternLen = count($pattern); + if (($stackPtr + $patternLen - $patternInfo['listen_pos']) > $phpcsFile->numTokens) { + // Pattern can never match as there are not enough tokens left in the file. + return false; + } + for ($i = $patternInfo['listen_pos']; $i < $patternLen; $i++) { if (isset($tokens[$stackPtr]) === false) { break; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Sniffs/AbstractScopeSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Sniffs/AbstractScopeSniff.php index 74201ab8e..165474ac4 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Sniffs/AbstractScopeSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Sniffs/AbstractScopeSniff.php @@ -14,7 +14,7 @@ * protected function processTokenWithinScope(\PHP_CodeSniffer\Files\File $phpcsFile, $stackPtr, $currScope) * { * $className = $phpcsFile->getDeclarationName($currScope); - * echo 'encountered a method within class '.$className; + * $phpcsFile->addWarning('encountered a method within class '.$className, $stackPtr, 'MethodFound'); * } * } * @@ -26,8 +26,8 @@ namespace PHP_CodeSniffer\Sniffs; -use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Exceptions\RuntimeException; +use PHP_CodeSniffer\Files\File; abstract class AbstractScopeSniff implements Sniff { @@ -123,7 +123,7 @@ final public function register() * * @return void|int Optionally returns a stack pointer. The sniff will not be * called again on the current file until the returned stack - * pointer is reached. Return ($phpcsFile->numTokens + 1) to skip + * pointer is reached. Return `$phpcsFile->numTokens` to skip * the rest of the file. * @see processTokenWithinScope() */ @@ -164,7 +164,7 @@ final public function process(File $phpcsFile, $stackPtr) * * @return void|int Optionally returns a stack pointer. The sniff will not be * called again on the current file until the returned stack - * pointer is reached. Return ($phpcsFile->numTokens + 1) to skip + * pointer is reached. Return `$phpcsFile->numTokens` to skip * the rest of the file. */ abstract protected function processTokenWithinScope(File $phpcsFile, $stackPtr, $currScope); @@ -180,7 +180,7 @@ abstract protected function processTokenWithinScope(File $phpcsFile, $stackPtr, * * @return void|int Optionally returns a stack pointer. The sniff will not be * called again on the current file until the returned stack - * pointer is reached. Return (count($tokens) + 1) to skip + * pointer is reached. Return `$phpcsFile->numTokens` to skip * the rest of the file. */ abstract protected function processTokenOutsideScope(File $phpcsFile, $stackPtr); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Sniffs/AbstractVariableSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Sniffs/AbstractVariableSniff.php index 6493d5701..34a3b43aa 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Sniffs/AbstractVariableSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Sniffs/AbstractVariableSniff.php @@ -72,7 +72,7 @@ public function __construct() * * @return void|int Optionally returns a stack pointer. The sniff will not be * called again on the current file until the returned stack - * pointer is reached. Return ($phpcsFile->numTokens + 1) to skip + * pointer is reached. Return `$phpcsFile->numTokens` to skip * the rest of the file. */ final protected function processTokenWithinScope(File $phpcsFile, $stackPtr, $currScope) @@ -156,7 +156,7 @@ final protected function processTokenWithinScope(File $phpcsFile, $stackPtr, $cu * * @return void|int Optionally returns a stack pointer. The sniff will not be * called again on the current file until the returned stack - * pointer is reached. Return ($phpcsFile->numTokens + 1) to skip + * pointer is reached. Return `$phpcsFile->numTokens` to skip * the rest of the file. */ final protected function processTokenOutsideScope(File $phpcsFile, $stackPtr) @@ -187,7 +187,7 @@ final protected function processTokenOutsideScope(File $phpcsFile, $stackPtr) * * @return void|int Optionally returns a stack pointer. The sniff will not be * called again on the current file until the returned stack - * pointer is reached. Return ($phpcsFile->numTokens + 1) to skip + * pointer is reached. Return `$phpcsFile->numTokens` to skip * the rest of the file. */ abstract protected function processMemberVar(File $phpcsFile, $stackPtr); @@ -202,7 +202,7 @@ abstract protected function processMemberVar(File $phpcsFile, $stackPtr); * * @return void|int Optionally returns a stack pointer. The sniff will not be * called again on the current file until the returned stack - * pointer is reached. Return ($phpcsFile->numTokens + 1) to skip + * pointer is reached. Return `$phpcsFile->numTokens` to skip * the rest of the file. */ abstract protected function processVariable(File $phpcsFile, $stackPtr); @@ -221,7 +221,7 @@ abstract protected function processVariable(File $phpcsFile, $stackPtr); * * @return void|int Optionally returns a stack pointer. The sniff will not be * called again on the current file until the returned stack - * pointer is reached. Return ($phpcsFile->numTokens + 1) to skip + * pointer is reached. Return `$phpcsFile->numTokens` to skip * the rest of the file. */ abstract protected function processVariableInString(File $phpcsFile, $stackPtr); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Sniffs/Sniff.php b/app/vendor/squizlabs/php_codesniffer/src/Sniffs/Sniff.php index 3556edd53..e0f7cfe9c 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Sniffs/Sniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Sniffs/Sniff.php @@ -71,7 +71,7 @@ public function register(); * * @return void|int Optionally returns a stack pointer. The sniff will not be * called again on the current file until the returned stack - * pointer is reached. Return (count($tokens) + 1) to skip + * pointer is reached. Return `$phpcsFile->numTokens` to skip * the rest of the file. */ public function process(File $phpcsFile, $stackPtr); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Arrays/ArrayIndentStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Arrays/ArrayIndentStandard.xml new file mode 100644 index 000000000..0312a70f1 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Arrays/ArrayIndentStandard.xml @@ -0,0 +1,107 @@ + + + + + + + [ + 1, + 2, +]; + +if ($condition) { + $a = + [ + 1, + 2, + ]; +} + + ]]> + + + [ + 1, + 2, + ]; +} + ]]> + + + + + + + + 1, + 2, + 3, +); + ]]> + + + 1, + 2, + 3, +); + ]]> + + + + + + + + +]; + ]]> + + + ]; + ]]> + + + + + + + + ); + ]]> + + + ); + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/CodeAnalysis/EmptyPHPStatementStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/CodeAnalysis/EmptyPHPStatementStandard.xml index 5652f657a..6b96c825a 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/CodeAnalysis/EmptyPHPStatementStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/CodeAnalysis/EmptyPHPStatementStandard.xml @@ -20,11 +20,11 @@ - + ; if (true) { @@ -32,7 +32,7 @@ if (true) { } ]]> - + ;;; if (true) { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/CodeAnalysis/UselessOverridingMethodStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/CodeAnalysis/UselessOverridingMethodStandard.xml index ba8bd7e42..ade341939 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/CodeAnalysis/UselessOverridingMethodStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/CodeAnalysis/UselessOverridingMethodStandard.xml @@ -1,13 +1,13 @@ - + - + - + + + + + + + + + + Some content. + */ + ]]> + + + + */ + ]]> + + + + + + + + /** + * Short description. + */ + ]]> + + + /** Short description. */ + ]]> + + + + + + + + Short description. + */ + ]]> + + + @return int + */ + +/** + * + * Short description. + */ + ]]> + + + + + + + + Short description. + * + * Long description. + */ + ]]> + + + short description. + * + * long description. + */ + ]]> + + + + + + + + * + * Long description. + * + * @param int $foo + */ + ]]> + + + * + * + + * Long description. + * @param int $foo + */ + ]]> + + + + + + + + * @param int $foo + * @param string $bar + */ + ]]> + + + * + * @param string $bar + */ + ]]> + + + + + + + + * @param int $foo + * + * @since 3.4.8 + * @deprecated 6.0.0 + */ + ]]> + + + * @param int $foo + * @since 3.4.8 + * @deprecated 6.0.0 + */ + ]]> + + + + + + + + 0.5.0 + * @deprecated 1.0.0 + */ + ]]> + + + 0.5.0 + * @deprecated 1.0.0 + */ + ]]> + + + + + + + + @param string $foo + * + * @return void + */ + ]]> + + + @param string $bar + */ + ]]> + + + + + + + + + */ + ]]> + + + * + */ + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/ControlStructures/DisallowYodaConditionsStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/ControlStructures/DisallowYodaConditionsStandard.xml index 570e4192b..651cc70d3 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/ControlStructures/DisallowYodaConditionsStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/ControlStructures/DisallowYodaConditionsStandard.xml @@ -5,14 +5,14 @@ ]]> - + { $var = 1; } ]]> - + { $var = 1; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Files/InlineHTMLStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Files/InlineHTMLStandard.xml index 3fbf5024d..3c137a9a9 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Files/InlineHTMLStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Files/InlineHTMLStandard.xml @@ -1,18 +1,18 @@ - + - + some string here - + = (1 + 2); $veryLongVarName = 'string'; $var = foo($bar, $baz); ]]> - + = (1 + 2); $veryLongVarName = 'string'; @@ -22,17 +22,17 @@ $var = foo($bar, $baz); - + += 1; $veryLongVarName = 1; ]]> - + += 1; $veryLongVarName = 1; @@ -40,13 +40,13 @@ $veryLongVarName = 1; - + = 1; $veryLongVarName -= 1; ]]> - + = 1; $veryLongVarName -= 1; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Formatting/NoSpaceAfterCastStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Formatting/NoSpaceAfterCastStandard.xml index 042e4f803..80b932d27 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Formatting/NoSpaceAfterCastStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Formatting/NoSpaceAfterCastStandard.xml @@ -1,4 +1,4 @@ - + + + - + $baz) -{ -} +foo($bar, $baz); ]]> - + $baz) -{ -} - ]]> - - - - - = true) -{ -} - ]]> - - - =true) -{ -} +foo($bar ,$baz); ]]> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Functions/OpeningFunctionBraceBsdAllmanStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Functions/OpeningFunctionBraceBsdAllmanStandard.xml index 414dc289e..9eea8ca80 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Functions/OpeningFunctionBraceBsdAllmanStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Functions/OpeningFunctionBraceBsdAllmanStandard.xml @@ -1,22 +1,24 @@ - + - + { - ... + // Do something } ]]> - + { - ... + // Do something } ]]> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Functions/OpeningFunctionBraceKernighanRitchieStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Functions/OpeningFunctionBraceKernighanRitchieStandard.xml index 84c2bdd86..2d5d0ed81 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Functions/OpeningFunctionBraceKernighanRitchieStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Functions/OpeningFunctionBraceKernighanRitchieStandard.xml @@ -1,22 +1,24 @@ - + - + { - ... + // Do something. } ]]> - + { - ... + // Do something. } ]]> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/NamingConventions/AbstractClassNamePrefixStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/NamingConventions/AbstractClassNamePrefixStandard.xml index c30d26e9d..e9e61ddd6 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/NamingConventions/AbstractClassNamePrefixStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/NamingConventions/AbstractClassNamePrefixStandard.xml @@ -5,14 +5,14 @@ ]]> - + AbstractBar { } ]]> - + Bar { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/NamingConventions/InterfaceNameSuffixStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/NamingConventions/InterfaceNameSuffixStandard.xml index 0aa0c76e4..bf1a70769 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/NamingConventions/InterfaceNameSuffixStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/NamingConventions/InterfaceNameSuffixStandard.xml @@ -5,14 +5,14 @@ ]]> - + BarInterface { } ]]> - + Bar { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/NamingConventions/TraitNameSuffixStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/NamingConventions/TraitNameSuffixStandard.xml index 711867e45..fb5f2e670 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/NamingConventions/TraitNameSuffixStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/NamingConventions/TraitNameSuffixStandard.xml @@ -5,14 +5,14 @@ ]]> - + BarTrait { } ]]> - + Bar { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/NamingConventions/UpperCaseConstantNameStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/NamingConventions/UpperCaseConstantNameStandard.xml index 6ef61b93c..22c2f6b12 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/NamingConventions/UpperCaseConstantNameStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/NamingConventions/UpperCaseConstantNameStandard.xml @@ -1,11 +1,11 @@ - + FOO_CONSTANT', 'foo'); @@ -15,7 +15,7 @@ class FooClass } ]]> - + Foo_Constant', 'foo'); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/PHP/CharacterBeforePHPOpeningTagStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/PHP/CharacterBeforePHPOpeningTagStandard.xml index df5a0eba4..494a5d738 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/PHP/CharacterBeforePHPOpeningTagStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/PHP/CharacterBeforePHPOpeningTagStandard.xml @@ -1,17 +1,17 @@ - + - + Beginning content - + echo 'Foo'; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/PHP/DisallowRequestSuperglobalStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/PHP/DisallowRequestSuperglobalStandard.xml index f94769427..519d7f5c8 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/PHP/DisallowRequestSuperglobalStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/PHP/DisallowRequestSuperglobalStandard.xml @@ -1,6 +1,6 @@ - diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/PHP/LowerCaseConstantStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/PHP/LowerCaseConstantStandard.xml index 7dc30c10d..d4aac8093 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/PHP/LowerCaseConstantStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/PHP/LowerCaseConstantStandard.xml @@ -5,14 +5,14 @@ ]]> - + false || $var === null) { $var = true; } ]]> - + FALSE || $var === NULL) { $var = TRUE; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/PHP/RequireStrictTypesStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/PHP/RequireStrictTypesStandard.xml new file mode 100644 index 000000000..dc7243069 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/PHP/RequireStrictTypesStandard.xml @@ -0,0 +1,38 @@ + + + + + + + strict_types=1); + +declare(encoding='UTF-8', strict_types=0); + ]]> + + + ); + ]]> + + + + + + + + 1); + ]]> + + + 0); + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/PHP/SAPIUsageStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/PHP/SAPIUsageStandard.xml index e74005ad1..989827ed9 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/PHP/SAPIUsageStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/PHP/SAPIUsageStandard.xml @@ -12,7 +12,7 @@ if (PHP_SAPI === 'cli') { } ]]> - + php_sapi_name() === 'cli') { echo "Hello, CLI user."; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/PHP/UpperCaseConstantStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/PHP/UpperCaseConstantStandard.xml index 1f337f77e..2cc1df2f4 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/PHP/UpperCaseConstantStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/PHP/UpperCaseConstantStandard.xml @@ -5,14 +5,14 @@ ]]> - + FALSE || $var === NULL) { $var = TRUE; } ]]> - + false || $var === null) { $var = true; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Strings/UnnecessaryHeredocStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Strings/UnnecessaryHeredocStandard.xml new file mode 100644 index 000000000..e0ca14f47 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/Strings/UnnecessaryHeredocStandard.xml @@ -0,0 +1,39 @@ + + + + + + + <<<'EOD' +some text +EOD; + ]]> + + + << +some text +EOD; + ]]> + + + + + <<<"EOD" +some $text +EOD; + ]]> + + + <<<"EOD" +some text +EOD; + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/VersionControl/SubversionPropertiesStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/VersionControl/SubversionPropertiesStandard.xml index f4f3e19cb..c38ae4c44 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/VersionControl/SubversionPropertiesStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/VersionControl/SubversionPropertiesStandard.xml @@ -1,7 +1,7 @@ diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/WhiteSpace/ArbitraryParenthesesSpacingStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/WhiteSpace/ArbitraryParenthesesSpacingStandard.xml index 338c83893..d65c93a8c 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/WhiteSpace/ArbitraryParenthesesSpacingStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/WhiteSpace/ArbitraryParenthesesSpacingStandard.xml @@ -5,12 +5,12 @@ ]]> - + - + + + + + + + << +some text +EOD; + ]]> + + + <<< END +some text +END; + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/WhiteSpace/LanguageConstructSpacingStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/WhiteSpace/LanguageConstructSpacingStandard.xml index a9cd5a65c..af6a4f954 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/WhiteSpace/LanguageConstructSpacingStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/WhiteSpace/LanguageConstructSpacingStandard.xml @@ -29,15 +29,18 @@ $newLine; from [1, 2, 3]; +function myGenerator() { + yield from [1, 2, 3]; +} ]]> - + from [1, 2, 3]; -yield from [1, 2, 3]; -yield -from [1, 2, 3]; +function myGenerator() { + yield from [1, 2, 3]; + yield + from [1, 2, 3]; +} ]]> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/WhiteSpace/SpreadOperatorSpacingAfterStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/WhiteSpace/SpreadOperatorSpacingAfterStandard.xml index d33b6051d..558bebfac 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/WhiteSpace/SpreadOperatorSpacingAfterStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Docs/WhiteSpace/SpreadOperatorSpacingAfterStandard.xml @@ -17,7 +17,7 @@ function foo(&...$spread) { } ]]> - + ... $spread) { bar(... @@ -25,7 +25,7 @@ function bar(... $spread) { ); bar( - [... $foo ],.../*comment*/array_values($keyedArray) + [... $foo ],.../*@*/array_values($keyed) ); } ]]> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Arrays/ArrayIndentSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Arrays/ArrayIndentSniff.php index 87da8f3cf..b6e3d37d7 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Arrays/ArrayIndentSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Arrays/ArrayIndentSniff.php @@ -62,7 +62,6 @@ public function processMultiLineArray($phpcsFile, $stackPtr, $arrayStart, $array // Determine how far indented the entire array declaration should be. $ignore = Tokens::$emptyTokens; $ignore[] = T_DOUBLE_ARROW; - $ignore[] = T_COMMA; $prev = $phpcsFile->findPrevious($ignore, ($stackPtr - 1), null, true); $start = $phpcsFile->findStartOfStatement($prev); $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $start, true); @@ -152,7 +151,7 @@ public function processMultiLineArray($phpcsFile, $stackPtr, $arrayStart, $array $error = 'Closing brace of array declaration must be on a new line'; $fix = $phpcsFile->addFixableError($error, $arrayEnd, 'CloseBraceNotNewLine'); if ($fix === true) { - $padding = $phpcsFile->eolChar.str_repeat(' ', $expectedIndent); + $padding = $phpcsFile->eolChar.str_repeat(' ', $startIndent); $phpcsFile->fixer->addContentBefore($arrayEnd, $padding); } @@ -160,20 +159,19 @@ public function processMultiLineArray($phpcsFile, $stackPtr, $arrayStart, $array } // The close brace must be indented one stop less. - $expectedIndent -= $this->indent; - $foundIndent = ($tokens[$arrayEnd]['column'] - 1); - if ($foundIndent === $expectedIndent) { + $foundIndent = ($tokens[$arrayEnd]['column'] - 1); + if ($foundIndent === $startIndent) { return; } $pluralizeSpace = 's'; - if ($expectedIndent === 1) { + if ($startIndent === 1) { $pluralizeSpace = ''; } $error = 'Array close brace not indented correctly; expected %s space%s but found %s'; $data = [ - $expectedIndent, + $startIndent, $pluralizeSpace, $foundIndent, ]; @@ -182,7 +180,7 @@ public function processMultiLineArray($phpcsFile, $stackPtr, $arrayStart, $array return; } - $padding = str_repeat(' ', $expectedIndent); + $padding = str_repeat(' ', $startIndent); if ($foundIndent === 0) { $phpcsFile->fixer->addContentBefore($arrayEnd, $padding); } else { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Arrays/DisallowLongArraySyntaxSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Arrays/DisallowLongArraySyntaxSniff.php index 58d26325c..6854945ad 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Arrays/DisallowLongArraySyntaxSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Arrays/DisallowLongArraySyntaxSniff.php @@ -45,9 +45,7 @@ public function process(File $phpcsFile, $stackPtr) $error = 'Short array syntax must be used to define arrays'; - if (isset($tokens[$stackPtr]['parenthesis_opener']) === false - || isset($tokens[$stackPtr]['parenthesis_closer']) === false - ) { + if (isset($tokens[$stackPtr]['parenthesis_opener'], $tokens[$stackPtr]['parenthesis_closer']) === false) { // Live coding/parse error, just show the error, don't try and fix it. $phpcsFile->addError($error, $stackPtr, 'Found'); return; @@ -61,13 +59,9 @@ public function process(File $phpcsFile, $stackPtr) $phpcsFile->fixer->beginChangeset(); - if ($opener === null) { - $phpcsFile->fixer->replaceToken($stackPtr, '[]'); - } else { - $phpcsFile->fixer->replaceToken($stackPtr, ''); - $phpcsFile->fixer->replaceToken($opener, '['); - $phpcsFile->fixer->replaceToken($closer, ']'); - } + $phpcsFile->fixer->replaceToken($stackPtr, ''); + $phpcsFile->fixer->replaceToken($opener, '['); + $phpcsFile->fixer->replaceToken($closer, ']'); $phpcsFile->fixer->endChangeset(); } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php index 19ff1edf6..dd0454797 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Classes/DuplicateClassNameSniff.php @@ -11,6 +11,7 @@ use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\Sniff; +use PHP_CodeSniffer\Util\Tokens; class DuplicateClassNameSniff implements Sniff { @@ -42,7 +43,7 @@ public function register() * @param int $stackPtr The position of the current token * in the stack passed in $tokens. * - * @return void + * @return int */ public function process(File $phpcsFile, $stackPtr) { @@ -55,63 +56,70 @@ public function process(File $phpcsFile, $stackPtr) T_TRAIT, T_ENUM, T_NAMESPACE, - T_CLOSE_TAG, ]; $stackPtr = $phpcsFile->findNext($findTokens, ($stackPtr + 1)); while ($stackPtr !== false) { - if ($tokens[$stackPtr]['code'] === T_CLOSE_TAG) { - // We can stop here. The sniff will continue from the next open - // tag when PHPCS reaches that token, if there is one. - return; - } - // Keep track of what namespace we are in. if ($tokens[$stackPtr]['code'] === T_NAMESPACE) { - $nsEnd = $phpcsFile->findNext( - [ - T_NS_SEPARATOR, - T_STRING, - T_WHITESPACE, - ], - ($stackPtr + 1), - null, - true - ); - - $namespace = trim($phpcsFile->getTokensAsString(($stackPtr + 1), ($nsEnd - $stackPtr - 1))); - $stackPtr = $nsEnd; - } else { - $nameToken = $phpcsFile->findNext(T_STRING, $stackPtr); - $name = $tokens[$nameToken]['content']; - if ($namespace !== '') { - $name = $namespace.'\\'.$name; + $nextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true); + if ($nextNonEmpty !== false + // Ignore namespace keyword used as operator. + && $tokens[$nextNonEmpty]['code'] !== T_NS_SEPARATOR + ) { + $namespace = ''; + for ($i = $nextNonEmpty; $i < $phpcsFile->numTokens; $i++) { + if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) { + continue; + } + + if ($tokens[$i]['code'] !== T_STRING && $tokens[$i]['code'] !== T_NS_SEPARATOR) { + break; + } + + $namespace .= $tokens[$i]['content']; + } + + $stackPtr = $i; } - - $compareName = strtolower($name); - if (isset($this->foundClasses[$compareName]) === true) { - $type = strtolower($tokens[$stackPtr]['content']); - $file = $this->foundClasses[$compareName]['file']; - $line = $this->foundClasses[$compareName]['line']; - $error = 'Duplicate %s name "%s" found; first defined in %s on line %s'; - $data = [ - $type, - $name, - $file, - $line, - ]; - $phpcsFile->addWarning($error, $stackPtr, 'Found', $data); - } else { - $this->foundClasses[$compareName] = [ - 'file' => $phpcsFile->getFilename(), - 'line' => $tokens[$stackPtr]['line'], - ]; + } else { + $name = $phpcsFile->getDeclarationName($stackPtr); + if (empty($name) === false) { + if ($namespace !== '') { + $name = $namespace.'\\'.$name; + } + + $compareName = strtolower($name); + if (isset($this->foundClasses[$compareName]) === true) { + $type = strtolower($tokens[$stackPtr]['content']); + $file = $this->foundClasses[$compareName]['file']; + $line = $this->foundClasses[$compareName]['line']; + $error = 'Duplicate %s name "%s" found; first defined in %s on line %s'; + $data = [ + $type, + $name, + $file, + $line, + ]; + $phpcsFile->addWarning($error, $stackPtr, 'Found', $data); + } else { + $this->foundClasses[$compareName] = [ + 'file' => $phpcsFile->getFilename(), + 'line' => $tokens[$stackPtr]['line'], + ]; + } + }//end if + + if (isset($tokens[$stackPtr]['scope_closer']) === true) { + $stackPtr = $tokens[$stackPtr]['scope_closer']; } }//end if $stackPtr = $phpcsFile->findNext($findTokens, ($stackPtr + 1)); }//end while + return $phpcsFile->numTokens; + }//end process() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/CodeAnalysis/EmptyPHPStatementSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/CodeAnalysis/EmptyPHPStatementSniff.php index 3ebfccc04..6fbfdc0b2 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/CodeAnalysis/EmptyPHPStatementSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/CodeAnalysis/EmptyPHPStatementSniff.php @@ -2,7 +2,7 @@ /** * Checks against empty PHP statements. * - * - Check against two semi-colons with no executable code in between. + * - Check against two semicolons with no executable code in between. * - Check against an empty PHP open - close tag combination. * * @author Juliette Reinders Folmer @@ -48,115 +48,136 @@ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); - switch ($tokens[$stackPtr]['type']) { - // Detect `something();;`. - case 'T_SEMICOLON': - $prevNonEmpty = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); + if ($tokens[$stackPtr]['code'] === T_SEMICOLON) { + $this->processSemicolon($phpcsFile, $stackPtr); + } else { + $this->processCloseTag($phpcsFile, $stackPtr); + } - if ($prevNonEmpty === false) { + }//end process() + + + /** + * Detect `something();;`. + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + private function processSemicolon(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + $prevNonEmpty = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); + if ($tokens[$prevNonEmpty]['code'] !== T_SEMICOLON + && $tokens[$prevNonEmpty]['code'] !== T_OPEN_TAG + && $tokens[$prevNonEmpty]['code'] !== T_OPEN_TAG_WITH_ECHO + ) { + if (isset($tokens[$prevNonEmpty]['scope_condition']) === false) { return; } - if ($tokens[$prevNonEmpty]['code'] !== T_SEMICOLON - && $tokens[$prevNonEmpty]['code'] !== T_OPEN_TAG - && $tokens[$prevNonEmpty]['code'] !== T_OPEN_TAG_WITH_ECHO + if ($tokens[$prevNonEmpty]['scope_opener'] !== $prevNonEmpty + && $tokens[$prevNonEmpty]['code'] !== T_CLOSE_CURLY_BRACKET ) { - if (isset($tokens[$prevNonEmpty]['scope_condition']) === false) { - return; - } + return; + } - if ($tokens[$prevNonEmpty]['scope_opener'] !== $prevNonEmpty - && $tokens[$prevNonEmpty]['code'] !== T_CLOSE_CURLY_BRACKET - ) { - return; - } + $scopeOwner = $tokens[$tokens[$prevNonEmpty]['scope_condition']]['code']; + if ($scopeOwner === T_CLOSURE || $scopeOwner === T_ANON_CLASS || $scopeOwner === T_MATCH) { + return; + } - $scopeOwner = $tokens[$tokens[$prevNonEmpty]['scope_condition']]['code']; - if ($scopeOwner === T_CLOSURE || $scopeOwner === T_ANON_CLASS || $scopeOwner === T_MATCH) { - return; - } + // Else, it's something like `if (foo) {};` and the semicolon is not needed. + } - // Else, it's something like `if (foo) {};` and the semi-colon is not needed. + if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) { + $nested = $tokens[$stackPtr]['nested_parenthesis']; + $lastCloser = array_pop($nested); + if (isset($tokens[$lastCloser]['parenthesis_owner']) === true + && $tokens[$tokens[$lastCloser]['parenthesis_owner']]['code'] === T_FOR + ) { + // Empty for() condition. + return; } + } - if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) { - $nested = $tokens[$stackPtr]['nested_parenthesis']; - $lastCloser = array_pop($nested); - if (isset($tokens[$lastCloser]['parenthesis_owner']) === true - && $tokens[$tokens[$lastCloser]['parenthesis_owner']]['code'] === T_FOR - ) { - // Empty for() condition. - return; + $fix = $phpcsFile->addFixableWarning( + 'Empty PHP statement detected: superfluous semicolon.', + $stackPtr, + 'SemicolonWithoutCodeDetected' + ); + + if ($fix === true) { + $phpcsFile->fixer->beginChangeset(); + + if ($tokens[$prevNonEmpty]['code'] === T_OPEN_TAG + || $tokens[$prevNonEmpty]['code'] === T_OPEN_TAG_WITH_ECHO + ) { + // Check for superfluous whitespace after the semicolon which should be + // removed as the `fixer->replaceToken(($stackPtr + 1), $replacement); } } - $fix = $phpcsFile->addFixableWarning( - 'Empty PHP statement detected: superfluous semi-colon.', - $stackPtr, - 'SemicolonWithoutCodeDetected' - ); - if ($fix === true) { - $phpcsFile->fixer->beginChangeset(); - - if ($tokens[$prevNonEmpty]['code'] === T_OPEN_TAG - || $tokens[$prevNonEmpty]['code'] === T_OPEN_TAG_WITH_ECHO + for ($i = $stackPtr; $i > $prevNonEmpty; $i--) { + if ($tokens[$i]['code'] !== T_SEMICOLON + && $tokens[$i]['code'] !== T_WHITESPACE ) { - // Check for superfluous whitespace after the semi-colon which will be - // removed as the `fixer->replaceToken(($stackPtr + 1), $replacement); - } + break; } - for ($i = $stackPtr; $i > $prevNonEmpty; $i--) { - if ($tokens[$i]['code'] !== T_SEMICOLON - && $tokens[$i]['code'] !== T_WHITESPACE - ) { - break; - } + $phpcsFile->fixer->replaceToken($i, ''); + } - $phpcsFile->fixer->replaceToken($i, ''); - } + $phpcsFile->fixer->endChangeset(); + }//end if - $phpcsFile->fixer->endChangeset(); - }//end if - break; + }//end processSemicolon() - // Detect ``. - case 'T_CLOSE_TAG': - $prevNonEmpty = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); - if ($prevNonEmpty === false - || ($tokens[$prevNonEmpty]['code'] !== T_OPEN_TAG - && $tokens[$prevNonEmpty]['code'] !== T_OPEN_TAG_WITH_ECHO) - ) { - return; - } + /** + * Detect ``. + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + private function processCloseTag(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); - $fix = $phpcsFile->addFixableWarning( - 'Empty PHP open/close tag combination detected.', - $prevNonEmpty, - 'EmptyPHPOpenCloseTagsDetected' - ); - if ($fix === true) { - $phpcsFile->fixer->beginChangeset(); + $prevNonEmpty = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + if ($tokens[$prevNonEmpty]['code'] !== T_OPEN_TAG + && $tokens[$prevNonEmpty]['code'] !== T_OPEN_TAG_WITH_ECHO + ) { + return; + } - for ($i = $prevNonEmpty; $i <= $stackPtr; $i++) { - $phpcsFile->fixer->replaceToken($i, ''); - } + $fix = $phpcsFile->addFixableWarning( + 'Empty PHP open/close tag combination detected.', + $prevNonEmpty, + 'EmptyPHPOpenCloseTagsDetected' + ); - $phpcsFile->fixer->endChangeset(); + if ($fix === true) { + $phpcsFile->fixer->beginChangeset(); + + for ($i = $prevNonEmpty; $i <= $stackPtr; $i++) { + $phpcsFile->fixer->replaceToken($i, ''); } - break; - default: - // Deliberately left empty. - break; - }//end switch + $phpcsFile->fixer->endChangeset(); + } - }//end process() + }//end processCloseTag() }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/CodeAnalysis/JumbledIncrementerSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/CodeAnalysis/JumbledIncrementerSniff.php index 63e925fe7..8174d6653 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/CodeAnalysis/JumbledIncrementerSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/CodeAnalysis/JumbledIncrementerSniff.php @@ -67,7 +67,7 @@ public function process(File $phpcsFile, $stackPtr) return; } - // Find incrementors for outer loop. + // Find incrementers for outer loop. $outer = $this->findIncrementers($tokens, $token); // Skip if empty. @@ -88,8 +88,8 @@ public function process(File $phpcsFile, $stackPtr) $diff = array_intersect($outer, $inner); if (count($diff) !== 0) { - $error = 'Loop incrementor (%s) jumbling with inner loop'; - $data = [join(', ', $diff)]; + $error = 'Loop incrementer (%s) jumbling with inner loop'; + $data = [implode(', ', $diff)]; $phpcsFile->addWarning($error, $stackPtr, 'Found', $data); } } @@ -101,14 +101,14 @@ public function process(File $phpcsFile, $stackPtr) * Get all used variables in the incrementer part of a for statement. * * @param array $tokens Array with all code sniffer tokens. - * @param array $token Current for loop token + * @param array $token Current for loop token. * * @return string[] List of all found incrementer variables. */ protected function findIncrementers(array $tokens, array $token) { // Skip invalid statement. - if (isset($token['parenthesis_opener']) === false) { + if (isset($token['parenthesis_opener'], $token['parenthesis_closer']) === false) { return []; } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/CodeAnalysis/RequireExplicitBooleanOperatorPrecedenceSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/CodeAnalysis/RequireExplicitBooleanOperatorPrecedenceSniff.php index 93afe2e35..41922efc6 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/CodeAnalysis/RequireExplicitBooleanOperatorPrecedenceSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/CodeAnalysis/RequireExplicitBooleanOperatorPrecedenceSniff.php @@ -53,8 +53,7 @@ class RequireExplicitBooleanOperatorPrecedenceSniff implements Sniff */ public function register() { - $this->searchTargets = Tokens::$booleanOperators; - $this->searchTargets += Tokens::$blockOpeners; + $this->searchTargets = Tokens::$booleanOperators; $this->searchTargets[T_INLINE_THEN] = T_INLINE_THEN; $this->searchTargets[T_INLINE_ELSE] = T_INLINE_ELSE; @@ -102,12 +101,6 @@ public function process(File $phpcsFile, $stackPtr) return; } - if (isset(Tokens::$blockOpeners[$tokens[$previous]['code']]) === true) { - // Beginning of the expression found for a block opener. Needed to - // correctly handle match arms. - return; - } - // We found a mismatching operator, thus we must report the error. $error = 'Mixing different binary boolean operators within an expression'; $error .= ' without using parentheses to clarify precedence is not allowed.'; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/CodeAnalysis/UselessOverridingMethodSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/CodeAnalysis/UselessOverridingMethodSniff.php index 1b79fd339..5163da71c 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/CodeAnalysis/UselessOverridingMethodSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/CodeAnalysis/UselessOverridingMethodSniff.php @@ -28,6 +28,17 @@ class UselessOverridingMethodSniff implements Sniff { + /** + * Object-Oriented scopes in which a call to parent::method() can exist. + * + * @var array Keys are the token constants, value is irrelevant. + */ + private $validOOScopes = [ + T_CLASS => true, + T_ANON_CLASS => true, + T_TRAIT => true, + ]; + /** * Registers the tokens that this sniff wants to listen for. @@ -56,7 +67,15 @@ public function process(File $phpcsFile, $stackPtr) $token = $tokens[$stackPtr]; // Skip function without body. - if (isset($token['scope_opener']) === false) { + if (isset($token['scope_opener'], $token['scope_closer']) === false) { + return; + } + + $conditions = $token['conditions']; + $lastCondition = end($conditions); + + // Skip functions that are not a method part of a class, anon class or trait. + if (isset($this->validOOScopes[$lastCondition]) === false) { return; } @@ -93,15 +112,15 @@ public function process(File $phpcsFile, $stackPtr) $next = $phpcsFile->findNext(Tokens::$emptyTokens, ($next + 1), null, true); // Skip for invalid code. - if ($next === false || $tokens[$next]['code'] !== T_DOUBLE_COLON) { + if ($tokens[$next]['code'] !== T_DOUBLE_COLON) { return; } - // Find next non empty token index, should be the function name. + // Find next non empty token index, should be the name of the method being called. $next = $phpcsFile->findNext(Tokens::$emptyTokens, ($next + 1), null, true); // Skip for invalid code or other method. - if ($next === false || $tokens[$next]['content'] !== $methodName) { + if (strcasecmp($tokens[$next]['content'], $methodName) !== 0) { return; } @@ -109,14 +128,13 @@ public function process(File $phpcsFile, $stackPtr) $next = $phpcsFile->findNext(Tokens::$emptyTokens, ($next + 1), null, true); // Skip for invalid code. - if ($next === false || $tokens[$next]['code'] !== T_OPEN_PARENTHESIS) { + if ($tokens[$next]['code'] !== T_OPEN_PARENTHESIS || isset($tokens[$next]['parenthesis_closer']) === false) { return; } $parameters = ['']; $parenthesisCount = 1; - $count = count($tokens); - for (++$next; $next < $count; ++$next) { + for (++$next; $next < $phpcsFile->numTokens; ++$next) { $code = $tokens[$next]['code']; if ($code === T_OPEN_PARENTHESIS) { @@ -135,15 +153,20 @@ public function process(File $phpcsFile, $stackPtr) }//end for $next = $phpcsFile->findNext(Tokens::$emptyTokens, ($next + 1), null, true); - if ($next === false || $tokens[$next]['code'] !== T_SEMICOLON) { + if ($tokens[$next]['code'] !== T_SEMICOLON && $tokens[$next]['code'] !== T_CLOSE_TAG) { return; } + // This list deliberately does not include the `T_OPEN_TAG_WITH_ECHO` as that token implicitly is an echo statement, i.e. content. + $nonContent = Tokens::$emptyTokens; + $nonContent[T_OPEN_TAG] = T_OPEN_TAG; + $nonContent[T_CLOSE_TAG] = T_CLOSE_TAG; + // Check rest of the scope. for (++$next; $next <= $end; ++$next) { $code = $tokens[$next]['code']; // Skip for any other content. - if (isset(Tokens::$emptyTokens[$code]) === false) { + if (isset($nonContent[$code]) === false) { return; } } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/ControlStructures/DisallowYodaConditionsSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/ControlStructures/DisallowYodaConditionsSniff.php index d82931cb6..17e81850c 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/ControlStructures/DisallowYodaConditionsSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/ControlStructures/DisallowYodaConditionsSniff.php @@ -25,7 +25,10 @@ class DisallowYodaConditionsSniff implements Sniff */ public function register() { - return Tokens::$comparisonTokens; + $tokens = Tokens::$comparisonTokens; + unset($tokens[T_COALESCE]); + + return $tokens; }//end register() @@ -54,9 +57,7 @@ public function process(File $phpcsFile, $stackPtr) T_CONSTANT_ENCAPSED_STRING, ]; - if ($previousIndex === false - || in_array($tokens[$previousIndex]['code'], $relevantTokens, true) === false - ) { + if (in_array($tokens[$previousIndex]['code'], $relevantTokens, true) === false) { return; } @@ -68,9 +69,6 @@ public function process(File $phpcsFile, $stackPtr) } $prevIndex = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($previousIndex - 1), null, true); - if ($prevIndex === false) { - return; - } if (in_array($tokens[$prevIndex]['code'], Tokens::$arithmeticTokens, true) === true) { return; @@ -82,20 +80,19 @@ public function process(File $phpcsFile, $stackPtr) // Is it a parenthesis. if ($tokens[$previousIndex]['code'] === T_CLOSE_PARENTHESIS) { - // Check what exists inside the parenthesis. - $closeParenthesisIndex = $phpcsFile->findPrevious( + $beforeOpeningParenthesisIndex = $phpcsFile->findPrevious( Tokens::$emptyTokens, ($tokens[$previousIndex]['parenthesis_opener'] - 1), null, true ); - if ($closeParenthesisIndex === false || $tokens[$closeParenthesisIndex]['code'] !== T_ARRAY) { - if ($tokens[$closeParenthesisIndex]['code'] === T_STRING) { + if ($beforeOpeningParenthesisIndex === false || $tokens[$beforeOpeningParenthesisIndex]['code'] !== T_ARRAY) { + if ($tokens[$beforeOpeningParenthesisIndex]['code'] === T_STRING) { return; } - // If it is not an array check what is inside. + // If it is not an array, check what is inside. $found = $phpcsFile->findPrevious( T_VARIABLE, ($previousIndex - 1), @@ -107,14 +104,14 @@ public function process(File $phpcsFile, $stackPtr) return; } - // If there is nothing inside the parenthesis, it it not a Yoda. + // If there is nothing inside the parenthesis, it is not a Yoda condition. $opener = $tokens[$previousIndex]['parenthesis_opener']; $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($previousIndex - 1), ($opener + 1), true); if ($prev === false) { return; } - } else if ($tokens[$closeParenthesisIndex]['code'] === T_ARRAY - && $this->isArrayStatic($phpcsFile, $closeParenthesisIndex) === false + } else if ($tokens[$beforeOpeningParenthesisIndex]['code'] === T_ARRAY + && $this->isArrayStatic($phpcsFile, $beforeOpeningParenthesisIndex) === false ) { return; }//end if @@ -141,7 +138,6 @@ public function isArrayStatic(File $phpcsFile, $arrayToken) { $tokens = $phpcsFile->getTokens(); - $arrayEnd = null; if ($tokens[$arrayToken]['code'] === T_OPEN_SHORT_ARRAY) { $start = $arrayToken; $end = $tokens[$arrayToken]['bracket_closer']; @@ -149,7 +145,8 @@ public function isArrayStatic(File $phpcsFile, $arrayToken) $start = $tokens[$arrayToken]['parenthesis_opener']; $end = $tokens[$arrayToken]['parenthesis_closer']; } else { - return true; + // Shouldn't be possible but may happen if external sniffs are using this method. + return true; // @codeCoverageIgnore } $staticTokens = Tokens::$emptyTokens; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/ControlStructures/InlineControlStructureSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/ControlStructures/InlineControlStructureSniff.php index 8a4884d3c..1efb15c7b 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/ControlStructures/InlineControlStructureSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/ControlStructures/InlineControlStructureSniff.php @@ -48,7 +48,6 @@ public function register() T_FOREACH, T_WHILE, T_DO, - T_SWITCH, T_FOR, ]; @@ -75,7 +74,7 @@ public function process(File $phpcsFile, $stackPtr) // Ignore the ELSE in ELSE IF. We'll process the IF part later. if ($tokens[$stackPtr]['code'] === T_ELSE) { - $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + $next = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true); if ($tokens[$next]['code'] === T_IF) { return; } @@ -95,21 +94,6 @@ public function process(File $phpcsFile, $stackPtr) return; } } - - // In Javascript DO WHILE loops without curly braces are legal. This - // is only valid if a single statement is present between the DO and - // the WHILE. We can detect this by checking only a single semicolon - // is present between them. - if ($tokens[$stackPtr]['code'] === T_WHILE && $phpcsFile->tokenizerType === 'JS') { - $lastDo = $phpcsFile->findPrevious(T_DO, ($stackPtr - 1)); - $lastSemicolon = $phpcsFile->findPrevious(T_SEMICOLON, ($stackPtr - 1)); - if ($lastDo !== false && $lastSemicolon !== false && $lastDo < $lastSemicolon) { - $precedingSemicolon = $phpcsFile->findPrevious(T_SEMICOLON, ($lastSemicolon - 1)); - if ($precedingSemicolon === false || $precedingSemicolon < $lastDo) { - return; - } - } - } }//end if if (isset($tokens[$stackPtr]['parenthesis_opener'], $tokens[$stackPtr]['parenthesis_closer']) === false @@ -150,7 +134,7 @@ public function process(File $phpcsFile, $stackPtr) // tag in short open tags and scan run with short_open_tag=Off. // Bow out completely as any further detection will be unreliable // and create incorrect fixes or cause fixer conflicts. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; } unset($nextNonEmpty, $start); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Debug/CSSLintSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Debug/CSSLintSniff.php index 2e4b25192..db0660d19 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Debug/CSSLintSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Debug/CSSLintSniff.php @@ -13,10 +13,11 @@ use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Common; -class CSSLintSniff implements Sniff +class CSSLintSniff implements Sniff, DeprecatedSniff { /** @@ -52,7 +53,7 @@ public function process(File $phpcsFile, $stackPtr) { $csslintPath = Config::getExecutablePath('csslint'); if ($csslintPath === null) { - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; } $fileName = $phpcsFile->getFilename(); @@ -61,7 +62,7 @@ public function process(File $phpcsFile, $stackPtr) exec($cmd, $output, $retval); if (is_array($output) === false) { - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; } $count = count($output); @@ -90,9 +91,45 @@ public function process(File $phpcsFile, $stackPtr) }//end for // Ignore the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning CSS files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Debug/ClosureLinterSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Debug/ClosureLinterSniff.php index 6a90533a9..8d365f287 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Debug/ClosureLinterSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Debug/ClosureLinterSniff.php @@ -13,10 +13,11 @@ use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Common; -class ClosureLinterSniff implements Sniff +class ClosureLinterSniff implements Sniff, DeprecatedSniff { /** @@ -63,13 +64,13 @@ public function register() * the token was found. * * @return int - * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If jslint.js could not be run + * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If jslint.js could not be run. */ public function process(File $phpcsFile, $stackPtr) { $lintPath = Config::getExecutablePath('gjslint'); if ($lintPath === null) { - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; } $fileName = $phpcsFile->getFilename(); @@ -79,7 +80,7 @@ public function process(File $phpcsFile, $stackPtr) exec($cmd, $output, $retval); if (is_array($output) === false) { - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; } foreach ($output as $finding) { @@ -111,9 +112,45 @@ public function process(File $phpcsFile, $stackPtr) }//end foreach // Ignore the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning JavaScript files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Debug/ESLintSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Debug/ESLintSniff.php index e62e6856c..469d63641 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Debug/ESLintSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Debug/ESLintSniff.php @@ -13,10 +13,11 @@ use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Common; -class ESLintSniff implements Sniff +class ESLintSniff implements Sniff, DeprecatedSniff { /** @@ -54,13 +55,13 @@ public function register() * the token was found. * * @return int - * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If jshint.js could not be run + * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If jshint.js could not be run. */ public function process(File $phpcsFile, $stackPtr) { $eslintPath = Config::getExecutablePath('eslint'); if ($eslintPath === null) { - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; } $filename = $phpcsFile->getFilename(); @@ -86,13 +87,13 @@ public function process(File $phpcsFile, $stackPtr) if ($code <= 0) { // No errors, continue. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; } $data = json_decode(implode("\n", $stdout)); if (json_last_error() !== JSON_ERROR_NONE) { // Ignore any errors. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; } // Data is a list of files, but we only pass a single one. @@ -107,9 +108,45 @@ public function process(File $phpcsFile, $stackPtr) } // Ignore the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning JavaScript files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Debug/JSHintSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Debug/JSHintSniff.php index 5af7f772a..66bc04e3f 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Debug/JSHintSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Debug/JSHintSniff.php @@ -14,10 +14,11 @@ use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Common; -class JSHintSniff implements Sniff +class JSHintSniff implements Sniff, DeprecatedSniff { /** @@ -48,14 +49,14 @@ public function register() * the token was found. * * @return int - * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If jshint.js could not be run + * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If jshint.js could not be run. */ public function process(File $phpcsFile, $stackPtr) { $rhinoPath = Config::getExecutablePath('rhino'); $jshintPath = Config::getExecutablePath('jshint'); if ($jshintPath === null) { - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; } $fileName = $phpcsFile->getFilename(); @@ -89,9 +90,45 @@ public function process(File $phpcsFile, $stackPtr) } // Ignore the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning JavaScript files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/ByteOrderMarkSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/ByteOrderMarkSniff.php index d01490832..5a1fde6f3 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/ByteOrderMarkSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/ByteOrderMarkSniff.php @@ -49,13 +49,13 @@ public function register() * @param int $stackPtr The position of the current token in * the stack passed in $tokens. * - * @return void + * @return int */ public function process(File $phpcsFile, $stackPtr) { // The BOM will be the very first token in the file. if ($stackPtr !== 0) { - return; + return $phpcsFile->numTokens; } $tokens = $phpcsFile->getTokens(); @@ -68,12 +68,14 @@ public function process(File $phpcsFile, $stackPtr) $error = 'File contains %s byte order mark, which may corrupt your application'; $phpcsFile->addError($error, $stackPtr, 'Found', $errorData); $phpcsFile->recordMetric($stackPtr, 'Using byte order mark', 'yes'); - return; + return $phpcsFile->numTokens; } } $phpcsFile->recordMetric($stackPtr, 'Using byte order mark', 'no'); + return $phpcsFile->numTokens; + }//end process() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/EndFileNewlineSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/EndFileNewlineSniff.php index a920bdf8a..71bcabbb7 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/EndFileNewlineSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/EndFileNewlineSniff.php @@ -76,7 +76,7 @@ public function process(File $phpcsFile, $stackPtr) } // Ignore the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; }//end process() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/EndFileNoNewlineSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/EndFileNoNewlineSniff.php index afff5587b..3f7660756 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/EndFileNoNewlineSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/EndFileNoNewlineSniff.php @@ -83,7 +83,7 @@ public function process(File $phpcsFile, $stackPtr) } // Ignore the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; }//end process() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/ExecutableFileSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/ExecutableFileSniff.php index cb199aa69..8f597dfdf 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/ExecutableFileSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/ExecutableFileSniff.php @@ -54,7 +54,7 @@ public function process(File $phpcsFile, $stackPtr) } // Ignore the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; }//end process() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/InlineHTMLSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/InlineHTMLSniff.php index 1d79a0ea7..d90b89301 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/InlineHTMLSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/InlineHTMLSniff.php @@ -54,7 +54,7 @@ public function process(File $phpcsFile, $stackPtr) { // Allow a byte-order mark. $tokens = $phpcsFile->getTokens(); - foreach ($this->bomDefinitions as $bomName => $expectedBomHex) { + foreach ($this->bomDefinitions as $expectedBomHex) { $bomByteLength = (strlen($expectedBomHex) / 2); $htmlBomHex = bin2hex(substr($tokens[0]['content'], 0, $bomByteLength)); if ($htmlBomHex === $expectedBomHex && strlen($tokens[0]['content']) === $bomByteLength) { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/LineEndingsSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/LineEndingsSniff.php index e44d5147a..1814b5555 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/LineEndingsSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/LineEndingsSniff.php @@ -68,7 +68,7 @@ public function process(File $phpcsFile, $stackPtr) if ($found === $this->eolChar) { // Ignore the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; } // Check for single line files without an EOL. This is a very special @@ -79,7 +79,7 @@ public function process(File $phpcsFile, $stackPtr) if ($tokens[$lastToken]['line'] === 1 && $tokens[$lastToken]['content'] !== "\n" ) { - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; } } @@ -140,7 +140,7 @@ public function process(File $phpcsFile, $stackPtr) }//end if // Ignore the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; }//end process() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/LineLengthSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/LineLengthSniff.php index 94d4144a1..a65baf76b 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/LineLengthSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/LineLengthSniff.php @@ -80,7 +80,7 @@ public function process(File $phpcsFile, $stackPtr) $this->checkLineLength($phpcsFile, $tokens, $i); // Ignore the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; }//end process() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/LowercasedFilenameSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/LowercasedFilenameSniff.php index 608fdcf6b..1773cb8a6 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/LowercasedFilenameSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Files/LowercasedFilenameSniff.php @@ -44,7 +44,7 @@ public function process(File $phpcsFile, $stackPtr) { $filename = $phpcsFile->getFilename(); if ($filename === 'STDIN') { - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; } $filename = basename($filename); @@ -62,7 +62,7 @@ public function process(File $phpcsFile, $stackPtr) } // Ignore the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; }//end process() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Formatting/NoSpaceAfterCastSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Formatting/NoSpaceAfterCastSniff.php index f7644df03..008d27662 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Formatting/NoSpaceAfterCastSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Formatting/NoSpaceAfterCastSniff.php @@ -13,10 +13,11 @@ namespace PHP_CodeSniffer\Standards\Generic\Sniffs\Formatting; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Tokens; -class NoSpaceAfterCastSniff implements Sniff +class NoSpaceAfterCastSniff implements Sniff, DeprecatedSniff { @@ -58,4 +59,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.4.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Use the Generic.Formatting.SpaceAfterCast sniff with the $spacing property set to 0 instead.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Functions/CallTimePassByReferenceSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Functions/CallTimePassByReferenceSniff.php index d97c0f79b..2547e238d 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Functions/CallTimePassByReferenceSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Functions/CallTimePassByReferenceSniff.php @@ -5,15 +5,18 @@ * @author Florian Grandel * @copyright 2009-2014 Florian Grandel * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + * + * @deprecated 3.12.1 */ namespace PHP_CodeSniffer\Standards\Generic\Sniffs\Functions; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Tokens; -class CallTimePassByReferenceSniff implements Sniff +class CallTimePassByReferenceSniff implements Sniff, DeprecatedSniff { @@ -27,6 +30,10 @@ public function register() return [ T_STRING, T_VARIABLE, + T_ANON_CLASS, + T_PARENT, + T_SELF, + T_STATIC, ]; }//end register() @@ -50,12 +57,12 @@ public function process(File $phpcsFile, $stackPtr) $prev = $phpcsFile->findPrevious($findTokens, ($stackPtr - 1), null, true); - // Skip tokens that are the names of functions or classes + // Skip tokens that are the names of functions // within their definitions. For example: function myFunction... // "myFunction" is T_STRING but we should skip because it is not a // function or method *call*. $prevCode = $tokens[$prev]['code']; - if ($prevCode === T_FUNCTION || $prevCode === T_CLASS) { + if ($prevCode === T_FUNCTION) { return; } @@ -69,7 +76,7 @@ public function process(File $phpcsFile, $stackPtr) true ); - if ($tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) { + if ($openBracket === false || $tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) { return; } @@ -86,10 +93,6 @@ public function process(File $phpcsFile, $stackPtr) ]; while (($nextSeparator = $phpcsFile->findNext($find, ($nextSeparator + 1), $closeBracket)) !== false) { - if (isset($tokens[$nextSeparator]['nested_parenthesis']) === false) { - continue; - } - if ($tokens[$nextSeparator]['code'] === T_OPEN_SHORT_ARRAY) { $nextSeparator = $tokens[$nextSeparator]['bracket_closer']; continue; @@ -138,4 +141,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.12.1'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return ''; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Functions/FunctionCallArgumentSpacingSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Functions/FunctionCallArgumentSpacingSniff.php index 1ae482256..bf93c5533 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Functions/FunctionCallArgumentSpacingSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Functions/FunctionCallArgumentSpacingSniff.php @@ -109,17 +109,25 @@ public function checkSpacing(File $phpcsFile, $stackPtr, $openBracket) $find = [ T_COMMA, T_CLOSURE, + T_FN, T_ANON_CLASS, T_OPEN_SHORT_ARRAY, + T_MATCH, ]; while (($nextSeparator = $phpcsFile->findNext($find, ($nextSeparator + 1), $closeBracket)) !== false) { if ($tokens[$nextSeparator]['code'] === T_CLOSURE || $tokens[$nextSeparator]['code'] === T_ANON_CLASS + || $tokens[$nextSeparator]['code'] === T_MATCH ) { - // Skip closures. + // Skip closures, anon class declarations and match control structures. $nextSeparator = $tokens[$nextSeparator]['scope_closer']; continue; + } else if ($tokens[$nextSeparator]['code'] === T_FN) { + // Skip arrow functions, but don't skip the arrow function closer as it is likely to + // be the comma separating it from the next function call argument (or the parenthesis closer). + $nextSeparator = ($tokens[$nextSeparator]['scope_closer'] - 1); + continue; } else if ($tokens[$nextSeparator]['code'] === T_OPEN_SHORT_ARRAY) { // Skips arrays using short notation. $nextSeparator = $tokens[$nextSeparator]['bracket_closer']; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceBsdAllmanSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceBsdAllmanSniff.php index be96f5858..42df278bc 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceBsdAllmanSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceBsdAllmanSniff.php @@ -152,7 +152,7 @@ public function process(File $phpcsFile, $stackPtr) for ($i = $openingBrace; $i > $prev; $i--) { if ($tokens[$i]['line'] === $tokens[$openingBrace]['line']) { if ($tokens[$i]['column'] === 1) { - $phpcsFile->fixer->addNewLineBefore($i); + $phpcsFile->fixer->addNewlineBefore($i); } continue; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php index ca259854e..d5a84982c 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Functions/OpeningFunctionBraceKernighanRitchieSniff.php @@ -72,17 +72,9 @@ public function process(File $phpcsFile, $stackPtr) } $openingBrace = $tokens[$stackPtr]['scope_opener']; - $closeBracket = $tokens[$stackPtr]['parenthesis_closer']; - if ($tokens[$stackPtr]['code'] === T_CLOSURE) { - $use = $phpcsFile->findNext(T_USE, ($closeBracket + 1), $tokens[$stackPtr]['scope_opener']); - if ($use !== false) { - $openBracket = $phpcsFile->findNext(T_OPEN_PARENTHESIS, ($use + 1)); - $closeBracket = $tokens[$openBracket]['parenthesis_closer']; - } - } // Find the end of the function declaration. - $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($openingBrace - 1), $closeBracket, true); + $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($openingBrace - 1), null, true); $functionLine = $tokens[$prev]['line']; $braceLine = $tokens[$openingBrace]['line']; @@ -99,7 +91,6 @@ public function process(File $phpcsFile, $stackPtr) $error = 'Opening brace should be on the same line as the declaration'; $fix = $phpcsFile->addFixableError($error, $openingBrace, 'BraceOnNewLine'); if ($fix === true) { - $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($openingBrace - 1), $closeBracket, true); $phpcsFile->fixer->beginChangeset(); $phpcsFile->fixer->addContent($prev, ' {'); $phpcsFile->fixer->replaceToken($openingBrace, ''); @@ -147,28 +138,32 @@ public function process(File $phpcsFile, $stackPtr) return; } - // We are looking for tabs, even if they have been replaced, because - // we enforce a space here. - if (isset($tokens[($openingBrace - 1)]['orig_content']) === true) { - $spacing = $tokens[($openingBrace - 1)]['orig_content']; - } else { - $spacing = $tokens[($openingBrace - 1)]['content']; - } - + // Enforce a single space. Tabs not allowed. + $spacing = $tokens[($openingBrace - 1)]['content']; if ($tokens[($openingBrace - 1)]['code'] !== T_WHITESPACE) { $length = 0; } else if ($spacing === "\t") { + // Tab without tab-width set, so no tab replacement has taken place. $length = '\t'; } else { $length = strlen($spacing); } + // If tab replacement is on, avoid confusing the user with a "expected 1 space, found 1" + // message when the "1" found is actually a tab, not a space. + if ($length === 1 + && isset($tokens[($openingBrace - 1)]['orig_content']) === true + && $tokens[($openingBrace - 1)]['orig_content'] === "\t" + ) { + $length = '\t'; + } + if ($length !== 1) { $error = 'Expected 1 space before opening brace; found %s'; $data = [$length]; $fix = $phpcsFile->addFixableError($error, $openingBrace, 'SpaceBeforeBrace', $data); if ($fix === true) { - if ($length === 0 || $length === '\t') { + if ($length === 0) { $phpcsFile->fixer->addContentBefore($openingBrace, ' '); } else { $phpcsFile->fixer->replaceToken(($openingBrace - 1), ' '); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php index 8cba81daf..a6b17d131 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Metrics/CyclomaticComplexitySniff.php @@ -60,8 +60,8 @@ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); - // Ignore abstract methods. - if (isset($tokens[$stackPtr]['scope_opener']) === false) { + // Ignore abstract and interface methods. Bail early when live coding. + if (isset($tokens[$stackPtr]['scope_opener'], $tokens[$stackPtr]['scope_closer']) === false) { return; } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Metrics/NestingLevelSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Metrics/NestingLevelSniff.php index 3c086c7fe..d2672b5ee 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Metrics/NestingLevelSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Metrics/NestingLevelSniff.php @@ -56,8 +56,8 @@ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); - // Ignore abstract methods. - if (isset($tokens[$stackPtr]['scope_opener']) === false) { + // Ignore abstract and interface methods. Bail early when live coding. + if (isset($tokens[$stackPtr]['scope_opener'], $tokens[$stackPtr]['scope_closer']) === false) { return; } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/NamingConventions/AbstractClassNamePrefixSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/NamingConventions/AbstractClassNamePrefixSniff.php index 145dddf74..44c16390e 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/NamingConventions/AbstractClassNamePrefixSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/NamingConventions/AbstractClassNamePrefixSniff.php @@ -45,7 +45,7 @@ public function process(File $phpcsFile, $stackPtr) $className = $phpcsFile->getDeclarationName($stackPtr); if ($className === null) { - // We are not interested in anonymous classes. + // Live coding or parse error. return; } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/NamingConventions/CamelCapsFunctionNameSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/NamingConventions/CamelCapsFunctionNameSniff.php index ec1cfd002..d596f1744 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/NamingConventions/CamelCapsFunctionNameSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/NamingConventions/CamelCapsFunctionNameSniff.php @@ -113,7 +113,7 @@ protected function processTokenWithinScope(File $phpcsFile, $stackPtr, $currScop $methodName = $phpcsFile->getDeclarationName($stackPtr); if ($methodName === null) { - // Ignore closures. + // Live coding or parse error. Bow out. return; } @@ -150,7 +150,7 @@ protected function processTokenWithinScope(File $phpcsFile, $stackPtr, $currScop return; } - // Ignore first underscore in methods prefixed with "_". + // Ignore leading underscores in the method name. $methodName = ltrim($methodName, '_'); $methodProps = $phpcsFile->getMethodProperties($stackPtr); @@ -168,7 +168,6 @@ protected function processTokenWithinScope(File $phpcsFile, $stackPtr, $currScop } $phpcsFile->recordMetric($stackPtr, 'CamelCase method name', 'no'); - return; } else { $phpcsFile->recordMetric($stackPtr, 'CamelCase method name', 'yes'); } @@ -189,7 +188,7 @@ protected function processTokenOutsideScope(File $phpcsFile, $stackPtr) { $functionName = $phpcsFile->getDeclarationName($stackPtr); if ($functionName === null) { - // Ignore closures. + // Live coding or parse error. Bow out. return; } @@ -206,7 +205,7 @@ protected function processTokenOutsideScope(File $phpcsFile, $stackPtr) $phpcsFile->addError($error, $stackPtr, 'FunctionDoubleUnderscore', $errorData); } - // Ignore first underscore in functions prefixed with "_". + // Ignore leading underscores in the method name. $functionName = ltrim($functionName, '_'); if (Common::isCamelCaps($functionName, false, true, $this->strict) === false) { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/NamingConventions/ConstructorNameSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/NamingConventions/ConstructorNameSniff.php index 75fbd2264..e87f066b3 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/NamingConventions/ConstructorNameSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/NamingConventions/ConstructorNameSniff.php @@ -15,6 +15,7 @@ use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\AbstractScopeSniff; +use PHP_CodeSniffer\Util\Tokens; class ConstructorNameSniff extends AbstractScopeSniff { @@ -77,8 +78,13 @@ protected function processTokenWithinScope(File $phpcsFile, $stackPtr, $currScop $this->currentClass = $className; } - $methodName = strtolower($phpcsFile->getDeclarationName($stackPtr)); + $methodName = $phpcsFile->getDeclarationName($stackPtr); + if ($methodName === null) { + // Live coding or parse error. Bow out. + return; + } + $methodName = strtolower($methodName); if ($methodName === $className) { if (in_array('__construct', $this->functionList, true) === false) { $error = 'PHP4 style constructors are not allowed; use "__construct()" instead'; @@ -90,27 +96,41 @@ protected function processTokenWithinScope(File $phpcsFile, $stackPtr, $currScop } // Stop if the constructor doesn't have a body, like when it is abstract. - if (isset($tokens[$stackPtr]['scope_closer']) === false) { + if (isset($tokens[$stackPtr]['scope_opener'], $tokens[$stackPtr]['scope_closer']) === false) { return; } - $parentClassName = strtolower($phpcsFile->findExtendedClassName($currScope)); + $parentClassName = $phpcsFile->findExtendedClassName($currScope); if ($parentClassName === false) { return; } + $parentClassNameLc = strtolower($parentClassName); + $endFunctionIndex = $tokens[$stackPtr]['scope_closer']; - $startIndex = $stackPtr; - while (($doubleColonIndex = $phpcsFile->findNext(T_DOUBLE_COLON, $startIndex, $endFunctionIndex)) !== false) { - if ($tokens[($doubleColonIndex + 1)]['code'] === T_STRING - && strtolower($tokens[($doubleColonIndex + 1)]['content']) === $parentClassName + $startIndex = $tokens[$stackPtr]['scope_opener']; + while (($doubleColonIndex = $phpcsFile->findNext(T_DOUBLE_COLON, ($startIndex + 1), $endFunctionIndex)) !== false) { + $nextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, ($doubleColonIndex + 1), null, true); + if ($tokens[$nextNonEmpty]['code'] !== T_STRING + || strtolower($tokens[$nextNonEmpty]['content']) !== $parentClassNameLc + ) { + $startIndex = $nextNonEmpty; + continue; + } + + $prevNonEmpty = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($doubleColonIndex - 1), null, true); + if ($tokens[$prevNonEmpty]['code'] === T_PARENT + || $tokens[$prevNonEmpty]['code'] === T_SELF + || $tokens[$prevNonEmpty]['code'] === T_STATIC + || ($tokens[$prevNonEmpty]['code'] === T_STRING + && strtolower($tokens[$prevNonEmpty]['content']) === $parentClassNameLc) ) { $error = 'PHP4 style calls to parent constructors are not allowed; use "parent::__construct()" instead'; - $phpcsFile->addError($error, ($doubleColonIndex + 1), 'OldStyleCall'); + $phpcsFile->addError($error, $nextNonEmpty, 'OldStyleCall'); } - $startIndex = ($doubleColonIndex + 1); - } + $startIndex = $nextNonEmpty; + }//end while }//end processTokenWithinScope() @@ -149,7 +169,13 @@ protected function loadFunctionNamesInScope(File $phpcsFile, $currScope) continue; } - $this->functionList[] = trim(strtolower($phpcsFile->getDeclarationName($i))); + $methodName = $phpcsFile->getDeclarationName($i); + if ($methodName === null) { + // Live coding or parse error. Ignore. + continue; + } + + $this->functionList[] = trim(strtolower($methodName)); if (isset($tokens[$i]['scope_closer']) !== false) { // Skip past nested functions and such. diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/NamingConventions/InterfaceNameSuffixSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/NamingConventions/InterfaceNameSuffixSniff.php index 637e036f1..6dfad6b40 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/NamingConventions/InterfaceNameSuffixSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/NamingConventions/InterfaceNameSuffixSniff.php @@ -40,6 +40,7 @@ public function process(File $phpcsFile, $stackPtr) { $interfaceName = $phpcsFile->getDeclarationName($stackPtr); if ($interfaceName === null) { + // Live coding or parse error. Bow out. return; } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/NamingConventions/TraitNameSuffixSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/NamingConventions/TraitNameSuffixSniff.php index cbd9651dd..79a77557d 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/NamingConventions/TraitNameSuffixSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/NamingConventions/TraitNameSuffixSniff.php @@ -40,6 +40,7 @@ public function process(File $phpcsFile, $stackPtr) { $traitName = $phpcsFile->getDeclarationName($stackPtr); if ($traitName === null) { + // Live coding or parse error. Bow out. return; } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php index f62cfe94b..41b5b6124 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php @@ -87,39 +87,41 @@ public function process(File $phpcsFile, $stackPtr) return; } - // Make sure this is not a method call. - $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + // Make sure this is not a method call or class instantiation. + $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); if ($tokens[$prev]['code'] === T_OBJECT_OPERATOR || $tokens[$prev]['code'] === T_DOUBLE_COLON || $tokens[$prev]['code'] === T_NULLSAFE_OBJECT_OPERATOR + || $tokens[$prev]['code'] === T_NEW ) { return; } + // Make sure this is not an attribute. + if (empty($tokens[$stackPtr]['nested_attributes']) === false) { + return; + } + // If the next non-whitespace token after this token // is not an opening parenthesis then it is not a function call. $openBracket = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true); - if ($openBracket === false) { + if ($openBracket === false || $tokens[$openBracket]['code'] !== T_OPEN_PARENTHESIS) { return; } - // The next non-whitespace token must be the constant name. - $constPtr = $phpcsFile->findNext(T_WHITESPACE, ($openBracket + 1), null, true); - if ($tokens[$constPtr]['code'] !== T_CONSTANT_ENCAPSED_STRING) { + // Bow out if next non-empty token after the opening parenthesis is not a string (the + // constant name). This could happen when live coding, if the constant is a variable or an + // expression, or if handling a first-class callable or a function definition outside the + // global scope. + $constPtr = $phpcsFile->findNext(Tokens::$emptyTokens, ($openBracket + 1), null, true); + if ($constPtr === false || $tokens[$constPtr]['code'] !== T_CONSTANT_ENCAPSED_STRING) { return; } $constName = $tokens[$constPtr]['content']; + $prefix = ''; - // Check for constants like self::CONSTANT. - $prefix = ''; - $splitPos = strpos($constName, '::'); - if ($splitPos !== false) { - $prefix = substr($constName, 0, ($splitPos + 2)); - $constName = substr($constName, ($splitPos + 2)); - } - - // Strip namespace from constant like /foo/bar/CONSTANT. + // Strip namespace from constant like \foo\bar\CONSTANT. $splitPos = strrpos($constName, '\\'); if ($splitPos !== false) { $prefix = substr($constName, 0, ($splitPos + 1)); @@ -128,9 +130,9 @@ public function process(File $phpcsFile, $stackPtr) if (strtoupper($constName) !== $constName) { if (strtolower($constName) === $constName) { - $phpcsFile->recordMetric($stackPtr, 'Constant name case', 'lower'); + $phpcsFile->recordMetric($constPtr, 'Constant name case', 'lower'); } else { - $phpcsFile->recordMetric($stackPtr, 'Constant name case', 'mixed'); + $phpcsFile->recordMetric($constPtr, 'Constant name case', 'mixed'); } $error = 'Constants must be uppercase; expected %s but found %s'; @@ -138,9 +140,9 @@ public function process(File $phpcsFile, $stackPtr) $prefix.strtoupper($constName), $prefix.$constName, ]; - $phpcsFile->addError($error, $stackPtr, 'ConstantNotUpperCase', $data); + $phpcsFile->addError($error, $constPtr, 'ConstantNotUpperCase', $data); } else { - $phpcsFile->recordMetric($stackPtr, 'Constant name case', 'upper'); + $phpcsFile->recordMetric($constPtr, 'Constant name case', 'upper'); } }//end process() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/CharacterBeforePHPOpeningTagSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/CharacterBeforePHPOpeningTagSniff.php index 66f73860e..61ff4f2f0 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/CharacterBeforePHPOpeningTagSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/CharacterBeforePHPOpeningTagSniff.php @@ -56,7 +56,7 @@ public function process(File $phpcsFile, $stackPtr) if ($stackPtr > 0) { // Allow a byte-order mark. $tokens = $phpcsFile->getTokens(); - foreach ($this->bomDefinitions as $bomName => $expectedBomHex) { + foreach ($this->bomDefinitions as $expectedBomHex) { $bomByteLength = (strlen($expectedBomHex) / 2); $htmlBomHex = bin2hex(substr($tokens[0]['content'], 0, $bomByteLength)); if ($htmlBomHex === $expectedBomHex) { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/DeprecatedFunctionsSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/DeprecatedFunctionsSniff.php index 83f38898c..44efd53af 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/DeprecatedFunctionsSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/DeprecatedFunctionsSniff.php @@ -10,6 +10,8 @@ namespace PHP_CodeSniffer\Standards\Generic\Sniffs\PHP; +use ReflectionFunction; + class DeprecatedFunctionsSniff extends ForbiddenFunctionsSniff { @@ -34,7 +36,7 @@ public function __construct() $functions = get_defined_functions(); foreach ($functions['internal'] as $functionName) { - $function = new \ReflectionFunction($functionName); + $function = new ReflectionFunction($functionName); if ($function->isDeprecated() === true) { $this->forbiddenFunctions[$functionName] = null; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/DisallowShortOpenTagSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/DisallowShortOpenTagSniff.php index 7d68ac9e5..0355216a2 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/DisallowShortOpenTagSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/DisallowShortOpenTagSniff.php @@ -74,18 +74,20 @@ public function process(File $phpcsFile, $stackPtr) if ($token['code'] === T_OPEN_TAG_WITH_ECHO) { $nextVar = $tokens[$phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true)]; - $error = 'Short PHP opening tag used with echo; expected "addFixableError($error, $stackPtr, 'EchoFound', $data); - if ($fix === true) { - if ($tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE) { - $phpcsFile->fixer->replaceToken($stackPtr, 'fixer->replaceToken($stackPtr, 'addFixableError($error, $stackPtr, 'EchoFound', $data); + if ($fix === true) { + if ($tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE) { + $phpcsFile->fixer->replaceToken($stackPtr, 'fixer->replaceToken($stackPtr, ' true, ]; - $prevToken = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + $prevToken = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); // If function call is directly preceded by a NS_SEPARATOR it points to the // global namespace, so we should still catch it. if ($tokens[$prevToken]['code'] === T_NS_SEPARATOR) { - $prevToken = $phpcsFile->findPrevious(T_WHITESPACE, ($prevToken - 1), null, true); + $prevToken = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($prevToken - 1), null, true); if ($tokens[$prevToken]['code'] === T_STRING) { // Not in the global namespace. return; @@ -152,7 +153,7 @@ public function process(File $phpcsFile, $stackPtr) return; } - $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + $nextToken = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true); if (isset($ignore[$tokens[$nextToken]['code']]) === true) { // Not a call to a PHP function. return; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/LowerCaseConstantSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/LowerCaseConstantSniff.php index 4447f4630..29e184ec6 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/LowerCaseConstantSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/LowerCaseConstantSniff.php @@ -43,21 +43,23 @@ class LowerCaseConstantSniff implements Sniff * @var array */ private $propertyTypeTokens = [ - T_CALLABLE => T_CALLABLE, - T_SELF => T_SELF, - T_PARENT => T_PARENT, - T_FALSE => T_FALSE, - T_TRUE => T_TRUE, - T_NULL => T_NULL, - T_STRING => T_STRING, - T_NAME_QUALIFIED => T_NAME_QUALIFIED, - T_NAME_FULLY_QUALIFIED => T_NAME_FULLY_QUALIFIED, - T_NAME_RELATIVE => T_NAME_RELATIVE, - T_NS_SEPARATOR => T_NS_SEPARATOR, - T_NAMESPACE => T_NAMESPACE, - T_TYPE_UNION => T_TYPE_UNION, - T_TYPE_INTERSECTION => T_TYPE_INTERSECTION, - T_NULLABLE => T_NULLABLE, + T_CALLABLE => T_CALLABLE, + T_SELF => T_SELF, + T_PARENT => T_PARENT, + T_FALSE => T_FALSE, + T_TRUE => T_TRUE, + T_NULL => T_NULL, + T_STRING => T_STRING, + T_NAME_QUALIFIED => T_NAME_QUALIFIED, + T_NAME_FULLY_QUALIFIED => T_NAME_FULLY_QUALIFIED, + T_NAME_RELATIVE => T_NAME_RELATIVE, + T_NS_SEPARATOR => T_NS_SEPARATOR, + T_NAMESPACE => T_NAMESPACE, + T_TYPE_UNION => T_TYPE_UNION, + T_TYPE_INTERSECTION => T_TYPE_INTERSECTION, + T_TYPE_OPEN_PARENTHESIS => T_TYPE_OPEN_PARENTHESIS, + T_TYPE_CLOSE_PARENTHESIS => T_TYPE_CLOSE_PARENTHESIS, + T_NULLABLE => T_NULLABLE, ]; @@ -75,6 +77,7 @@ public function register() $targets[] = T_VAR; $targets[] = T_STATIC; $targets[] = T_READONLY; + $targets[] = T_FINAL; // Register function keywords to filter out param/return type declarations. $targets[] = T_FUNCTION; @@ -135,6 +138,7 @@ public function process(File $phpcsFile, $stackPtr) || $tokens[$stackPtr]['code'] === T_VAR || $tokens[$stackPtr]['code'] === T_STATIC || $tokens[$stackPtr]['code'] === T_READONLY + || $tokens[$stackPtr]['code'] === T_FINAL ) { $skipOver = (Tokens::$emptyTokens + $this->propertyTypeTokens); $skipTo = $phpcsFile->findNext($skipOver, ($stackPtr + 1), null, true); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/LowerCaseKeywordSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/LowerCaseKeywordSniff.php index 1a3691717..c547fa989 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/LowerCaseKeywordSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/LowerCaseKeywordSniff.php @@ -27,15 +27,15 @@ public function register() { $targets = Tokens::$contextSensitiveKeywords; $targets += [ + T_ANON_CLASS => T_ANON_CLASS, T_CLOSURE => T_CLOSURE, - T_EMPTY => T_EMPTY, T_ENUM_CASE => T_ENUM_CASE, - T_EVAL => T_EVAL, - T_ISSET => T_ISSET, T_MATCH_DEFAULT => T_MATCH_DEFAULT, T_PARENT => T_PARENT, T_SELF => T_SELF, - T_UNSET => T_UNSET, + T_PUBLIC_SET => T_PUBLIC_SET, + T_PROTECTED_SET => T_PROTECTED_SET, + T_PRIVATE_SET => T_PRIVATE_SET, ]; return $targets; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/LowerCaseTypeSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/LowerCaseTypeSniff.php index 7fb3b8584..1b085853e 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/LowerCaseTypeSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/LowerCaseTypeSniff.php @@ -132,31 +132,11 @@ public function process(File $phpcsFile, $stackPtr) if ($startOfType !== $constName) { $endOfType = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($constName - 1), null, true); - $type = ''; - $isUnionType = false; - $isIntersectionType = false; - for ($j = $startOfType; $j <= $endOfType; $j++) { - if (isset($ignore[$tokens[$j]['code']]) === true) { - continue; - } - - if ($tokens[$j]['code'] === T_TYPE_UNION) { - $isUnionType = true; - } - - if ($tokens[$j]['code'] === T_TYPE_INTERSECTION) { - $isIntersectionType = true; - } - - $type .= $tokens[$j]['content']; - } - $error = 'PHP constant type declarations must be lowercase; expected "%s" but found "%s"'; $errorCode = 'ConstantTypeFound'; - if ($isIntersectionType === true) { - // Intersection types don't support simple types. - } else if ($isUnionType === true) { + if ($startOfType !== $endOfType) { + // Multi-token type. $this->processUnionType( $phpcsFile, $startOfType, @@ -164,8 +144,11 @@ public function process(File $phpcsFile, $stackPtr) $error, $errorCode ); - } else if (isset($this->phpTypes[strtolower($type)]) === true) { - $this->processType($phpcsFile, $startOfType, $type, $error, $errorCode); + } else { + $type = $tokens[$startOfType]['content']; + if (isset($this->phpTypes[strtolower($type)]) === true) { + $this->processType($phpcsFile, $startOfType, $type, $error, $errorCode); + } } }//end if @@ -195,9 +178,8 @@ public function process(File $phpcsFile, $stackPtr) $error = 'PHP property type declarations must be lowercase; expected "%s" but found "%s"'; $errorCode = 'PropertyTypeFound'; - if (strpos($type, '&') !== false) { - // Intersection types don't support simple types. - } else if (strpos($type, '|') !== false) { + if ($props['type_token'] !== $props['type_end_token']) { + // Multi-token type. $this->processUnionType( $phpcsFile, $props['type_token'], @@ -227,9 +209,8 @@ public function process(File $phpcsFile, $stackPtr) $error = 'PHP return type declarations must be lowercase; expected "%s" but found "%s"'; $errorCode = 'ReturnTypeFound'; - if (strpos($returnType, '&') !== false) { - // Intersection types don't support simple types. - } else if (strpos($returnType, '|') !== false) { + if ($props['return_type_token'] !== $props['return_type_end_token']) { + // Multi-token type. $this->processUnionType( $phpcsFile, $props['return_type_token'], @@ -259,9 +240,8 @@ public function process(File $phpcsFile, $stackPtr) $error = 'PHP parameter type declarations must be lowercase; expected "%s" but found "%s"'; $errorCode = 'ParamTypeFound'; - if (strpos($typeHint, '&') !== false) { - // Intersection types don't support simple types. - } else if (strpos($typeHint, '|') !== false) { + if ($param['type_hint_token'] !== $param['type_hint_end_token']) { + // Multi-token type. $this->processUnionType( $phpcsFile, $param['type_hint_token'], @@ -279,7 +259,9 @@ public function process(File $phpcsFile, $stackPtr) /** - * Processes a union type declaration. + * Processes a multi-token type declaration. + * + * {@internal The method name is superseded by the reality, but changing it would be a BC-break.} * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $typeDeclStart The position of the start of the type token. @@ -291,37 +273,51 @@ public function process(File $phpcsFile, $stackPtr) */ protected function processUnionType(File $phpcsFile, $typeDeclStart, $typeDeclEnd, $error, $errorCode) { - $tokens = $phpcsFile->getTokens(); - $current = $typeDeclStart; - - do { - $endOfType = $phpcsFile->findNext(T_TYPE_UNION, $current, $typeDeclEnd); - if ($endOfType === false) { - // This must be the last type in the union. - $endOfType = ($typeDeclEnd + 1); - } + $tokens = $phpcsFile->getTokens(); + $typeTokenCount = 0; + $typeStart = null; + $type = ''; - $hasNsSep = $phpcsFile->findNext(T_NS_SEPARATOR, $current, $endOfType); - if ($hasNsSep !== false) { - // Multi-token class based type. Ignore. - $current = ($endOfType + 1); + for ($i = $typeDeclStart; $i <= $typeDeclEnd; $i++) { + if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) { continue; } - // Type consisting of a single token. - $startOfType = $phpcsFile->findNext(Tokens::$emptyTokens, $current, $endOfType, true); - if ($startOfType === false) { - // Parse error. - return; + if ($tokens[$i]['code'] === T_TYPE_UNION + || $tokens[$i]['code'] === T_TYPE_INTERSECTION + || $tokens[$i]['code'] === T_TYPE_OPEN_PARENTHESIS + || $tokens[$i]['code'] === T_TYPE_CLOSE_PARENTHESIS + ) { + if ($typeTokenCount === 1 + && $type !== '' + && isset($this->phpTypes[strtolower($type)]) === true + ) { + $this->processType($phpcsFile, $typeStart, $type, $error, $errorCode); + } + + // Reset for the next type in the type string. + $typeTokenCount = 0; + $typeStart = null; + $type = ''; + + continue; } - $type = $tokens[$startOfType]['content']; - if (isset($this->phpTypes[strtolower($type)]) === true) { - $this->processType($phpcsFile, $startOfType, $type, $error, $errorCode); + if (isset($typeStart) === false) { + $typeStart = $i; } - $current = ($endOfType + 1); - } while ($current <= $typeDeclEnd); + ++$typeTokenCount; + $type .= $tokens[$i]['content']; + }//end for + + // Handle type at end of type string. + if ($typeTokenCount === 1 + && $type !== '' + && isset($this->phpTypes[strtolower($type)]) === true + ) { + $this->processType($phpcsFile, $typeStart, $type, $error, $errorCode); + } }//end processUnionType() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/SyntaxSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/SyntaxSniff.php index 000511273..7297ebc13 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/SyntaxSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/PHP/SyntaxSniff.php @@ -67,7 +67,7 @@ public function process(File $phpcsFile, $stackPtr) } // Ignore the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; }//end process() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Strings/UnnecessaryHeredocSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Strings/UnnecessaryHeredocSniff.php new file mode 100644 index 000000000..aa81dc2ec --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Strings/UnnecessaryHeredocSniff.php @@ -0,0 +1,145 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Standards\Generic\Sniffs\Strings; + +use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\Sniff; + +class UnnecessaryHeredocSniff implements Sniff +{ + + /** + * Escape chars which are supported in heredocs, but not in nowdocs. + * + * @var array + */ + private $escapeChars = [ + // Octal sequences. + '\0', + '\1', + '\2', + '\3', + '\4', + '\5', + '\6', + '\7', + + // Various whitespace and the escape char. + '\n', + '\r', + '\t', + '\v', + '\e', + '\f', + + // Hex and unicode sequences. + '\x', + '\u', + ]; + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return [T_START_HEREDOC]; + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if (isset($tokens[$stackPtr]['scope_closer']) === false) { + // Just to be safe. Shouldn't be possible as in that case, the opener shouldn't be tokenized + // to T_START_HEREDOC by PHP. + return; // @codeCoverageIgnore + } + + $closer = $tokens[$stackPtr]['scope_closer']; + $body = ''; + + // Collect all the tokens within the heredoc body. + for ($i = ($stackPtr + 1); $i < $closer; $i++) { + $body .= $tokens[$i]['content']; + } + + $tokenizedBody = token_get_all(sprintf("", $body)); + foreach ($tokenizedBody as $ptr => $bodyToken) { + if (is_array($bodyToken) === false) { + continue; + } + + if ($bodyToken[0] === T_DOLLAR_OPEN_CURLY_BRACES + || $bodyToken[0] === T_VARIABLE + ) { + // Contains interpolation or expression. + $phpcsFile->recordMetric($stackPtr, 'Heredoc contains interpolation or expression', 'yes'); + return; + } + + if ($bodyToken[0] === T_CURLY_OPEN + && is_array($tokenizedBody[($ptr + 1)]) === false + && $tokenizedBody[($ptr + 1)] === '$' + ) { + // Contains interpolation or expression. + $phpcsFile->recordMetric($stackPtr, 'Heredoc contains interpolation or expression', 'yes'); + return; + } + }//end foreach + + $phpcsFile->recordMetric($stackPtr, 'Heredoc contains interpolation or expression', 'no'); + + // Check for escape sequences which aren't supported in nowdocs. + foreach ($this->escapeChars as $testChar) { + if (strpos($body, $testChar) !== false) { + return; + } + } + + $warning = 'Detected heredoc without interpolation or expressions. Use nowdoc syntax instead'; + + $fix = $phpcsFile->addFixableWarning($warning, $stackPtr, 'Found'); + if ($fix === true) { + $phpcsFile->fixer->beginChangeset(); + + $identifier = trim(ltrim($tokens[$stackPtr]['content'], '<')); + $replaceWith = "'".trim($identifier, '"')."'"; + $replacement = str_replace($identifier, $replaceWith, $tokens[$stackPtr]['content']); + $phpcsFile->fixer->replaceToken($stackPtr, $replacement); + + for ($i = ($stackPtr + 1); $i < $closer; $i++) { + $content = $tokens[$i]['content']; + $content = str_replace(['\\$', '\\\\'], ['$', '\\'], $content); + if ($tokens[$i]['content'] !== $content) { + $phpcsFile->fixer->replaceToken($i, $content); + } + } + + $phpcsFile->fixer->endChangeset(); + } + + }//end process() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Strings/UnnecessaryStringConcatSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Strings/UnnecessaryStringConcatSniff.php index ffaa1db12..033a6e7b3 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Strings/UnnecessaryStringConcatSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/Strings/UnnecessaryStringConcatSniff.php @@ -70,54 +70,58 @@ public function register() */ public function process(File $phpcsFile, $stackPtr) { - // Work out which type of file this is for. $tokens = $phpcsFile->getTokens(); - if ($tokens[$stackPtr]['code'] === T_STRING_CONCAT) { - if ($phpcsFile->tokenizerType === 'JS') { - return; - } - } else { - if ($phpcsFile->tokenizerType === 'PHP') { - return; - } + + if ($tokens[$stackPtr]['code'] === T_STRING_CONCAT && $phpcsFile->tokenizerType === 'JS') { + // JS uses T_PLUS for string concatenation, not T_STRING_CONCAT. + return; + } else if ($tokens[$stackPtr]['code'] === T_PLUS && $phpcsFile->tokenizerType === 'PHP') { + // PHP uses T_STRING_CONCAT for string concatenation, not T_PLUS. + return; } $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); $next = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); - if ($prev === false || $next === false) { + if ($next === false) { + return; + } + + if (isset(Tokens::$stringTokens[$tokens[$prev]['code']]) === false + || isset(Tokens::$stringTokens[$tokens[$next]['code']]) === false + ) { + // Bow out as at least one of the two tokens being concatenated is not a string. return; } - if (isset(Tokens::$stringTokens[$tokens[$prev]['code']]) === true - && isset(Tokens::$stringTokens[$tokens[$next]['code']]) === true + if ($tokens[$prev]['content'][0] !== $tokens[$next]['content'][0]) { + // Bow out as the two strings are not of the same type. + return; + } + + // Before we throw an error for PHP, allow strings to be + // combined if they would have < and ? next to each other because + // this trick is sometimes required in PHP strings. + if ($phpcsFile->tokenizerType === 'PHP') { + $prevChar = substr($tokens[$prev]['content'], -2, 1); + $nextChar = $tokens[$next]['content'][1]; + $combined = $prevChar.$nextChar; + if ($combined === '?'.'>' || $combined === '<'.'?') { + return; + } + } + + if ($this->allowMultiline === true + && $tokens[$prev]['line'] !== $tokens[$next]['line'] ) { - if ($tokens[$prev]['content'][0] === $tokens[$next]['content'][0]) { - // Before we throw an error for PHP, allow strings to be - // combined if they would have < and ? next to each other because - // this trick is sometimes required in PHP strings. - if ($phpcsFile->tokenizerType === 'PHP') { - $prevChar = substr($tokens[$prev]['content'], -2, 1); - $nextChar = $tokens[$next]['content'][1]; - $combined = $prevChar.$nextChar; - if ($combined === '?'.'>' || $combined === '<'.'?') { - return; - } - } - - if ($this->allowMultiline === true - && $tokens[$prev]['line'] !== $tokens[$next]['line'] - ) { - return; - } - - $error = 'String concat is not required here; use a single string instead'; - if ($this->error === true) { - $phpcsFile->addError($error, $stackPtr, 'Found'); - } else { - $phpcsFile->addWarning($error, $stackPtr, 'Found'); - } - }//end if - }//end if + return; + } + + $error = 'String concat is not required here; use a single string instead'; + if ($this->error === true) { + $phpcsFile->addError($error, $stackPtr, 'Found'); + } else { + $phpcsFile->addWarning($error, $stackPtr, 'Found'); + } }//end process() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/VersionControl/GitMergeConflictSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/VersionControl/GitMergeConflictSniff.php index 4a573b068..67ca59ae9 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/VersionControl/GitMergeConflictSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/VersionControl/GitMergeConflictSniff.php @@ -220,7 +220,7 @@ public function process(File $phpcsFile, $stackPtr) }//end for // Ignore the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; }//end process() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/VersionControl/SubversionPropertiesSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/VersionControl/SubversionPropertiesSniff.php index 446ee9819..3e6c5fe1f 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/VersionControl/SubversionPropertiesSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/VersionControl/SubversionPropertiesSniff.php @@ -58,7 +58,7 @@ public function process(File $phpcsFile, $stackPtr) $properties = $this->getProperties($path); if ($properties === null) { // Not under version control. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; } $allProperties = ($properties + $this->properties); @@ -101,7 +101,7 @@ public function process(File $phpcsFile, $stackPtr) }//end foreach // Ignore the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; }//end process() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/WhiteSpace/DisallowSpaceIndentSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/WhiteSpace/DisallowSpaceIndentSniff.php index e812500e5..37edfc887 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/WhiteSpace/DisallowSpaceIndentSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/WhiteSpace/DisallowSpaceIndentSniff.php @@ -78,6 +78,8 @@ public function process(File $phpcsFile, $stackPtr) T_INLINE_HTML => true, T_DOC_COMMENT_WHITESPACE => true, T_COMMENT => true, + T_END_HEREDOC => true, + T_END_NOWDOC => true, ]; $eolLen = strlen($phpcsFile->eolChar); @@ -202,8 +204,18 @@ public function process(File $phpcsFile, $stackPtr) } }//end if - $error = 'Tabs must be used to indent lines; spaces are not allowed'; - $fix = $phpcsFile->addFixableError($error, $i, 'SpacesUsed'); + $error = 'Tabs must be used to indent lines; spaces are not allowed'; + $errorCode = 'SpacesUsed'; + + // Report, but don't auto-fix space identation for a PHP 7.3+ flexible heredoc/nowdoc closer. + // Auto-fixing this would cause parse errors as the indentation of the heredoc/nowdoc contents + // needs to use the same type of indentation. Also see: https://3v4l.org/7OF3M . + if ($tokens[$i]['code'] === T_END_HEREDOC || $tokens[$i]['code'] === T_END_NOWDOC) { + $phpcsFile->addError($error, $i, $errorCode.'HeredocCloser'); + continue; + } + + $fix = $phpcsFile->addFixableError($error, $i, $errorCode); if ($fix === true) { $padding = str_repeat("\t", $expectedTabs); $padding .= str_repeat(' ', $expectedSpaces); @@ -212,7 +224,7 @@ public function process(File $phpcsFile, $stackPtr) }//end for // Ignore the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; }//end process() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/WhiteSpace/DisallowTabIndentSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/WhiteSpace/DisallowTabIndentSniff.php index 51a859e84..b33a58b46 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/WhiteSpace/DisallowTabIndentSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/WhiteSpace/DisallowTabIndentSniff.php @@ -78,6 +78,7 @@ public function process(File $phpcsFile, $stackPtr) T_COMMENT => true, T_END_HEREDOC => true, T_END_NOWDOC => true, + T_YIELD_FROM => true, ]; for ($i = 0; $i < $phpcsFile->numTokens; $i++) { @@ -169,6 +170,14 @@ public function process(File $phpcsFile, $stackPtr) continue; } + // Report, but don't auto-fix tab identation for a PHP 7.3+ flexible heredoc/nowdoc closer. + // Auto-fixing this would cause parse errors as the indentation of the heredoc/nowdoc contents + // needs to use the same type of indentation. Also see: https://3v4l.org/7OF3M . + if ($tokens[$i]['code'] === T_END_HEREDOC || $tokens[$i]['code'] === T_END_NOWDOC) { + $phpcsFile->addError($error, $i, $errorCode.'HeredocCloser'); + continue; + } + $fix = $phpcsFile->addFixableError($error, $i, $errorCode); if ($fix === true) { if (isset($tokens[$i]['orig_content']) === true) { @@ -184,7 +193,7 @@ public function process(File $phpcsFile, $stackPtr) }//end for // Ignore the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; }//end process() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/WhiteSpace/HereNowdocIdentifierSpacingSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/WhiteSpace/HereNowdocIdentifierSpacingSniff.php new file mode 100644 index 000000000..ca595743d --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/WhiteSpace/HereNowdocIdentifierSpacingSniff.php @@ -0,0 +1,69 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace; + +use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\Sniff; + +class HereNowdocIdentifierSpacingSniff implements Sniff +{ + + + /** + * Returns an array of tokens this test wants to listen for. + * + * @return array + */ + public function register() + { + return [ + T_START_HEREDOC, + T_START_NOWDOC, + ]; + + }//end register() + + + /** + * Processes this test, when one of its tokens is encountered. + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in + * the stack passed in $tokens. + * + * @return void + */ + public function process(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + if (strpos($tokens[$stackPtr]['content'], ' ') === false + && strpos($tokens[$stackPtr]['content'], "\t") === false + ) { + // Nothing to do. + $phpcsFile->recordMetric($stackPtr, 'Heredoc/nowdoc identifier', 'no space between <<< and ID'); + return; + } + + $phpcsFile->recordMetric($stackPtr, 'Heredoc/nowdoc identifier', 'space between <<< and ID'); + + $error = 'There should be no space between the <<< and the heredoc/nowdoc identifier string. Found: %s'; + $data = [$tokens[$stackPtr]['content']]; + + $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpaceFound', $data); + if ($fix === true) { + $replacement = str_replace([' ', "\t"], '', $tokens[$stackPtr]['content']); + $phpcsFile->fixer->replaceToken($stackPtr, $replacement); + } + + }//end process() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/WhiteSpace/LanguageConstructSpacingSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/WhiteSpace/LanguageConstructSpacingSniff.php index 462027d3d..90b311799 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/WhiteSpace/LanguageConstructSpacingSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/WhiteSpace/LanguageConstructSpacingSniff.php @@ -39,6 +39,7 @@ public function register() T_THROW, T_NAMESPACE, T_USE, + T_GOTO, ]; }//end register() @@ -51,7 +52,8 @@ public function register() * @param int $stackPtr The position of the current token in * the stack passed in $tokens. * - * @return void + * @return int|void Integer stack pointer to skip forward or void to continue + * normal file processing. */ public function process(File $phpcsFile, $stackPtr) { @@ -80,42 +82,57 @@ public function process(File $phpcsFile, $stackPtr) if ($tokens[$stackPtr]['code'] === T_YIELD_FROM && strtolower($content) !== 'yield from' ) { - if ($tokens[($stackPtr - 1)]['code'] === T_YIELD_FROM) { - // A multi-line statements that has already been processed. - return; - } + $found = $content; + $hasComment = false; + $yieldFromEnd = $stackPtr; + + // Handle potentially multi-line/multi-token "yield from" expressions. + if (preg_match('`yield\s+from`i', $content) !== 1) { + for ($i = ($stackPtr + 1); $i < $phpcsFile->numTokens; $i++) { + if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === false + && $tokens[$i]['code'] !== T_YIELD_FROM + ) { + break; + } + + if (isset(Tokens::$commentTokens[$tokens[$i]['code']]) === true) { + $hasComment = true; + } - $found = $content; - if ($tokens[($stackPtr + 1)]['code'] === T_YIELD_FROM) { - // This yield from statement is split over multiple lines. - $i = ($stackPtr + 1); - do { $found .= $tokens[$i]['content']; - $i++; - } while ($tokens[$i]['code'] === T_YIELD_FROM); - } + + if ($tokens[$i]['code'] === T_YIELD_FROM + && strtolower(trim($tokens[$i]['content'])) === 'from' + ) { + break; + } + } + + $yieldFromEnd = $i; + }//end if $error = 'Language constructs must be followed by a single space; expected 1 space between YIELD FROM found "%s"'; $data = [Common::prepareForOutput($found)]; - $fix = $phpcsFile->addFixableError($error, $stackPtr, 'IncorrectYieldFrom', $data); - if ($fix === true) { - preg_match('/yield/i', $found, $yield); - preg_match('/from/i', $found, $from); - $phpcsFile->fixer->beginChangeset(); - $phpcsFile->fixer->replaceToken($stackPtr, $yield[0].' '.$from[0]); - - if ($tokens[($stackPtr + 1)]['code'] === T_YIELD_FROM) { - $i = ($stackPtr + 1); - do { + + if ($hasComment === true) { + $phpcsFile->addError($error, $stackPtr, 'IncorrectYieldFromWithComment', $data); + } else { + $fix = $phpcsFile->addFixableError($error, $stackPtr, 'IncorrectYieldFrom', $data); + if ($fix === true) { + preg_match('/yield/i', $found, $yield); + preg_match('/from/i', $found, $from); + $phpcsFile->fixer->beginChangeset(); + $phpcsFile->fixer->replaceToken($stackPtr, $yield[0].' '.$from[0]); + + for ($i = ($stackPtr + 1); $i <= $yieldFromEnd; $i++) { $phpcsFile->fixer->replaceToken($i, ''); - $i++; - } while ($tokens[$i]['code'] === T_YIELD_FROM); - } + } - $phpcsFile->fixer->endChangeset(); - } + $phpcsFile->fixer->endChangeset(); + } + }//end if - return; + return ($yieldFromEnd + 1); }//end if if ($tokens[($stackPtr + 1)]['code'] === T_WHITESPACE) { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/WhiteSpace/ScopeIndentSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/WhiteSpace/ScopeIndentSniff.php index 151cb7d5c..d587d7966 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/WhiteSpace/ScopeIndentSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Sniffs/WhiteSpace/ScopeIndentSniff.php @@ -106,10 +106,6 @@ class ScopeIndentSniff implements Sniff */ public function register() { - if (defined('PHP_CODESNIFFER_IN_TESTS') === true) { - $this->debug = false; - } - return [T_OPEN_TAG]; }//end register() @@ -161,7 +157,7 @@ public function process(File $phpcsFile, $stackPtr) if ($this->debug === true) { $line = $tokens[$stackPtr]['line']; - echo "Start with token $stackPtr on line $line with indent $currentIndent".PHP_EOL; + echo PHP_EOL."Start with token $stackPtr on line $line with indent $currentIndent".PHP_EOL; } if (empty($this->ignoreIndentation) === true) { @@ -644,7 +640,7 @@ public function process(File $phpcsFile, $stackPtr) } $conditionToken = array_pop($openScopes); - if ($this->debug === true) { + if ($this->debug === true && $conditionToken !== null) { $line = $tokens[$conditionToken]['line']; $type = $tokens[$conditionToken]['type']; echo "\t=> removed open scope $conditionToken ($type) on line $line".PHP_EOL; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Arrays/ArrayIndentUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Arrays/ArrayIndentUnitTest.inc index 6f418ca1f..06ebca78f 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Arrays/ArrayIndentUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Arrays/ArrayIndentUnitTest.inc @@ -149,3 +149,6 @@ $var = [ ]; // phpcs:set Generic.Arrays.ArrayIndent indent 4 + +$array = [1, +]; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Arrays/ArrayIndentUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Arrays/ArrayIndentUnitTest.inc.fixed index 1ea8dd1e6..03f508dbe 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Arrays/ArrayIndentUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Arrays/ArrayIndentUnitTest.inc.fixed @@ -150,3 +150,6 @@ $var = [ ]; // phpcs:set Generic.Arrays.ArrayIndent indent 4 + +$array = [1, +]; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Arrays/DisallowLongArraySyntaxUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Arrays/DisallowLongArraySyntaxUnitTest.1.inc index 60c2ef96f..6855f02cb 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Arrays/DisallowLongArraySyntaxUnitTest.1.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Arrays/DisallowLongArraySyntaxUnitTest.1.inc @@ -3,14 +3,13 @@ $var = array(); $var = [1,2,3]; $var = array(1,2,3); echo $var[1]; -$foo = array($var[1],$var[2]); +$foo = ARRAY($var[1],$var[2]); $foo = array( 1, 2, 3 ); $var = array/*comment*/(1,2,3); -$var = array; function foo(array $array) {} @@ -26,3 +25,9 @@ array_map( static fn (array $value): array => array_filter($value), [] ); + +class Foo { + function array() {} +} + +$obj->array( 1, 2, 3 ); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Arrays/DisallowLongArraySyntaxUnitTest.1.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Arrays/DisallowLongArraySyntaxUnitTest.1.inc.fixed index e37971f23..5e9930684 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Arrays/DisallowLongArraySyntaxUnitTest.1.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Arrays/DisallowLongArraySyntaxUnitTest.1.inc.fixed @@ -10,7 +10,6 @@ $foo = [ 3 ]; $var = /*comment*/[1,2,3]; -$var = array; function foo(array $array) {} @@ -26,3 +25,9 @@ array_map( static fn (array $value): array => array_filter($value), [] ); + +class Foo { + function array() {} +} + +$obj->array( 1, 2, 3 ); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Arrays/DisallowLongArraySyntaxUnitTest.3.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Arrays/DisallowLongArraySyntaxUnitTest.3.inc new file mode 100644 index 000000000..68020bdca --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Arrays/DisallowLongArraySyntaxUnitTest.3.inc @@ -0,0 +1,7 @@ + 1, 9 => 1, ]; + case 'DisallowLongArraySyntaxUnitTest.3.inc': + return [ + 7 => 1, + ]; default: return []; }//end switch diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Classes/DuplicateClassNameUnitTest.10.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Classes/DuplicateClassNameUnitTest.10.inc new file mode 100644 index 000000000..d5ab20e3e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Classes/DuplicateClassNameUnitTest.10.inc @@ -0,0 +1,6 @@ + + + + + + 1]; + case 'DuplicateClassNameUnitTest.8.inc': + return [ + 7 => 1, + 8 => 1, + ]; + + case 'DuplicateClassNameUnitTest.9.inc': + return [ + 3 => 1, + 4 => 1, + ]; + + case 'DuplicateClassNameUnitTest.11.inc': + return [13 => 1]; + default: return []; }//end switch diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.1.inc similarity index 78% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.1.inc index 464b0e3d8..83e071bf4 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.1.inc @@ -1,7 +1,7 @@ - + /* * Test empty statement: no code between PHP open and close tag. @@ -42,7 +42,7 @@ function_call(); --> - + @@ -50,10 +50,10 @@ function_call(); true, }; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.1.inc.fixed similarity index 83% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.inc.fixed rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.1.inc.fixed index cc0f85e06..6bf8b2126 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.1.inc.fixed @@ -1,7 +1,7 @@ true, }; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.2.inc new file mode 100644 index 000000000..a9f895d71 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.2.inc @@ -0,0 +1,27 @@ + + + + + +/* + * Test empty statement: no code between PHP open and close tag. + */ + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.2.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.2.inc.fixed new file mode 100644 index 000000000..fd27d0a25 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.2.inc.fixed @@ -0,0 +1,23 @@ + + + + + +/* + * Test empty statement: no code between PHP open and close tag. + */ + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.php index 1b31b5f28..77542acba 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/EmptyPHPStatementUnitTest.php @@ -20,6 +20,27 @@ final class EmptyPHPStatementUnitTest extends AbstractSniffUnitTest { + /** + * Get a list of all test files to check. + * + * @param string $testFileBase The base path that the unit tests files will have. + * + * @return string[] + */ + protected function getTestFiles($testFileBase) + { + $testFiles = [$testFileBase.'1.inc']; + + $option = (bool) ini_get('short_open_tag'); + if ($option === true) { + $testFiles[] = $testFileBase.'2.inc'; + } + + return $testFiles; + + }//end getTestFiles() + + /** * Returns the lines where errors should occur. * @@ -41,31 +62,47 @@ public function getErrorList() * The key of the array should represent the line number and the value * should represent the number of warnings that should occur on that line. * + * @param string $testFile The name of the file being tested. + * * @return array */ - public function getWarningList() + public function getWarningList($testFile='') { - return [ - 9 => 1, - 12 => 1, - 15 => 1, - 18 => 1, - 21 => 1, - 22 => 1, - 31 => 1, - 33 => 1, - 43 => 1, - 45 => 1, - 49 => 1, - 50 => 1, - 57 => 1, - 59 => 1, - 61 => 1, - 63 => 2, - 71 => 1, - 72 => 1, - 80 => 1, - ]; + switch ($testFile) { + case 'EmptyPHPStatementUnitTest.1.inc': + return [ + 9 => 1, + 12 => 1, + 15 => 1, + 18 => 1, + 21 => 1, + 22 => 2, + 31 => 1, + 33 => 1, + 43 => 1, + 45 => 2, + 49 => 1, + 50 => 1, + 57 => 1, + 59 => 1, + 61 => 1, + 63 => 2, + 71 => 1, + 72 => 1, + 80 => 1, + ]; + case 'EmptyPHPStatementUnitTest.2.inc': + return [ + 3 => 1, + 4 => 1, + 13 => 1, + 15 => 1, + 25 => 1, + 27 => 1, + ]; + default: + return []; + }//end switch }//end getWarningList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/JumbledIncrementerUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/JumbledIncrementerUnitTest.1.inc new file mode 100644 index 000000000..966818420 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/JumbledIncrementerUnitTest.1.inc @@ -0,0 +1,89 @@ + 3; $same++) { + + } + } +} + +for ($i = 0; $i < 20; $i++) { + for ($j = 0; $j < 5; $j += 2) { + for ($k = 0; $k > 3; $k++) { + + } + } +} + +for ($i = 0; $i < 20; $i++) { + for ($same = 0; $same < 5; $same += 2) { + for ($k = 0; $k > 3; $same++) { + + } + } +} + +for (; $i < 10; $i++) { + for ($j = 0;; $j++) { + if ($j > 5) { + break; + } + for (;; $k++) { + if ($k > 5) { + break; + } + } + } +} + +for (; $same < 10; $same++) { + for ($j = 0;; $same++) { + if ($j > 5) { + break; + } + for (;; $same++) { + if ($k > 5) { + break; + } + } + } +} + +for ($i = 0; $i < 20; $i++) : + for ($j = 0; $j < 5; $j += 2) : + endfor; +endfor; + +for ($same = 0; $same < 20; $same++) : + for ($j = 0; $j < 5; $same += 2) : + endfor; +endfor; + +// Sniff bails early when there is no incrementor in the third expression of the outer for loop. +for ($same = 0; $same < 10;) { + ++$same; + for ($j = 0; $j < 5; $same++) {} +} + +for ($i = 1, $same = 0; $i <= 10; $i++, $same++) { + for ($same = 0, $k = 0; $k < 5; $same++, $k++) {} +} + +for ($i = 20; $i > 0; $i--) { + for ($j = 5; $j > 0; $j -= 2) { + for ($k = 3; $k > 0; $k--) {} + } +} + +for ($same = 20; $same > 0; $same--) { + for ($j = 5; $j > 0; $same -= 2) { + for ($k = 3; $k > 0; $same--) {} + } +} + +for ($i = 0; $i < 20; $i++); + +for ($same = 0; $same < 20; $same++) { + for ($j = 0; $j < 20; $same++); +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/JumbledIncrementerUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/JumbledIncrementerUnitTest.2.inc new file mode 100644 index 000000000..2324427bb --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/JumbledIncrementerUnitTest.2.inc @@ -0,0 +1,8 @@ + 3; $i++) { - - } - } -} - -for ($i = 0; $i < 20; $i++) { - for ($j = 0; $j < 5; $j += 2) { - for ($k = 0; $k > 3; $k++) { - - } - } -} - -for ($i = 0; $i < 20; $i++) { - for ($j = 0; $j < 5; $j += 2) { - for ($k = 0; $k > 3; $j++) { - - } - } -} \ No newline at end of file diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/JumbledIncrementerUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/JumbledIncrementerUnitTest.php index b3f65f156..0060efe62 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/JumbledIncrementerUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/JumbledIncrementerUnitTest.php @@ -41,15 +41,30 @@ public function getErrorList() * The key of the array should represent the line number and the value * should represent the number of warnings that should occur on that line. * + * @param string $testFile The name of the file being tested. + * * @return array */ - public function getWarningList() + public function getWarningList($testFile='') { - return [ - 3 => 2, - 4 => 1, - 20 => 1, - ]; + switch ($testFile) { + case 'JumbledIncrementerUnitTest.1.inc': + return [ + 3 => 2, + 4 => 1, + 20 => 1, + 40 => 2, + 41 => 1, + 58 => 1, + 69 => 1, + 79 => 2, + 80 => 1, + 87 => 1, + ]; + + default: + return []; + } }//end getWarningList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UnconditionalIfStatementUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UnconditionalIfStatementUnitTest.1.inc similarity index 54% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UnconditionalIfStatementUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UnconditionalIfStatementUnitTest.1.inc index 0d220c96e..58b604f73 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UnconditionalIfStatementUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UnconditionalIfStatementUnitTest.1.inc @@ -11,7 +11,3 @@ if (true) { if (file_exists(__FILE__) === true) { } - -// Intentional parse error/live coding. -// This needs to be the last test in the file. -if(true diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UnconditionalIfStatementUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UnconditionalIfStatementUnitTest.2.inc new file mode 100644 index 000000000..84306a522 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UnconditionalIfStatementUnitTest.2.inc @@ -0,0 +1,4 @@ + */ - public function getWarningList() + public function getWarningList($testFile='') { - return [ - 3 => 1, - 5 => 1, - 7 => 1, - ]; + switch ($testFile) { + case 'UnconditionalIfStatementUnitTest.1.inc': + return [ + 3 => 1, + 5 => 1, + 7 => 1, + ]; + + default: + return []; + }//end switch }//end getWarningList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UnnecessaryFinalModifierUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UnnecessaryFinalModifierUnitTest.1.inc index d217d0736..fc665669c 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UnnecessaryFinalModifierUnitTest.1.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UnnecessaryFinalModifierUnitTest.1.inc @@ -54,3 +54,25 @@ class Regular_Class_Regular_Constants { protected const PROTECTED_CONST = 'foo'; private const PRIVATE_CONST = true; } + +final class Final_Class_Final_Properties { + final readonly public ?MyType $final_public; + protected final $final_protected = 'foo'; +} + +final class Final_Class_Regular_Properties { + public $public = 23; + protected string $protected = 'foo'; + private $private = true; +} + +class Regular_Class_Final_Properties { + public static final $final_public = 23; + final readonly $final_protected = 'foo'; +} + +class Regular_Class_Regular_Properties { + public $public = 23; + protected $protected = 'foo'; + private static bool $private = true; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UnnecessaryFinalModifierUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UnnecessaryFinalModifierUnitTest.php index 6557db434..2969a865e 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UnnecessaryFinalModifierUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UnnecessaryFinalModifierUnitTest.php @@ -58,6 +58,8 @@ public function getWarningList($testFile='') 33 => 1, 37 => 1, 38 => 1, + 59 => 1, + 60 => 1, ]; default: return []; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UnusedFunctionParameterUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UnusedFunctionParameterUnitTest.1.inc index f13253d30..1e3d9bbcd 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UnusedFunctionParameterUnitTest.1.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UnusedFunctionParameterUnitTest.1.inc @@ -140,11 +140,11 @@ function moreParamSecond(LogicException $bar, Exception $foo) { // phpcs:set Generic.CodeAnalysis.UnusedFunctionParameter ignoreTypeHints[] class ConstructorPropertyPromotionNoContentInMethod { - public function __construct(protected int $id) {} + public function __construct(protected int $id, private(set) $foo) {} } class ConstructorPropertyPromotionWithContentInMethod { - public function __construct(protected int $id, $toggle = true) { + public function __construct(protected int $id, private(set) $foo, $toggle = true) { if ($toggle === true) { doSomething(); } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UselessOverridingMethodUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UselessOverridingMethodUnitTest.1.inc new file mode 100644 index 000000000..16a874f57 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/CodeAnalysis/UselessOverridingMethodUnitTest.1.inc @@ -0,0 +1,173 @@ +prop[$a], $this->{$b}); + } + + public function differentCase() { + return parent::DIFFERENTcase(); + } + + public function differentCaseSameNonAnsiiCharáctêrs() { + // This should be flagged, only ASCII chars have changed case. + return parent::DIFFERENTcaseSameNonAnsiiCharáctêrs(); + } + + public function differentCaseDifferentNonAnsiiCharáctêrs() { + // This should not be flagged as non-ASCII chars have changed case, making this a different method name. + return parent::DIFFERENTcaseDifferentNonAnsiiCharÁctÊrs(); + } + + public function nestedFunctionShouldBailEarly() { + function nestedFunctionShouldBailEarly() { + // Invalid code needed to ensure an error is NOT triggered and the sniff bails early when handling nested function. + parent::nestedFunctionShouldBailEarly(); + } + } +} + +abstract class AbstractFoo { + abstract public function sniffShouldBailEarly(); + + public function uselessMethodInAbstractClass() { + parent::uselessMethodInAbstractClass(); + } + + public function usefulMethodInAbstractClass() { + $a = 1; + parent::usefulMethodInAbstractClass($a); + } +} + +interface InterfaceFoo { + public function sniffShouldBailEarly(); +} + +trait TraitFoo { + abstract public function sniffShouldBailEarly(); + + public function usefulMethodInTrait() { + parent::usefulMethodInTrait(); + + return 1; + } + + public function uselessMethodInTrait() { + return parent::uselessMethodInTrait(); + } +} + +enum EnumFoo { + public function sniffShouldBailEarly() { + // Invalid code needed to ensure an error is NOT triggered and the sniff bails early when handling an enum method. + parent::sniffShouldBailEarly(); + } +} + +function shouldBailEarly() { + // Invalid code needed to ensure an error is NOT triggered and the sniff bails early when handling a regular function. + parent::shouldBailEarly(); +} + +$anon = new class extends ParentClass { + public function uselessOverridingMethod() { + parent::uselessOverridingMethod(); + } + + public function usefulOverridingMethod() { + $a = 10; + parent::usefulOverridingMethod($a); + } +}; + +function foo() { + $anon = new class extends ParentClass { + public function uselessOverridingMethod() { + parent::uselessOverridingMethod(); + } + }; +} + +class SniffShouldHandlePHPOpenCloseTagsCorrectly { + public function thisIsStillAUselessOverride($a, $b) { + return parent::thisIsStillAUselessOverride($a, $b) ?> + +
HTML
+ */ - public function getWarningList() + public function getWarningList($testFile='') { - return [ - 4 => 1, - 16 => 1, - ]; + switch ($testFile) { + case 'UselessOverridingMethodUnitTest.1.inc': + return [ + 4 => 1, + 16 => 1, + 38 => 1, + 56 => 1, + 68 => 1, + 72 => 1, + 93 => 1, + 116 => 1, + 134 => 1, + 146 => 1, + 153 => 1, + ]; + default: + return []; + } }//end getWarningList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Commenting/DocCommentUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Commenting/DocCommentUnitTest.php index 78fdf44bc..e447833d4 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Commenting/DocCommentUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Commenting/DocCommentUnitTest.php @@ -43,7 +43,7 @@ public function setCliValues($testFile, $config) * * @param string $testFile The name of the file being tested. * - * @return array(int => int) + * @return array */ public function getErrorList($testFile='') { @@ -115,7 +115,7 @@ public function getErrorList($testFile='') * The key of the array should represent the line number and the value * should represent the number of warnings that should occur on that line. * - * @return array(int => int) + * @return array */ public function getWarningList() { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/DisallowYodaConditionsUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/DisallowYodaConditionsUnitTest.inc index ce458d842..27053c4d6 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/DisallowYodaConditionsUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/DisallowYodaConditionsUnitTest.inc @@ -173,3 +173,15 @@ echo match ($text) { 'foo' => 10 === $y, 10 === $y => 'bar', }; + +1 ?? $nullCoalescingShouldNotTriggerSniff; + +1 + 2 === $sniffBailsArithmeticToken; + +'string' . 'concat' === $sniffBailsStringConcatToken; + +1 != $value; +1 <> $value; +1 >= $value; +1 <= $value; +1 <=> $value; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/DisallowYodaConditionsUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/DisallowYodaConditionsUnitTest.php index 52fc370a6..64a487d51 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/DisallowYodaConditionsUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/DisallowYodaConditionsUnitTest.php @@ -67,6 +67,11 @@ public function getErrorList() 167 => 1, 173 => 1, 174 => 1, + 183 => 1, + 184 => 1, + 185 => 1, + 186 => 1, + 187 => 1, ]; }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc index fb4a7380f..ada26fb7f 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc @@ -79,26 +79,26 @@ if ($a) error): - case Shop_Customer :: ERROR_INVALID_GENDER: ?> - Ungültiges Geschlecht! - - Die eingetragene E-Mail-Adresse ist bereits registriert. - allowShopping !== true): - if ($this->status != Shop_Cart :: OK): - switch ($this->status): - case Shop_Cart :: NOT_FOUND: - echo 'foo'; - endswitch; + +if ($error === ERROR_ONE): ?> + Error one! + + Error two! + $num) - return bar( - baz( - "foobarbaz" - ) - ); - break; -} +for ($i = 0; $i <= 4; $i++) + if ($i % 2) + return bar( + baz( + "foobarbaz" + ) + ); + + + do { $i++; @@ -272,3 +272,7 @@ function testFinally() } finally { } } + +if ($something) { + echo 'hello'; +} else /* comment */ if ($somethingElse) echo 'hi'; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc.fixed index d80a32652..53c6f0952 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.inc.fixed @@ -91,26 +91,26 @@ if ($a) { error): - case Shop_Customer :: ERROR_INVALID_GENDER: ?> - Ungültiges Geschlecht! - - Die eingetragene E-Mail-Adresse ist bereits registriert. - allowShopping !== true): - if ($this->status != Shop_Cart :: OK): - switch ($this->status): - case Shop_Cart :: NOT_FOUND: - echo 'foo'; - endswitch; + +if ($error === ERROR_ONE): ?> + Error one! + + Error two! + $num) { - return bar( - baz( - "foobarbaz" - ) - ); - } - break; +for ($i = 0; $i <= 4; $i++) { + if ($i % 2) { + return bar( + baz( + "foobarbaz" + ) + ); + } } + + + do { $i++; } @@ -307,3 +309,8 @@ function testFinally() } } } + +if ($something) { + echo 'hello'; +} else /* comment */ if ($somethingElse) { echo 'hi'; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.js b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.js similarity index 79% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.js rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.js index 4d3b1e8aa..763c1c1c1 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.js +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.js @@ -20,7 +20,7 @@ do { do i++; while (i < 5); -SomeClass.prototype.switch = function() { +SomeClass.prototype.for = function() { // do something }; @@ -29,3 +29,7 @@ if ($("#myid").rotationDegrees()=='90') if ($("#myid").rotationDegrees()=='90') $foo = {'transform': 'rotate(90deg)'}; + +if (something) { + alert('hello'); +} else /* comment */ if (somethingElse) alert('hi'); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.js.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.js.fixed similarity index 79% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.js.fixed rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.js.fixed index 8f0c413e7..050a406bb 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.js.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.1.js.fixed @@ -26,7 +26,7 @@ do { do { i++; } while (i < 5); -SomeClass.prototype.switch = function() { +SomeClass.prototype.for = function() { // do something }; @@ -37,3 +37,8 @@ if ($("#myid").rotationDegrees()=='90') { if ($("#myid").rotationDegrees()=='90') { $foo = {'transform': 'rotate(90deg)'}; } + +if (something) { + alert('hello'); +} else /* comment */ if (somethingElse) { alert('hi'); +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.2.js b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.2.js new file mode 100644 index 000000000..e26c33127 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.2.js @@ -0,0 +1,5 @@ +// Intentional parse error (missing closing parenthesis). +// This should be the only test in this file. +// Testing that the sniff is *not* triggered. + +do i++; while (i < 5 diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.3.js b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.3.js new file mode 100644 index 000000000..9ccedcda3 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.3.js @@ -0,0 +1,5 @@ +// Intentional parse error (missing opening parenthesis). +// This should be the only test in this file. +// Testing that the sniff is *not* triggered. + +do i++; while diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.php index 44f1d7471..22eeb075c 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/ControlStructures/InlineControlStructureUnitTest.php @@ -48,6 +48,7 @@ public function getErrorList($testFile='') 62 => 1, 66 => 1, 78 => 1, + 109 => 1, 120 => 1, 128 => 1, 134 => 1, @@ -69,7 +70,8 @@ public function getErrorList($testFile='') 191 => 1, 195 => 1, 198 => 1, - 206 => 1, + 204 => 1, + 205 => 1, 222 => 1, 232 => 1, 235 => 1, @@ -78,9 +80,10 @@ public function getErrorList($testFile='') 242 => 1, 260 => 1, 269 => 1, + 278 => 1, ]; - case 'InlineControlStructureUnitTest.js': + case 'InlineControlStructureUnitTest.1.js': return [ 3 => 1, 7 => 1, @@ -90,6 +93,7 @@ public function getErrorList($testFile='') 21 => 1, 27 => 1, 30 => 1, + 35 => 1, ]; default: diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Debug/CSSLintUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Debug/CSSLintUnitTest.php index 83f875cb0..e4afa67b6 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Debug/CSSLintUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Debug/CSSLintUnitTest.php @@ -16,6 +16,8 @@ * Unit test class for the CSSLint sniff. * * @covers \PHP_CodeSniffer\Standards\Generic\Sniffs\Debug\CSSLintSniff + * @covers \PHP_CodeSniffer\Config::getExecutablePath + * @group Windows */ final class CSSLintUnitTest extends AbstractSniffUnitTest { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Debug/ESLintUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Debug/ESLintUnitTest.php index 824beae4a..e035c2088 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Debug/ESLintUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Debug/ESLintUnitTest.php @@ -52,6 +52,8 @@ protected function setUpPrerequisites() $cwd = getcwd(); file_put_contents($cwd.'/.eslintrc.json', self::ESLINT_CONFIG); + putenv('ESLINT_USE_FLAT_CONFIG=false'); + }//end setUpPrerequisites() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Debug/JSHintUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Debug/JSHintUnitTest.php index 19c0473a8..254515994 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Debug/JSHintUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Debug/JSHintUnitTest.php @@ -28,7 +28,6 @@ final class JSHintUnitTest extends AbstractSniffUnitTest */ protected function shouldSkipTest() { - $rhinoPath = Config::getExecutablePath('rhino'); $jshintPath = Config::getExecutablePath('jshint'); if ($jshintPath === null) { return true; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Files/LowercasedFilenameUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Files/LowercasedFilenameUnitTest.php index 894a86dfe..ea7d5aa8b 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Files/LowercasedFilenameUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Files/LowercasedFilenameUnitTest.php @@ -9,6 +9,9 @@ namespace PHP_CodeSniffer\Standards\Generic\Tests\Files; +use PHP_CodeSniffer\Files\DummyFile; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; /** @@ -20,6 +23,24 @@ final class LowercasedFilenameUnitTest extends AbstractSniffUnitTest { + /** + * Get a list of all test files to check. + * + * @param string $testFileBase The base path that the unit tests files will have. + * + * @return string[] + */ + protected function getTestFiles($testFileBase) + { + $testFileDir = dirname($testFileBase); + $testFiles = parent::getTestFiles($testFileBase); + $testFiles[] = $testFileDir.DIRECTORY_SEPARATOR.'lowercased_filename_unit_test.inc'; + + return $testFiles; + + }//end getTestFiles() + + /** * Returns the lines where errors should occur. * @@ -58,4 +79,28 @@ public function getWarningList() }//end getWarningList() + /** + * Test the sniff bails early when handling STDIN. + * + * @return void + */ + public function testStdIn() + { + $config = new ConfigDouble(); + $config->standards = ['Generic']; + $config->sniffs = ['Generic.Files.LowercasedFilename']; + + $ruleset = new Ruleset($config); + + $content = 'process(); + + $this->assertSame(0, $file->getErrorCount()); + $this->assertSame(0, $file->getWarningCount()); + $this->assertCount(0, $file->getErrors()); + + }//end testStdIn() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Files/OneTraitPerFileUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Files/OneTraitPerFileUnitTest.php index 38f50a47c..ab95b5868 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Files/OneTraitPerFileUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Files/OneTraitPerFileUnitTest.php @@ -26,7 +26,7 @@ final class OneTraitPerFileUnitTest extends AbstractSniffUnitTest * The key of the array should represent the line number and the value * should represent the number of errors that should occur on that line. * - * @return array(int => int) + * @return array */ public function getErrorList() { @@ -44,7 +44,7 @@ public function getErrorList() * The key of the array should represent the line number and the value * should represent the number of warnings that should occur on that line. * - * @return array(int => int) + * @return array */ public function getWarningList() { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Files/lowercased_filename_unit_test.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Files/lowercased_filename_unit_test.inc new file mode 100644 index 000000000..b3d9bbc7f --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Files/lowercased_filename_unit_test.inc @@ -0,0 +1 @@ + */ - public function getErrorList() + public function getErrorList($testFile='') { - return [ - 4 => 1, - 5 => 1, - 8 => 1, - 9 => 1, - 12 => 1, - 13 => 1, - 16 => 1, - 17 => 1, - 20 => 1, - 21 => 1, - 24 => 1, - 25 => 1, - 28 => 1, - 29 => 1, - 32 => 1, - 33 => 1, - 36 => 1, - 37 => 1, - 40 => 1, - 41 => 1, - 44 => 1, - 45 => 1, - 51 => 1, - 53 => 1, - 55 => 1, - 58 => 1, - 64 => 1, - 72 => 1, - 73 => 1, - 75 => 1, - 76 => 1, - 78 => 1, - 82 => 1, - 84 => 1, - 85 => 1, - 86 => 1, - 88 => 1, - 93 => 1, - ]; + switch ($testFile) { + case 'SpaceAfterCastUnitTest.1.inc': + return [ + 4 => 1, + 5 => 1, + 8 => 1, + 9 => 1, + 12 => 1, + 13 => 1, + 16 => 1, + 17 => 1, + 20 => 1, + 21 => 1, + 24 => 1, + 25 => 1, + 28 => 1, + 29 => 1, + 32 => 1, + 33 => 1, + 36 => 1, + 37 => 1, + 40 => 1, + 41 => 1, + 44 => 1, + 45 => 1, + 51 => 1, + 53 => 1, + 55 => 1, + 58 => 1, + 64 => 1, + 72 => 1, + 73 => 1, + 75 => 1, + 76 => 1, + 78 => 1, + 82 => 1, + 84 => 1, + 85 => 1, + 86 => 1, + 88 => 1, + 93 => 1, + 97 => 1, + 99 => 1, + 100 => 1, + ]; + + default: + return []; + }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Formatting/SpaceAfterNotUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Formatting/SpaceAfterNotUnitTest.1.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Formatting/SpaceAfterNotUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Formatting/SpaceAfterNotUnitTest.1.inc diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Formatting/SpaceAfterNotUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Formatting/SpaceAfterNotUnitTest.1.inc.fixed similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Formatting/SpaceAfterNotUnitTest.inc.fixed rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Formatting/SpaceAfterNotUnitTest.1.inc.fixed diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Formatting/SpaceAfterNotUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Formatting/SpaceAfterNotUnitTest.2.inc new file mode 100644 index 000000000..2d6fa80a8 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Formatting/SpaceAfterNotUnitTest.2.inc @@ -0,0 +1,7 @@ + 2, 4 => 2, diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/CallTimePassByReferenceUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/CallTimePassByReferenceUnitTest.1.inc similarity index 57% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/CallTimePassByReferenceUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/CallTimePassByReferenceUnitTest.1.inc index 3fa33649e..9360680ce 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/CallTimePassByReferenceUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/CallTimePassByReferenceUnitTest.1.inc @@ -37,3 +37,30 @@ myfunc(MY_CONST&$myvar); efg( true == &$b ); efg( true === &$b ); + +foo($a, bar(&$b)); +foo($a, array(&$b)); + +enum Foo {} +interface Foo {} +trait Foo {} + +$instance = new $var($a); +$instance = new MyClass($a); +$instance = new $var(&$a); +$instance = new MyClass(&$a); + +$anon = new class($a) {}; +$anon = new class(&$a) {}; + +class Foo extends Bar { + function myMethod() { + $a = new static($var); + $b = new self($var); + $c = new parent($var); + + $d = new static(&$var); + $e = new self(&$var); + $f = new parent(&$var); + } +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/CallTimePassByReferenceUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/CallTimePassByReferenceUnitTest.2.inc new file mode 100644 index 000000000..769c5d61b --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/CallTimePassByReferenceUnitTest.2.inc @@ -0,0 +1,7 @@ + */ - public function getErrorList() + public function getErrorList($testFile='CallTimePassByReferenceUnitTest.1.inc') { - return [ - 9 => 1, - 12 => 1, - 15 => 1, - 18 => 2, - 23 => 1, - 30 => 1, - ]; + switch ($testFile) { + case 'CallTimePassByReferenceUnitTest.1.inc': + return [ + 9 => 1, + 12 => 1, + 15 => 1, + 18 => 2, + 23 => 1, + 30 => 1, + 41 => 1, + 50 => 1, + 51 => 1, + 54 => 1, + 62 => 1, + 63 => 1, + 64 => 1, + ]; + + default: + return []; + }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/FunctionCallArgumentSpacingUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/FunctionCallArgumentSpacingUnitTest.1.inc similarity index 79% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/FunctionCallArgumentSpacingUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/FunctionCallArgumentSpacingUnitTest.1.inc index 8bd067b3f..393ee10b6 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/FunctionCallArgumentSpacingUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/FunctionCallArgumentSpacingUnitTest.1.inc @@ -172,3 +172,28 @@ $foo = new MyClass( $obj, 'getMethod', ); + +#[AttributeName(1, 2)] +#[AttributeName(1,2)] + +$callable = myCallable(...); + +// Skip over PHP 7.4 arrow functions. +// While any commas belonging to the code within the arrow function would always need to be within parentheses +// or within a short array, so there aren't any false positives, the sniff also does not need to examine these, +// so will be more efficient skipping over arrow functions. +$foobar = functionCallFnParamA( + fn ($foo,$bar) => [1,2,3], + $args, +); + +$foobar = functionCallFnParamB(fn ($foo,$bar) => [1,2,3] ,$args); +$foobar = functionCallFnParamC($args, fn ($foo,$bar) => [1,2,3] , ); + +// Ignore spacing within PHP 8.0 match control structures, which may have their own rules. +$foobar = functionCallMatchParam( + match($foo) { + 1,2,3 => 'something',4,5,6 => 'else',default => 'works' + } , // But check the spacing again once the match expression has finished. + $args +); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/FunctionCallArgumentSpacingUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/FunctionCallArgumentSpacingUnitTest.1.inc.fixed similarity index 79% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/FunctionCallArgumentSpacingUnitTest.inc.fixed rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/FunctionCallArgumentSpacingUnitTest.1.inc.fixed index 69676524d..a50f695e4 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/FunctionCallArgumentSpacingUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/FunctionCallArgumentSpacingUnitTest.1.inc.fixed @@ -172,3 +172,28 @@ $foo = new MyClass( $obj, 'getMethod', ); + +#[AttributeName(1, 2)] +#[AttributeName(1, 2)] + +$callable = myCallable(...); + +// Skip over PHP 7.4 arrow functions. +// While any commas belonging to the code within the arrow function would always need to be within parentheses +// or within a short array, so there aren't any false positives, the sniff also does not need to examine these, +// so will be more efficient skipping over arrow functions. +$foobar = functionCallFnParamA( + fn ($foo,$bar) => [1,2,3], + $args, +); + +$foobar = functionCallFnParamB(fn ($foo,$bar) => [1,2,3], $args); +$foobar = functionCallFnParamC($args, fn ($foo,$bar) => [1,2,3], ); + +// Ignore spacing within PHP 8.0 match control structures, which may have their own rules. +$foobar = functionCallMatchParam( + match($foo) { + 1,2,3 => 'something',4,5,6 => 'else',default => 'works' + }, // But check the spacing again once the match expression has finished. + $args +); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/FunctionCallArgumentSpacingUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/FunctionCallArgumentSpacingUnitTest.2.inc new file mode 100644 index 000000000..f0ff633ee --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/FunctionCallArgumentSpacingUnitTest.2.inc @@ -0,0 +1,7 @@ + */ - public function getErrorList() + public function getErrorList($testFile='') { - return [ - 5 => 1, - 6 => 1, - 7 => 2, - 8 => 1, - 11 => 1, - 12 => 1, - 13 => 1, - 42 => 3, - 43 => 3, - 45 => 1, - 46 => 2, - 79 => 1, - 82 => 1, - 93 => 1, - 105 => 1, - 107 => 1, - 108 => 2, - 114 => 1, - 115 => 1, - 119 => 1, - 125 => 2, - 130 => 2, - 131 => 1, - 132 => 2, - 133 => 2, - 134 => 1, - 154 => 2, - 155 => 1, - 162 => 2, - 170 => 1, - ]; + switch ($testFile) { + case 'FunctionCallArgumentSpacingUnitTest.1.inc': + return [ + 5 => 1, + 6 => 1, + 7 => 2, + 8 => 1, + 11 => 1, + 12 => 1, + 13 => 1, + 42 => 3, + 43 => 3, + 45 => 1, + 46 => 2, + 79 => 1, + 82 => 1, + 93 => 1, + 105 => 1, + 107 => 1, + 108 => 2, + 114 => 1, + 115 => 1, + 119 => 1, + 125 => 2, + 130 => 2, + 131 => 1, + 132 => 2, + 133 => 2, + 134 => 1, + 154 => 2, + 155 => 1, + 162 => 2, + 170 => 1, + 177 => 1, + 190 => 2, + 191 => 2, + 197 => 1, + ]; + + default: + return []; + }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.1.inc similarity index 88% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.1.inc index 6c937a823..2e76d6215 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.1.inc @@ -23,16 +23,16 @@ class myClass // Good. function myFunction() { } - + // Brace should be on same line. function myFunction() { } - + // Too many spaces. function myFunction() { } - + // Uses tab. function myFunction() { } @@ -70,18 +70,18 @@ class myClass function myFunction($variable1, $variable2, $variable3, $variable4) { } - + // Brace should be on same line. function myFunction($variable1, $variable2, $variable3, $variable4) { } - + // Too many spaces. function myFunction($variable1, $variable2, $variable3, $variable4) { } - + // Uses tab. function myFunction($variable1, $variable2, $variable3, $variable4) { @@ -212,3 +212,21 @@ function myFunction($a, $lot, $of, $params) function myFunction() {} function myFunction() {} // Too many spaces with an empty function. function myFunction() {} // Too many spaces (tab) with an empty function. + +// phpcs:set Generic.Functions.OpeningFunctionBraceKernighanRitchie checkFunctions 0 +function shouldBeIgnored() +{} +// phpcs:set Generic.Functions.OpeningFunctionBraceKernighanRitchie checkFunctions 1 + +function dnfReturnType(): (Response&SuccessResponse)|AnotherResponse|string +{} + +function commentAfterOpeningBrace() { // Some comment. +} + +function variableAssignmentAfterOpeningBrace() { $a = 1; +} + +abstract class MyClass { + abstract public function abstractMethod(); +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.1.inc.fixed similarity index 88% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.inc.fixed rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.1.inc.fixed index bfb228384..14e62eae9 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.1.inc.fixed @@ -22,15 +22,15 @@ class myClass // Good. function myFunction() { } - + // Brace should be on same line. function myFunction() { } - + // Too many spaces. function myFunction() { } - + // Uses tab. function myFunction() { } @@ -67,17 +67,17 @@ class myClass function myFunction($variable1, $variable2, $variable3, $variable4) { } - + // Brace should be on same line. function myFunction($variable1, $variable2, $variable3, $variable4) { } - + // Too many spaces. function myFunction($variable1, $variable2, $variable3, $variable4) { } - + // Uses tab. function myFunction($variable1, $variable2, $variable3, $variable4) { @@ -200,3 +200,23 @@ function myFunction($a, $lot, $of, $params) function myFunction() {} function myFunction() {} // Too many spaces with an empty function. function myFunction() {} // Too many spaces (tab) with an empty function. + +// phpcs:set Generic.Functions.OpeningFunctionBraceKernighanRitchie checkFunctions 0 +function shouldBeIgnored() +{} +// phpcs:set Generic.Functions.OpeningFunctionBraceKernighanRitchie checkFunctions 1 + +function dnfReturnType(): (Response&SuccessResponse)|AnotherResponse|string { +} + +function commentAfterOpeningBrace() { + // Some comment. +} + +function variableAssignmentAfterOpeningBrace() { + $a = 1; +} + +abstract class MyClass { + abstract public function abstractMethod(); +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.2.inc new file mode 100644 index 000000000..36b5e8187 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Functions/OpeningFunctionBraceKernighanRitchieUnitTest.2.inc @@ -0,0 +1,19 @@ +tabWidth = 4; + } + + }//end setCliValues() + + /** * Returns the lines where errors should occur. * * The key of the array should represent the line number and the value * should represent the number of errors that should occur on that line. * + * @param string $testFile The name of the test file to process. + * * @return array */ - public function getErrorList() + public function getErrorList($testFile='') { - return [ - 9 => 1, - 13 => 1, - 17 => 1, - 29 => 1, - 33 => 1, - 37 => 1, - 53 => 1, - 58 => 1, - 63 => 1, - 77 => 1, - 82 => 1, - 87 => 1, - 104 => 1, - 119 => 1, - 123 => 1, - 127 => 1, - 132 => 1, - 137 => 1, - 142 => 1, - 157 => 1, - 162 => 1, - 171 => 1, - 181 => 1, - 191 => 1, - 197 => 1, - 203 => 1, - 213 => 1, - 214 => 1, - ]; + switch ($testFile) { + case 'OpeningFunctionBraceKernighanRitchieUnitTest.1.inc': + return [ + 9 => 1, + 13 => 1, + 17 => 1, + 29 => 1, + 33 => 1, + 37 => 1, + 53 => 1, + 58 => 1, + 63 => 1, + 77 => 1, + 82 => 1, + 87 => 1, + 104 => 1, + 119 => 1, + 123 => 1, + 127 => 1, + 132 => 1, + 137 => 1, + 142 => 1, + 157 => 1, + 162 => 1, + 171 => 1, + 181 => 1, + 191 => 1, + 197 => 1, + 203 => 1, + 213 => 1, + 214 => 1, + 222 => 1, + 224 => 1, + 227 => 1, + ]; + case 'OpeningFunctionBraceKernighanRitchieUnitTest.2.inc': + return [ + 6 => 1, + 10 => 1, + 14 => 1, + 18 => 1, + ]; + default: + return []; + }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.1.inc similarity index 95% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.1.inc index 494dcc769..9ee638b0c 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.1.inc @@ -46,7 +46,7 @@ function complexityEleven() { while ($condition === true) { if ($condition) { - } else if ($cond) { + } elseif ($cond) { } } @@ -61,11 +61,11 @@ function complexityEleven() echo 'hi'; } break; - case '3': - break; default: break; } + + foreach ($array as $element) {} } @@ -136,14 +136,6 @@ function complexityTwentyOne() echo 'hi'; } break; - case '3': - switch ($cond) { - case '1': - break; - case '2': - break; - } - break; case '4': do { if ($condition) { @@ -159,8 +151,16 @@ function complexityTwentyOne() } break; } -} + try { + for ($i = 0; $i < 10; $i++) { + if ($i % 2) { + doSomething(); + } + } + } catch (Exception $e) { + } +} function complexityTenWithTernaries() { @@ -451,4 +451,10 @@ function complexityElevenWithNullSafeOperator() $bits = $object5->getX()?->getY()?->getZ(); } -?> +abstract class AbstractClass { + abstract public function sniffShouldIgnoreAbstractMethods(); +} + +interface MyInterface { + public function sniffShouldIgnoreInterfaceMethods(); +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.2.inc new file mode 100644 index 000000000..9658af300 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Metrics/CyclomaticComplexityUnitTest.2.inc @@ -0,0 +1,7 @@ + */ - public function getErrorList() + public function getErrorList($testFile='') { - return [118 => 1]; + switch ($testFile) { + case 'CyclomaticComplexityUnitTest.1.inc': + return [118 => 1]; + default: + return []; + } }//end getErrorList() @@ -41,21 +48,28 @@ public function getErrorList() * The key of the array should represent the line number and the value * should represent the number of warnings that should occur on that line. * + * @param string $testFile The name of the file being tested. + * * @return array */ - public function getWarningList() + public function getWarningList($testFile='') { - return [ - 45 => 1, - 72 => 1, - 189 => 1, - 237 => 1, - 285 => 1, - 333 => 1, - 381 => 1, - 417 => 1, - 445 => 1, - ]; + switch ($testFile) { + case 'CyclomaticComplexityUnitTest.1.inc': + return [ + 45 => 1, + 72 => 1, + 189 => 1, + 237 => 1, + 285 => 1, + 333 => 1, + 381 => 1, + 417 => 1, + 445 => 1, + ]; + default: + return []; + } }//end getWarningList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.1.inc similarity index 68% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.1.inc index 970879241..3f1dd9261 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.1.inc @@ -27,16 +27,16 @@ function nestingFive() function nestingSix() { if ($condition) { - echo 'hi'; - switch ($condition) - { + } else { + switch ($condition) { case '1': if ($condition === '1') { - if ($cond) { + } elseif ($condition === '2') { + do { foreach ($conds as $cond) { echo 'hi'; } - } + } while ($cond > 5); } break; } @@ -79,19 +79,19 @@ function nestingEleven() case '1': if ($condition === '1') { if ($cond) { - switch ($cond) { - case '1': - if ($cond === '1') { - foreach ($conds as $cond) { - if ($cond === 'hi') { - if ($cond !== 'bye') { - echo 'hi'; - } + try { + if ( $cond === '1' ) { + for ( $i = 0; $i < 10; $i ++ ) { + while ($i < 5) { + if ( $cond === 'hi' ) { + match ( $cond ) { + 'hi' => 'something', + }; } } } - break; - } + } + } catch (Exception $e) {} } } break; @@ -99,4 +99,10 @@ function nestingEleven() } } -?> +abstract class AbstractClass { + abstract public function sniffShouldIgnoreAbstractMethods(); +} + +interface MyInterface { + public function sniffShouldIgnoreInterfaceMethods(); +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.2.inc new file mode 100644 index 000000000..9658af300 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Metrics/NestingLevelUnitTest.2.inc @@ -0,0 +1,7 @@ + */ - public function getErrorList() + public function getErrorList($testFile='') { - return [73 => 1]; + switch ($testFile) { + case 'NestingLevelUnitTest.1.inc': + return [73 => 1]; + default: + return []; + } }//end getErrorList() @@ -41,14 +48,21 @@ public function getErrorList() * The key of the array should represent the line number and the value * should represent the number of warnings that should occur on that line. * + * @param string $testFile The name of the test file to process. + * * @return array */ - public function getWarningList() + public function getWarningList($testFile='') { - return [ - 27 => 1, - 46 => 1, - ]; + switch ($testFile) { + case 'NestingLevelUnitTest.1.inc': + return [ + 27 => 1, + 46 => 1, + ]; + default: + return []; + } }//end getWarningList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/AbstractClassNamePrefixUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/AbstractClassNamePrefixUnitTest.1.inc new file mode 100644 index 000000000..43ba30c5b --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/AbstractClassNamePrefixUnitTest.1.inc @@ -0,0 +1,45 @@ + */ - public function getErrorList() + public function getErrorList($testFile='') { - return [ - 3 => 1, - 13 => 1, - 18 => 1, - 23 => 1, - 42 => 1, - ]; + switch ($testFile) { + case 'AbstractClassNamePrefixUnitTest.1.inc': + return [ + 3 => 1, + 7 => 1, + 11 => 1, + 16 => 1, + 29 => 1, + 44 => 1, + 45 => 1, + ]; + default: + return []; + } }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/CamelCapsFunctionNameUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/CamelCapsFunctionNameUnitTest.1.inc similarity index 86% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/CamelCapsFunctionNameUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/CamelCapsFunctionNameUnitTest.1.inc index 8441060d2..92368d8c8 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/CamelCapsFunctionNameUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/CamelCapsFunctionNameUnitTest.1.inc @@ -183,3 +183,22 @@ enum Suit: string implements Colorful, CardGame { public function parseMyDSN() {} public function get_some_value() {} } + +interface MyInterface { + public function getSomeValue(); + public function get_some_value(); +} + +class MyClass { + // phpcs:set Generic.NamingConventions.CamelCapsFunctionName strict false + function strictFOrmatDIsabled() {} // Ok. + // phpcs:set Generic.NamingConventions.CamelCapsFunctionName strict true + + function strictFOrmatIsENabled() {} // Not ok. +} + +// phpcs:set Generic.NamingConventions.CamelCapsFunctionName strict false +function strictFOrmatDIsabled() {} // Ok. +// phpcs:set Generic.NamingConventions.CamelCapsFunctionName strict true + +function strictFOrmatIsENabled() {} // Not ok. diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/CamelCapsFunctionNameUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/CamelCapsFunctionNameUnitTest.2.inc new file mode 100644 index 000000000..bfd1cfe25 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/CamelCapsFunctionNameUnitTest.2.inc @@ -0,0 +1,9 @@ + */ - public function getErrorList() + public function getErrorList($testFile='') { - $errors = [ - 10 => 1, - 11 => 1, - 12 => 1, - 13 => 1, - 16 => 1, - 17 => 1, - 20 => 1, - 21 => 1, - 24 => 1, - 25 => 1, - 30 => 1, - 31 => 1, - 50 => 1, - 52 => 1, - 53 => 2, - 57 => 1, - 58 => 1, - 59 => 1, - 60 => 1, - 61 => 1, - 62 => 1, - 63 => 1, - 64 => 1, - 65 => 1, - 66 => 1, - 67 => 1, - 68 => 2, - 69 => 1, - 71 => 1, - 72 => 1, - 73 => 2, - 118 => 1, - 144 => 1, - 146 => 1, - 147 => 2, - 158 => 1, - 159 => 1, - 179 => 1, - 180 => 2, - 183 => 1, - 184 => 1, - ]; - - return $errors; + switch ($testFile) { + case 'CamelCapsFunctionNameUnitTest.1.inc': + return[ + 10 => 1, + 11 => 1, + 12 => 1, + 13 => 1, + 16 => 1, + 17 => 1, + 20 => 1, + 21 => 1, + 24 => 1, + 25 => 1, + 30 => 1, + 31 => 1, + 50 => 1, + 52 => 1, + 53 => 2, + 57 => 1, + 58 => 1, + 59 => 1, + 60 => 1, + 61 => 1, + 62 => 1, + 63 => 1, + 64 => 1, + 65 => 1, + 66 => 1, + 67 => 1, + 68 => 2, + 69 => 1, + 71 => 1, + 72 => 1, + 73 => 2, + 118 => 1, + 144 => 1, + 146 => 1, + 147 => 2, + 158 => 1, + 159 => 1, + 179 => 1, + 180 => 2, + 183 => 1, + 184 => 1, + 189 => 1, + 197 => 1, + 204 => 1, + ]; + default: + return []; + }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/ConstructorNameUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/ConstructorNameUnitTest.1.inc similarity index 63% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/ConstructorNameUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/ConstructorNameUnitTest.1.inc index c68059198..2fb02d6aa 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/ConstructorNameUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/ConstructorNameUnitTest.1.inc @@ -95,3 +95,36 @@ interface CustomChildCreator { public function customChildCreator($elementName, Project $project); } + +// Bug: unconventional spacing and unexpected comments were not handled correctly. +class UnconventionalSpacing extends MyParent +{ + public function UnconventionalSpacing() { + self :: MyParent(); + MyParent/*comment*/::/*comment*/MyParent(); + } + + public function __construct() { + parent + //comment + :: + // phpcs:ignore Stnd.Cat.SniffName -- for reasons. + MyParent(); + } +} + +// Bug: calling a method with the same name as the class being extended on another class, should not be flagged. +class HierarchyKeywordBeforeColon extends MyParent +{ + public function HierarchyKeywordBeforeColon() { + parent::MyParent(); + MyParent::MyParent(); + SomeOtherClass::MyParent(); + } + + public function __construct() { + self::MyParent(); + static::MyParent(); + SomeOtherClass::MyParent(); + } +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/ConstructorNameUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/ConstructorNameUnitTest.2.inc new file mode 100644 index 000000000..bfd1cfe25 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/ConstructorNameUnitTest.2.inc @@ -0,0 +1,9 @@ + */ - public function getErrorList() + public function getErrorList($testFile='') { - return [ - 6 => 1, - 11 => 1, - 47 => 1, - 62 => 1, - 91 => 1, - ]; + switch ($testFile) { + case 'ConstructorNameUnitTest.1.inc': + return [ + 6 => 1, + 11 => 1, + 47 => 1, + 62 => 1, + 91 => 1, + 103 => 1, + 104 => 1, + 112 => 1, + 120 => 1, + 121 => 1, + 126 => 1, + 127 => 1, + ]; + default: + return []; + }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/InterfaceNameSuffixUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/InterfaceNameSuffixUnitTest.1.inc new file mode 100644 index 000000000..d09fa3df7 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/InterfaceNameSuffixUnitTest.1.inc @@ -0,0 +1,13 @@ + */ - public function getErrorList() + public function getErrorList($testFile='') { - return [8 => 1]; + switch ($testFile) { + case 'InterfaceNameSuffixUnitTest.1.inc': + return [ + 5 => 1, + 9 => 1, + ]; + default: + return []; + } }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/TraitNameSuffixUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/TraitNameSuffixUnitTest.1.inc new file mode 100644 index 000000000..e1d490825 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/TraitNameSuffixUnitTest.1.inc @@ -0,0 +1,11 @@ + */ - public function getErrorList() + public function getErrorList($testFile='') { - return [ - 3 => 1, - 9 => 1, - ]; + switch ($testFile) { + case 'TraitNameSuffixUnitTest.1.inc': + return [ + 3 => 1, + 9 => 1, + ]; + + default: + return []; + } }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.1.inc new file mode 100644 index 000000000..c5af2349c --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.1.inc @@ -0,0 +1,91 @@ +define('bar'); +$foo->getBar()->define('foo'); +Foo::define('bar'); + +class ClassConstBowOutTest { + const /* comment */ abc = 1; + const // phpcs:ignore Standard.Category.Sniff + some_constant = 2; +} + +$foo->getBar()?->define('foo'); + +// PHP 8.3 introduces typed constants. +class TypedConstants { + + const MyClass MYCONST = new MyClass; + const int VALID_NAME = 0; + final public const INT invalid_name = 0; + const FALSE false = false; // Yes, false can be used as a constant name, don't ask. + final protected const array ARRAY = array(); // Same goes for array. +} + +define /* comment */ ( /* comment */ 'CommentsInUnconventionalPlaces', 'value' ); + +define +// comment +( + // phpcs:ignore Stnd.Cat.SniffName -- for reasons. + 'CommentsInUnconventionalPlaces', + 'value' +); + +$foo-> /* comment */ define('bar'); +$foo?-> +// phpcs:ignore Stnd.Cat.SniffName -- for reasons. +define('bar'); + +const DEFINE = 'value'; + +#[Define('some param')] +class MyClass {} + +#[ + AttributeA, + define('some param') +] +class MyClass {} + +const MixedCase = 1; + +define('lower_case_name', 'value'); +define($var, 'sniff should bow out'); +define(constantName(), 'sniff should bow out'); +define($obj->constantName(), 'sniff should bow out'); +define(MyClass::constantName(), 'sniff should bow out'); +define(condition() ? 'name1' : 'name2', 'sniff should bow out'); + +$callable = define(...); + +// Valid if outside the global namespace. Sniff should bow out. +function define($param) {} + +class MyClass { + public function define($param) {} +} + +$a = ($cond) ? DEFINE : SOMETHING_ELSE; + +$object = new Define('value'); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.2.inc new file mode 100644 index 000000000..4136912dc --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.2.inc @@ -0,0 +1,7 @@ +define('bar'); -$foo->getBar()->define('foo'); -Foo::define('bar'); - -class ClassConstBowOutTest { - const /* comment */ abc = 1; - const // phpcs:ignore Standard.Category.Sniff - some_constant = 2; -} - -$foo->getBar()?->define('foo'); - -// PHP 8.3 introduces typed constants. -class TypedConstants { - const MISSING_VALUE; // Parse error. - const MyClass MYCONST = new MyClass; - const int VALID_NAME = 0; - const INT invalid_name = 0; - const FALSE false = false; // Yes, false can be used as a constant name, don't ask. - const array ARRAY = array(); // Same goes for array. -} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.php index afe362558..34a535abc 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/NamingConventions/UpperCaseConstantNameUnitTest.php @@ -26,21 +26,32 @@ final class UpperCaseConstantNameUnitTest extends AbstractSniffUnitTest * The key of the array should represent the line number and the value * should represent the number of errors that should occur on that line. * + * @param string $testFile The name of the test file to process. + * * @return array */ - public function getErrorList() + public function getErrorList($testFile='') { - return [ - 8 => 1, - 10 => 1, - 12 => 1, - 14 => 1, - 19 => 1, - 28 => 1, - 30 => 1, - 40 => 1, - 41 => 1, - ]; + switch ($testFile) { + case 'UpperCaseConstantNameUnitTest.1.inc': + return [ + 8 => 1, + 10 => 1, + 12 => 1, + 14 => 1, + 19 => 1, + 28 => 1, + 30 => 1, + 40 => 1, + 41 => 1, + 45 => 1, + 51 => 1, + 71 => 1, + 73 => 1, + ]; + default: + return []; + } }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/BacktickOperatorUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/BacktickOperatorUnitTest.inc index e2ca72d1f..3355c2d32 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/BacktickOperatorUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/BacktickOperatorUnitTest.inc @@ -1,9 +1,2 @@ 2, - 9 => 2, ]; }//end getErrorList() @@ -48,7 +47,6 @@ public function getErrorList() */ public function getWarningList() { - // Warning about incorrect annotation will be shown on line 1 once PR #3915 would be merged. return []; }//end getWarningList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/DeprecatedFunctionsUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/DeprecatedFunctionsUnitTest.inc index 2bc245368..d3df5f2ae 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/DeprecatedFunctionsUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/DeprecatedFunctionsUnitTest.inc @@ -2,3 +2,4 @@ create_function(); // Deprecated PHP 7.2. mbsplit(); // Deprecated PHP 7.3. +libxml_disable_entity_loader(); // Deprecated PHP 8.0. diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/DeprecatedFunctionsUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/DeprecatedFunctionsUnitTest.php index 4b6f6ef54..138c22239 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/DeprecatedFunctionsUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/DeprecatedFunctionsUnitTest.php @@ -40,6 +40,10 @@ public function getErrorList() $errors[4] = 1; } + if (PHP_VERSION_ID >= 80000) { + $errors[5] = 1; + } + return $errors; }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/DisallowShortOpenTagUnitTest.3.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/DisallowShortOpenTagUnitTest.3.inc index 9b7ccd6dc..6c4f83d56 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/DisallowShortOpenTagUnitTest.3.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/DisallowShortOpenTagUnitTest.3.inc @@ -12,5 +12,9 @@ Some content Some more content +// Test snippet clipping with a line that has more than 40 characters after the PHP open tag. +Some content Some longer content to trigger snippet clipping + // Only recognize closing tag after opener. +// The test below must be the last test in the file because there must be no PHP close tag after it. Some?> content diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/DisallowShortOpenTagUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/DisallowShortOpenTagUnitTest.php index a8955d699..b1fc64d34 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/DisallowShortOpenTagUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/DisallowShortOpenTagUnitTest.php @@ -36,6 +36,7 @@ protected function getTestFiles($testFileBase) $testFiles[] = $testFileBase.'2.inc'; } else { $testFiles[] = $testFileBase.'3.inc'; + $testFiles[] = $testFileBase.'4.inc'; } return $testFiles; @@ -97,6 +98,7 @@ public function getWarningList($testFile='') 3 => 1, 6 => 1, 11 => 1, + 16 => 1, ]; default: return []; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/ForbiddenFunctionsUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/ForbiddenFunctionsUnitTest.inc index 060da6128..06509d8c8 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/ForbiddenFunctionsUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/ForbiddenFunctionsUnitTest.inc @@ -48,7 +48,7 @@ class RightSideVisTest { } namespace Something\sizeof; -$var = new Sizeof(); +$var = new /*comment*/ Sizeof(); class SizeOf implements Something {} function mymodule_form_callback(SizeOf $sizeof) { @@ -58,3 +58,5 @@ $size = $class?->sizeof($array); #[SizeOf(10)] function doSomething() {} + +$size = sizeof /*comment*/ ($array); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/ForbiddenFunctionsUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/ForbiddenFunctionsUnitTest.php index cb0931312..3ebfc5520 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/ForbiddenFunctionsUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/ForbiddenFunctionsUnitTest.php @@ -31,9 +31,10 @@ final class ForbiddenFunctionsUnitTest extends AbstractSniffUnitTest public function getErrorList() { $errors = [ - 2 => 1, - 4 => 1, - 6 => 1, + 2 => 1, + 4 => 1, + 6 => 1, + 62 => 1, ]; return $errors; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseConstantUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseConstantUnitTest.1.inc similarity index 79% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseConstantUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseConstantUnitTest.1.inc index 07e54e258..301f6efd4 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseConstantUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseConstantUnitTest.1.inc @@ -84,15 +84,15 @@ $input->getFilterChain()->attachByName('Null', ['type' => Null::TYPE_STRING]); // Issue #3332 - ignore type declarations, but not default values. class TypedThings { - const MYCONST = FALSE; + const MYCONST = FALSE; - public int|FALSE $int = FALSE; - public Type|NULL $int = new MyObj(NULL); + public int|FALSE $int = FALSE; + public Type|NULL $int = new MyObj(NULL); - private function typed(int|FALSE $param = NULL, Type|NULL $obj = new MyObj(FALSE)) : string|FALSE|NULL - { - if (TRUE === FALSE) { - return NULL; + private function typed(int|FALSE $param = NULL, Type|NULL $obj = new MyObj(FALSE)) : string|FALSE|NULL + { + if (TRUE === FALSE) { + return NULL; } } } @@ -152,6 +152,23 @@ class TypedConstants { // Global constants can not be typed. const MYCONST = TRUE; -// Last coding/parse error. -// This has to be the last test in the file. -function UnclosedCurly (): FALSE { +class SkipOverPHP82DNFTypes { + protected (\FullyQualified&Partially\Qualified)|TRUE $propertyC; +} + +class SkipOverPHP84FinalProperties { + final MyType|FALSE $propA; + private static final NULL|MyClass $propB; +} + +// PHP 8.4 asymmetric visibility +class WithAsym { + + private(set) NULL|TRUE $asym1 = TRUE; + + public private(set) ?bool $asym2 = FALSE; + + protected(set) FALSE|string|null $asym3 = NULL; + + public protected(set) Type|NULL|bool $asym4 = TRUE; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseConstantUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseConstantUnitTest.1.inc.fixed similarity index 79% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseConstantUnitTest.inc.fixed rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseConstantUnitTest.1.inc.fixed index 723a7221e..5dcd342dc 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseConstantUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseConstantUnitTest.1.inc.fixed @@ -84,15 +84,15 @@ $input->getFilterChain()->attachByName('Null', ['type' => Null::TYPE_STRING]); // Issue #3332 - ignore type declarations, but not default values. class TypedThings { - const MYCONST = false; + const MYCONST = false; - public int|FALSE $int = false; - public Type|NULL $int = new MyObj(null); + public int|FALSE $int = false; + public Type|NULL $int = new MyObj(null); - private function typed(int|FALSE $param = null, Type|NULL $obj = new MyObj(false)) : string|FALSE|NULL - { - if (true === false) { - return null; + private function typed(int|FALSE $param = null, Type|NULL $obj = new MyObj(false)) : string|FALSE|NULL + { + if (true === false) { + return null; } } } @@ -152,6 +152,23 @@ class TypedConstants { // Global constants can not be typed. const MYCONST = true; -// Last coding/parse error. -// This has to be the last test in the file. -function UnclosedCurly (): FALSE { +class SkipOverPHP82DNFTypes { + protected (\FullyQualified&Partially\Qualified)|TRUE $propertyC; +} + +class SkipOverPHP84FinalProperties { + final MyType|FALSE $propA; + private static final NULL|MyClass $propB; +} + +// PHP 8.4 asymmetric visibility +class WithAsym { + + private(set) NULL|TRUE $asym1 = true; + + public private(set) ?bool $asym2 = false; + + protected(set) FALSE|string|null $asym3 = null; + + public protected(set) Type|NULL|bool $asym4 = true; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseConstantUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseConstantUnitTest.2.inc new file mode 100644 index 000000000..c61a0a50f --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseConstantUnitTest.2.inc @@ -0,0 +1,4 @@ + 1, 10 => 1, @@ -66,6 +66,10 @@ public function getErrorList($testFile='') 129 => 1, 149 => 1, 153 => 1, + 167 => 1, + 169 => 1, + 171 => 1, + 173 => 1, ]; case 'LowerCaseConstantUnitTest.js': diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseKeywordUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseKeywordUnitTest.inc index 37579d321..c39a8d24a 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseKeywordUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseKeywordUnitTest.inc @@ -44,5 +44,33 @@ EnuM ENUM: string Case HEARTS; } +new Class {}; +new clasS extends stdClass {}; +new class {}; + +if (isset($a) && !empty($a)) { unset($a); } +if (ISSET($a) && !Empty($a)) { UnSeT($a); } +eval('foo'); +eVaL('foo'); + +$c = function() { + Yield /*comment*/ From fun(); + YIELD + /*comment*/ + FROM fun(); +} + +class AsymmetricVisibility { + public(set) int $correctPublicSet; + protected(set) int $correctProtectedSet; + private(set) int $correctPrivateSet; + + PubliC(SeT) int $wrongCasePublic; + PROTECTED(set) array $wrongCaseProtected; + protected(sEt) int $wrongCaseProtectedSet; + Private(set) int $wrongCasePrivate; + private(SET) readonly ?string $wrongCasePrivateSet; +} + __HALT_COMPILER(); // An exception due to phar support. function diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseKeywordUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseKeywordUnitTest.inc.fixed index 7063327ae..ebb05d134 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseKeywordUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseKeywordUnitTest.inc.fixed @@ -44,5 +44,33 @@ enum ENUM: string case HEARTS; } +new class {}; +new class extends stdClass {}; +new class {}; + +if (isset($a) && !empty($a)) { unset($a); } +if (isset($a) && !empty($a)) { unset($a); } +eval('foo'); +eval('foo'); + +$c = function() { + yield /*comment*/ from fun(); + yield + /*comment*/ + from fun(); +} + +class AsymmetricVisibility { + public(set) int $correctPublicSet; + protected(set) int $correctProtectedSet; + private(set) int $correctPrivateSet; + + public(set) int $wrongCasePublic; + protected(set) array $wrongCaseProtected; + protected(set) int $wrongCaseProtectedSet; + private(set) int $wrongCasePrivate; + private(set) readonly ?string $wrongCasePrivateSet; +} + __HALT_COMPILER(); // An exception due to phar support. function diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseKeywordUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseKeywordUnitTest.php index 17f0e25d3..90e6be040 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseKeywordUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseKeywordUnitTest.php @@ -48,6 +48,18 @@ public function getErrorList() 39 => 2, 42 => 1, 44 => 1, + 47 => 1, + 48 => 1, + 52 => 3, + 54 => 1, + 57 => 2, + 58 => 1, + 60 => 1, + 68 => 1, + 69 => 1, + 70 => 1, + 71 => 1, + 72 => 1, ]; }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseTypeUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseTypeUnitTest.inc index 6674970e1..747431053 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseTypeUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseTypeUnitTest.inc @@ -75,7 +75,7 @@ class TypedProperties } class ConstructorPropertyPromotionWithTypes { - public function __construct(protected Float|Int $x, public ?STRING &$y = 'test', private mixed $z) {} + public function __construct(protected Float|Int $x, public(set) ?STRING &$y = 'test', private mixed $z) {} } class ConstructorPropertyPromotionAndNormalParams { @@ -125,6 +125,20 @@ enum TypedEnumConstants { public const sTRing | aRRaY | FaLSe FOURTH = 'fourth'; } +class DNFTypes { + const (Parent&Something)|Float CONST_NAME = 1.5; + + public readonly TRUE|(\A&B) $prop; + + function DNFParamTypes ( + null|(\Package\ClassName&\Package\Other_Class)|INT $DNFinMiddle, + (\Package\ClassName&\Package\Other_Class)|ARRAY $parensAtStart, + False|(\Package\ClassName&\Package\Other_Class) $parentAtEnd, + ) {} + + function DNFReturnTypes ($var): object|(Self&\Package\Other_Class)|sTRINg|false {} +} + // Intentional error, should be ignored by the sniff. interface PropertiesNotAllowed { public $notAllowed; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseTypeUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseTypeUnitTest.inc.fixed index 59e4af835..4814ea859 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseTypeUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseTypeUnitTest.inc.fixed @@ -75,7 +75,7 @@ class TypedProperties } class ConstructorPropertyPromotionWithTypes { - public function __construct(protected float|int $x, public ?string &$y = 'test', private mixed $z) {} + public function __construct(protected float|int $x, public(set) ?string &$y = 'test', private mixed $z) {} } class ConstructorPropertyPromotionAndNormalParams { @@ -125,6 +125,20 @@ enum TypedEnumConstants { public const string | array | false FOURTH = 'fourth'; } +class DNFTypes { + const (parent&Something)|float CONST_NAME = 1.5; + + public readonly true|(\A&B) $prop; + + function DNFParamTypes ( + null|(\Package\ClassName&\Package\Other_Class)|int $DNFinMiddle, + (\Package\ClassName&\Package\Other_Class)|array $parensAtStart, + false|(\Package\ClassName&\Package\Other_Class) $parentAtEnd, + ) {} + + function DNFReturnTypes ($var): object|(self&\Package\Other_Class)|string|false {} +} + // Intentional error, should be ignored by the sniff. interface PropertiesNotAllowed { public $notAllowed; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseTypeUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseTypeUnitTest.php index c5cfbb18a..262193285 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseTypeUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/LowerCaseTypeUnitTest.php @@ -87,6 +87,12 @@ public function getErrorList() 123 => 2, 124 => 3, 125 => 3, + 129 => 2, + 131 => 1, + 134 => 1, + 135 => 1, + 136 => 1, + 139 => 2, ]; }//end getErrorList() @@ -103,7 +109,7 @@ public function getErrorList() public function getWarningList() { // Warning from getMemberProperties() about parse error. - return [130 => 1]; + return [144 => 1]; }//end getWarningList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/UpperCaseConstantUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/UpperCaseConstantUnitTest.inc index 30c6d2980..4d0ca8ff5 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/UpperCaseConstantUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/UpperCaseConstantUnitTest.inc @@ -82,17 +82,34 @@ function true() {} // Issue #3332 - ignore type declarations, but not default values. class TypedThings { - const MYCONST = false; + const MYCONST = false; - public int|false $int = false; - public Type|null $int = new MyObj(null); + public int|false $int = false; + public Type|null $int = new MyObj(null); - private function typed(int|false $param = null, Type|null $obj = new MyObj(false)) : string|false|null - { - if (true === false) { - return null; + private function typed(int|false $param = null, Type|null $obj = new MyObj(false)) : string|false|null + { + if (true === false) { + return null; } } } $cl = function (int|false $param = null, Type|null $obj = new MyObj(false)) : string|false|null {}; + +class SkipOverPHP82DNFTypes { + protected (\FullyQualified&Partially\Qualified)|false $propertyC; +} + +class SkipOverPHP84FinalProperties { + final MyType|false $propA; + private static final null|MyClass $propB; +} + +// PHP 8.4 asymmetric visibility +class WithAsym { + private(set) null|true $asym1 = TRUE; + public private(set) ?bool $asym2 = false; + protected(set) false|string|null $asym3 = null; + public protected(set) Type|null|bool $asym4 = true; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/UpperCaseConstantUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/UpperCaseConstantUnitTest.inc.fixed index 7705198c8..831f1161d 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/UpperCaseConstantUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/UpperCaseConstantUnitTest.inc.fixed @@ -82,17 +82,34 @@ function true() {} // Issue #3332 - ignore type declarations, but not default values. class TypedThings { - const MYCONST = FALSE; + const MYCONST = FALSE; - public int|false $int = FALSE; - public Type|null $int = new MyObj(NULL); + public int|false $int = FALSE; + public Type|null $int = new MyObj(NULL); - private function typed(int|false $param = NULL, Type|null $obj = new MyObj(FALSE)) : string|false|null - { - if (TRUE === FALSE) { - return NULL; + private function typed(int|false $param = NULL, Type|null $obj = new MyObj(FALSE)) : string|false|null + { + if (TRUE === FALSE) { + return NULL; } } } $cl = function (int|false $param = NULL, Type|null $obj = new MyObj(FALSE)) : string|false|null {}; + +class SkipOverPHP82DNFTypes { + protected (\FullyQualified&Partially\Qualified)|false $propertyC; +} + +class SkipOverPHP84FinalProperties { + final MyType|false $propA; + private static final null|MyClass $propB; +} + +// PHP 8.4 asymmetric visibility +class WithAsym { + private(set) null|true $asym1 = TRUE; + public private(set) ?bool $asym2 = FALSE; + protected(set) false|string|null $asym3 = NULL; + public protected(set) Type|null|bool $asym4 = TRUE; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/UpperCaseConstantUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/UpperCaseConstantUnitTest.php index 481c4ab1c..7738b94d7 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/UpperCaseConstantUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/PHP/UpperCaseConstantUnitTest.php @@ -31,27 +31,30 @@ final class UpperCaseConstantUnitTest extends AbstractSniffUnitTest public function getErrorList() { return [ - 7 => 1, - 10 => 1, - 15 => 1, - 16 => 1, - 23 => 1, - 26 => 1, - 31 => 1, - 32 => 1, - 39 => 1, - 42 => 1, - 47 => 1, - 48 => 1, - 70 => 1, - 71 => 1, - 85 => 1, - 87 => 1, - 88 => 1, - 90 => 2, - 92 => 2, - 93 => 1, - 98 => 2, + 7 => 1, + 10 => 1, + 15 => 1, + 16 => 1, + 23 => 1, + 26 => 1, + 31 => 1, + 32 => 1, + 39 => 1, + 42 => 1, + 47 => 1, + 48 => 1, + 70 => 1, + 71 => 1, + 85 => 1, + 87 => 1, + 88 => 1, + 90 => 2, + 92 => 2, + 93 => 1, + 98 => 2, + 112 => 1, + 113 => 1, + 114 => 1, ]; }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Strings/UnnecessaryHeredocUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Strings/UnnecessaryHeredocUnitTest.1.inc new file mode 100644 index 000000000..428b4b8a4 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Strings/UnnecessaryHeredocUnitTest.1.inc @@ -0,0 +1,122 @@ +bar} +END; + +$heredoc = <<< "END" +some ${beers::softdrink} +END; + +$heredoc = <<< END +{${$object->getName()}} text +END; + +$heredoc = <<<"END" +some {${getName()}} +END; + +$heredoc = <<baz()()} +END; + +$heredoc = <<values[3]->name} text +END; + +$heredoc = <<<"END" +some ${$bar} +END; + +$heredoc = <<bar} text +END; + +$heredoc = <<<"END" +${foo["${bar}"]} text +END; + +$heredoc = <<{${'a'}}} text +END; + +$heredoc = <<{$baz[1]}} +END; + +$heredoc = <<john's wife greeted $people->robert. +END; + +$heredoc = <<bar} +END; + +$heredoc = <<< "END" +some ${beers::softdrink} +END; + +$heredoc = <<< END +{${$object->getName()}} text +END; + +$heredoc = <<<"END" +some {${getName()}} +END; + +$heredoc = <<baz()()} +END; + +$heredoc = <<values[3]->name} text +END; + +$heredoc = <<<"END" +some ${$bar} +END; + +$heredoc = <<bar} text +END; + +$heredoc = <<<"END" +${foo["${bar}"]} text +END; + +$heredoc = <<{${'a'}}} text +END; + +$heredoc = <<{$baz[1]}} +END; + +$heredoc = <<john's wife greeted $people->robert. +END; + +$heredoc = <<bar} + END; + +$heredoc = <<< "END" + some ${beers::softdrink} + END; + +$heredoc = <<< END + {${$object->getName()}} text + END; + +$heredoc = <<<"END" + some {${getName()}} + END; + +$heredoc = <<baz()()} + END; + +$heredoc = <<values[3]->name} text + END; + +$heredoc = <<<"END" + some ${$bar} + END; + +$heredoc = <<bar} text + END; + +$heredoc = <<<"END" + ${foo["${bar}"]} text + END; + +$heredoc = <<{${'a'}}} text + END; + +$heredoc = <<{$baz[1]}} + END; + +$heredoc = <<john's wife greeted $people->robert. + END; + +$heredoc = <<bar} + END; + +$heredoc = <<< "END" + some ${beers::softdrink} + END; + +$heredoc = <<< END + {${$object->getName()}} text + END; + +$heredoc = <<<"END" + some {${getName()}} + END; + +$heredoc = <<baz()()} + END; + +$heredoc = <<values[3]->name} text + END; + +$heredoc = <<<"END" + some ${$bar} + END; + +$heredoc = <<bar} text + END; + +$heredoc = <<<"END" + ${foo["${bar}"]} text + END; + +$heredoc = <<{${'a'}}} text + END; + +$heredoc = <<{$baz[1]}} + END; + +$heredoc = <<john's wife greeted $people->robert. + END; + +$heredoc = << + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Standards\Generic\Tests\Strings; + +use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; + +/** + * Unit test class for the UnnecessaryHeredoc sniff. + * + * @covers \PHP_CodeSniffer\Standards\Generic\Sniffs\Strings\UnnecessaryHeredocSniff + */ +final class UnnecessaryHeredocUnitTest extends AbstractSniffUnitTest +{ + + + /** + * Returns the lines where errors should occur. + * + * The key of the array should represent the line number and the value + * should represent the number of errors that should occur on that line. + * + * @return array + */ + public function getErrorList() + { + return []; + + }//end getErrorList() + + + /** + * Returns the lines where warnings should occur. + * + * The key of the array should represent the line number and the value + * should represent the number of warnings that should occur on that line. + * + * @param string $testFile The name of the file being tested. + * + * @return array + */ + public function getWarningList($testFile='') + { + $warnings = [ + 100 => 1, + 104 => 1, + ]; + + switch ($testFile) { + case 'UnnecessaryHeredocUnitTest.1.inc': + return $warnings; + + case 'UnnecessaryHeredocUnitTest.2.inc': + if (PHP_VERSION_ID >= 70300) { + return $warnings; + } + + // PHP 7.2 or lower: PHP version which doesn't support flexible heredocs/nowdocs yet. + return []; + + default: + return []; + } + + }//end getWarningList() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Strings/UnnecessaryStringConcatUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Strings/UnnecessaryStringConcatUnitTest.1.inc new file mode 100644 index 000000000..d2ac790d1 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Strings/UnnecessaryStringConcatUnitTest.1.inc @@ -0,0 +1,34 @@ +'; +$code = '<'.'?php '; + +$string = 'This is a really long string. ' + . 'It is being used for errors. ' + . 'The message is not translated.'; + +$shouldBail = 1 + 1; + +$shouldNotTrigger = 'My' . /* comment */ 'string'; +$shouldNotTrigger = 'My' /* comment */ . 'string'; + +// phpcs:set Generic.Strings.UnnecessaryStringConcat allowMultiline true +$string = 'Multiline strings are allowed ' + . 'when setting is enabled.'; +// phpcs:set Generic.Strings.UnnecessaryStringConcat allowMultiline false + +// phpcs:set Generic.Strings.UnnecessaryStringConcat error false +$throwWarning = 'My' . 'string'; +// phpcs:set Generic.Strings.UnnecessaryStringConcat error true diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Strings/UnnecessaryStringConcatUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Strings/UnnecessaryStringConcatUnitTest.2.inc new file mode 100644 index 000000000..6a5fcba9a --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Strings/UnnecessaryStringConcatUnitTest.2.inc @@ -0,0 +1,7 @@ +'; -$code = '<'.'?php '; - -$string = 'This is a really long string. ' - . 'It is being used for errors. ' - . 'The message is not translated.'; -?> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Strings/UnnecessaryStringConcatUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Strings/UnnecessaryStringConcatUnitTest.php index c08918d15..e657e4870 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Strings/UnnecessaryStringConcatUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/Strings/UnnecessaryStringConcatUnitTest.php @@ -33,7 +33,7 @@ final class UnnecessaryStringConcatUnitTest extends AbstractSniffUnitTest public function getErrorList($testFile='') { switch ($testFile) { - case 'UnnecessaryStringConcatUnitTest.inc': + case 'UnnecessaryStringConcatUnitTest.1.inc': return [ 2 => 1, 6 => 1, @@ -65,11 +65,21 @@ public function getErrorList($testFile='') * The key of the array should represent the line number and the value * should represent the number of warnings that should occur on that line. * + * @param string $testFile The name of the file being tested. + * * @return array */ - public function getWarningList() + public function getWarningList($testFile='') { - return []; + switch ($testFile) { + case 'UnnecessaryStringConcatUnitTest.1.inc': + return [ + 33 => 1, + ]; + + default: + return []; + } }//end getWarningList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowSpaceIndentUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowSpaceIndentUnitTest.1.inc index 1826b585b..b19a58d87 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowSpaceIndentUnitTest.1.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowSpaceIndentUnitTest.1.inc @@ -116,3 +116,10 @@ $x = 1; Another line. */ + +// A `yield from` can be multiline and may contain spaces in the indentation whitespace between the keywords. +function myGenerator() { + yield + from + gen2(); +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowSpaceIndentUnitTest.1.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowSpaceIndentUnitTest.1.inc.fixed index 298b3771a..ca037ee92 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowSpaceIndentUnitTest.1.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowSpaceIndentUnitTest.1.inc.fixed @@ -116,3 +116,10 @@ $x = 1; Another line. */ + +// A `yield from` can be multiline and may contain spaces in the indentation whitespace between the keywords. +function myGenerator() { + yield + from + gen2(); +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowSpaceIndentUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowSpaceIndentUnitTest.2.inc index 1826b585b..b19a58d87 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowSpaceIndentUnitTest.2.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowSpaceIndentUnitTest.2.inc @@ -116,3 +116,10 @@ $x = 1; Another line. */ + +// A `yield from` can be multiline and may contain spaces in the indentation whitespace between the keywords. +function myGenerator() { + yield + from + gen2(); +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowSpaceIndentUnitTest.2.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowSpaceIndentUnitTest.2.inc.fixed index 298b3771a..ca037ee92 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowSpaceIndentUnitTest.2.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowSpaceIndentUnitTest.2.inc.fixed @@ -116,3 +116,10 @@ $x = 1; Another line. */ + +// A `yield from` can be multiline and may contain spaces in the indentation whitespace between the keywords. +function myGenerator() { + yield + from + gen2(); +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowTabIndentUnitTest.3.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowSpaceIndentUnitTest.4.inc similarity index 52% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowTabIndentUnitTest.3.inc.fixed rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowSpaceIndentUnitTest.4.inc index 622088ad2..b438a9d8c 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowTabIndentUnitTest.3.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowSpaceIndentUnitTest.4.inc @@ -1,13 +1,13 @@ 1, 117 => 1, 118 => 1, + 123 => 1, ]; case 'DisallowSpaceIndentUnitTest.3.inc': @@ -102,6 +103,17 @@ public function getErrorList($testFile='') 15 => 1, ]; + case 'DisallowSpaceIndentUnitTest.4.inc': + if (PHP_VERSION_ID >= 70300) { + return [ + 7 => 1, + 13 => 1, + ]; + } + + // PHP 7.2 or lower: PHP version which doesn't support flexible heredocs/nowdocs yet. + return []; + case 'DisallowSpaceIndentUnitTest.js': return [3 => 1]; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowTabIndentUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowTabIndentUnitTest.1.inc index cf61177e8..74fa50511 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowTabIndentUnitTest.1.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowTabIndentUnitTest.1.inc @@ -91,3 +91,12 @@ $var = "$hello $there"; Another line. */ + +// A `yield from` can be single-line and multiline and may contain a tab in the whitespace between the keywords. +function myGenerator() { + yield from gen1(); + + yield + from + gen2(); +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowTabIndentUnitTest.1.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowTabIndentUnitTest.1.inc.fixed index 8154179c9..342592120 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowTabIndentUnitTest.1.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowTabIndentUnitTest.1.inc.fixed @@ -91,3 +91,12 @@ $var = "$hello $there"; Another line. */ + +// A `yield from` can be single-line and multiline and may contain a tab in the whitespace between the keywords. +function myGenerator() { + yield from gen1(); + + yield + from + gen2(); +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowTabIndentUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowTabIndentUnitTest.php index 7a5f15e9f..9618e55d8 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowTabIndentUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/DisallowTabIndentUnitTest.php @@ -50,43 +50,45 @@ public function getErrorList($testFile='') switch ($testFile) { case 'DisallowTabIndentUnitTest.1.inc': return [ - 5 => 2, - 9 => 1, - 15 => 1, - 20 => 2, - 21 => 1, - 22 => 2, - 23 => 1, - 24 => 2, - 31 => 1, - 32 => 2, - 33 => 2, - 41 => 1, - 42 => 1, - 43 => 1, - 44 => 1, - 45 => 1, - 46 => 1, - 47 => 1, - 48 => 1, - 54 => 1, - 55 => 1, - 56 => 1, - 57 => 1, - 58 => 1, - 59 => 1, - 79 => 1, - 80 => 1, - 81 => 1, - 82 => 1, - 83 => 1, - 85 => 1, - 86 => 1, - 87 => 1, - 89 => 1, - 90 => 1, - 92 => 1, - 93 => 1, + 5 => 2, + 9 => 1, + 15 => 1, + 20 => 2, + 21 => 1, + 22 => 2, + 23 => 1, + 24 => 2, + 31 => 1, + 32 => 2, + 33 => 2, + 41 => 1, + 42 => 1, + 43 => 1, + 44 => 1, + 45 => 1, + 46 => 1, + 47 => 1, + 48 => 1, + 54 => 1, + 55 => 1, + 56 => 1, + 57 => 1, + 58 => 1, + 59 => 1, + 79 => 1, + 80 => 1, + 81 => 1, + 82 => 1, + 83 => 1, + 85 => 1, + 86 => 1, + 87 => 1, + 89 => 1, + 90 => 1, + 92 => 1, + 93 => 1, + 97 => 1, + 100 => 1, ]; case 'DisallowTabIndentUnitTest.2.inc': diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/HereNowdocIdentifierSpacingUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/HereNowdocIdentifierSpacingUnitTest.inc new file mode 100644 index 000000000..0121118a5 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/HereNowdocIdentifierSpacingUnitTest.inc @@ -0,0 +1,25 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Standards\Generic\Tests\WhiteSpace; + +use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; + +/** + * Unit test class for the HereNowdocIdentifierSpacing sniff. + * + * @covers \PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace\HereNowdocIdentifierSpacingSniff + */ +final class HereNowdocIdentifierSpacingUnitTest extends AbstractSniffUnitTest +{ + + + /** + * Returns the lines where errors should occur. + * + * The key of the array should represent the line number and the value + * should represent the number of errors that should occur on that line. + * + * @return array + */ + public function getErrorList() + { + return [ + 11 => 1, + 15 => 1, + 19 => 1, + 23 => 1, + ]; + + }//end getErrorList() + + + /** + * Returns the lines where warnings should occur. + * + * The key of the array should represent the line number and the value + * should represent the number of warnings that should occur on that line. + * + * @return array + */ + public function getWarningList() + { + return []; + + }//end getWarningList() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/LanguageConstructSpacingUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/LanguageConstructSpacingUnitTest.1.inc index 1847778d0..571c5e115 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/LanguageConstructSpacingUnitTest.1.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/LanguageConstructSpacingUnitTest.1.inc @@ -89,3 +89,19 @@ $newLine; // The following line must have a single space at the end (after return) return $spaceAndNewLine; + +// Related to issue #529. These should not be auto-fixed as we don't know what to do with the comment. +yield /*comment*/ from $test(); +yield + # comment + from $test(); +yield + // phpcs:ignore Stnd.Category.SniffName + from $test(); + +// Closure use should be ignored. These are subject to their own rules. +$cl = function() use ($b) {}; +$cl = function() use($b) {}; + +goto MyName; +goto MyName; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/LanguageConstructSpacingUnitTest.1.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/LanguageConstructSpacingUnitTest.1.inc.fixed index 4f5d3cec2..e7653d020 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/LanguageConstructSpacingUnitTest.1.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/LanguageConstructSpacingUnitTest.1.inc.fixed @@ -83,3 +83,19 @@ return $newLine; // The following line must have a single space at the end (after return) return $spaceAndNewLine; + +// Related to issue #529. These should not be auto-fixed as we don't know what to do with the comment. +yield /*comment*/ from $test(); +yield + # comment + from $test(); +yield + // phpcs:ignore Stnd.Category.SniffName + from $test(); + +// Closure use should be ignored. These are subject to their own rules. +$cl = function() use ($b) {}; +$cl = function() use($b) {}; + +goto MyName; +goto MyName; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/LanguageConstructSpacingUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/LanguageConstructSpacingUnitTest.php index adac2c843..7a9c01ba0 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/LanguageConstructSpacingUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/LanguageConstructSpacingUnitTest.php @@ -35,42 +35,46 @@ public function getErrorList($testFile='') switch ($testFile) { case 'LanguageConstructSpacingUnitTest.1.inc': return [ - 3 => 1, - 5 => 1, - 8 => 1, - 10 => 1, - 13 => 1, - 15 => 1, - 18 => 1, - 20 => 1, - 23 => 1, - 25 => 1, - 28 => 1, - 30 => 1, - 33 => 1, - 36 => 1, - 39 => 1, - 40 => 1, - 43 => 1, - 44 => 1, - 45 => 1, - 46 => 1, - 48 => 1, - 52 => 1, - 55 => 1, - 56 => 1, - 57 => 2, - 60 => 1, - 63 => 1, - 65 => 1, - 73 => 1, - 75 => 1, - 77 => 1, - 81 => 1, - 83 => 1, - 85 => 1, - 86 => 1, - 90 => 1, + 3 => 1, + 5 => 1, + 8 => 1, + 10 => 1, + 13 => 1, + 15 => 1, + 18 => 1, + 20 => 1, + 23 => 1, + 25 => 1, + 28 => 1, + 30 => 1, + 33 => 1, + 36 => 1, + 39 => 1, + 40 => 1, + 43 => 1, + 44 => 1, + 45 => 1, + 46 => 1, + 48 => 1, + 52 => 1, + 55 => 1, + 56 => 1, + 57 => 2, + 60 => 1, + 63 => 1, + 65 => 1, + 73 => 1, + 75 => 1, + 77 => 1, + 81 => 1, + 83 => 1, + 85 => 1, + 86 => 1, + 90 => 1, + 94 => 1, + 95 => 1, + 98 => 1, + 107 => 1, ]; default: diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.1.inc index 4061aff56..74c5c0728 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.1.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.1.inc @@ -1579,6 +1579,47 @@ foo(function ($foo) { ]; }); +// Issue #110. +echo match (1) { + 0 => match (2) { + 2 => match (3) { + 3 => 3, + default => -1, + }, + }, + 1 => match (2) { + 1 => match (3) { + 3 => 3, + default => -1, + }, + 2 => match (3) { + 3 => 3, + default => -1, + }, + }, +}; + +// Issue #437. +match (true) { + default => [ + 'unrelated' => '', + 'example' => array_filter( + array_map( + function () { + return null; + }, + [] + ) + ) + ] +}; + +// Issue squizlabs/PHP_CodeSniffer#3808 +function test() { + yield + from [ 3, 4 ]; +} + /* ADD NEW TESTS ABOVE THIS LINE AND MAKE SURE THAT THE 1 (space-based) AND 2 (tab-based) FILES ARE IN SYNC! */ ?> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.1.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.1.inc.fixed index 7b5efea36..414ea6f7f 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.1.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.1.inc.fixed @@ -1579,6 +1579,47 @@ foo(function ($foo) { ]; }); +// Issue #110. +echo match (1) { + 0 => match (2) { + 2 => match (3) { + 3 => 3, + default => -1, + }, + }, + 1 => match (2) { + 1 => match (3) { + 3 => 3, + default => -1, + }, + 2 => match (3) { + 3 => 3, + default => -1, + }, + }, +}; + +// Issue #437. +match (true) { + default => [ + 'unrelated' => '', + 'example' => array_filter( + array_map( + function () { + return null; + }, + [] + ) + ) + ] +}; + +// Issue squizlabs/PHP_CodeSniffer#3808 +function test() { + yield + from [ 3, 4 ]; +} + /* ADD NEW TESTS ABOVE THIS LINE AND MAKE SURE THAT THE 1 (space-based) AND 2 (tab-based) FILES ARE IN SYNC! */ ?> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.2.inc index e7253141d..c30e5b8dd 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.2.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.2.inc @@ -1579,6 +1579,47 @@ foo(function ($foo) { ]; }); +// Issue #110. +echo match (1) { + 0 => match (2) { + 2 => match (3) { + 3 => 3, + default => -1, + }, + }, + 1 => match (2) { + 1 => match (3) { + 3 => 3, + default => -1, + }, + 2 => match (3) { + 3 => 3, + default => -1, + }, + }, +}; + +// Issue #437. +match (true) { + default => [ + 'unrelated' => '', + 'example' => array_filter( + array_map( + function () { + return null; + }, + [] + ) + ) + ] +}; + +// Issue squizlabs/PHP_CodeSniffer#3808 +function test() { + yield + from [ 3, 4 ]; +} + /* ADD NEW TESTS ABOVE THIS LINE AND MAKE SURE THAT THE 1 (space-based) AND 2 (tab-based) FILES ARE IN SYNC! */ ?> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.2.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.2.inc.fixed index 57caa2917..4660f7588 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.2.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.2.inc.fixed @@ -1579,6 +1579,47 @@ foo(function ($foo) { ]; }); +// Issue #110. +echo match (1) { + 0 => match (2) { + 2 => match (3) { + 3 => 3, + default => -1, + }, + }, + 1 => match (2) { + 1 => match (3) { + 3 => 3, + default => -1, + }, + 2 => match (3) { + 3 => 3, + default => -1, + }, + }, +}; + +// Issue #437. +match (true) { + default => [ + 'unrelated' => '', + 'example' => array_filter( + array_map( + function () { + return null; + }, + [] + ) + ) + ] +}; + +// Issue squizlabs/PHP_CodeSniffer#3808 +function test() { + yield + from [ 3, 4 ]; +} + /* ADD NEW TESTS ABOVE THIS LINE AND MAKE SURE THAT THE 1 (space-based) AND 2 (tab-based) FILES ARE IN SYNC! */ ?> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.3.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.3.inc index 55d1a06ab..dd095617c 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.3.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.3.inc @@ -1,6 +1,6 @@ -phpcs:set Generic.WhiteSpace.ScopeIndent tabIndent false -phpcs:set Generic.WhiteSpace.ScopeIndent exact true foo() ->bar() ->baz(); + +// Issue squizlabs/PHP_CodeSniffer#3808 +function test() { + yield + from [ 3, 4 ]; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.3.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.3.inc.fixed index e9ae5ff39..aaa0b1c81 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.3.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.3.inc.fixed @@ -1,6 +1,6 @@ -phpcs:set Generic.WhiteSpace.ScopeIndent tabIndent false -phpcs:set Generic.WhiteSpace.ScopeIndent exact true foo() ->bar() ->baz(); + +// Issue squizlabs/PHP_CodeSniffer#3808 +function test() { + yield + from [ 3, 4 ]; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.php index 2533b434c..e0d2cf7ca 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/ScopeIndentUnitTest.php @@ -30,6 +30,8 @@ final class ScopeIndentUnitTest extends AbstractSniffUnitTest */ public function setCliValues($testFile, $config) { + $config->setConfigData('scope_indent_debug', '0', true); + // Tab width setting is only needed for the tabbed file. if ($testFile === 'ScopeIndentUnitTest.2.inc') { $config->tabWidth = 4; @@ -84,6 +86,7 @@ public function getErrorList($testFile='') 6 => 1, 7 => 1, 10 => 1, + 33 => 1, ]; } @@ -192,10 +195,10 @@ public function getErrorList($testFile='') 1527 => 1, 1529 => 1, 1530 => 1, - 1590 => 1, - 1591 => 1, - 1592 => 1, - 1593 => 1, + 1631 => 1, + 1632 => 1, + 1633 => 1, + 1634 => 1, ]; }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/SpreadOperatorSpacingAfterUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/SpreadOperatorSpacingAfterUnitTest.1.inc similarity index 94% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/SpreadOperatorSpacingAfterUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/SpreadOperatorSpacingAfterUnitTest.1.inc index fb5c18142..6c86ac0b2 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/SpreadOperatorSpacingAfterUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/SpreadOperatorSpacingAfterUnitTest.1.inc @@ -75,5 +75,4 @@ $map = array_map(strtolower(...), $map); // Ignore PHP 8.1 first class callable declarations. $map = array_map(strtolower( ... ), $map); -// Intentional parse error. This has to be the last test in the file. -function bar( ... +bar(... /*comment*/$array); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/SpreadOperatorSpacingAfterUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/SpreadOperatorSpacingAfterUnitTest.1.inc.fixed similarity index 94% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/SpreadOperatorSpacingAfterUnitTest.inc.fixed rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/SpreadOperatorSpacingAfterUnitTest.1.inc.fixed index 9388acfc6..1466a5dbd 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/SpreadOperatorSpacingAfterUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/SpreadOperatorSpacingAfterUnitTest.1.inc.fixed @@ -70,5 +70,4 @@ $map = array_map(strtolower(...), $map); // Ignore PHP 8.1 first class callable declarations. $map = array_map(strtolower( ... ), $map); -// Intentional parse error. This has to be the last test in the file. -function bar( ... +bar(... /*comment*/$array); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/SpreadOperatorSpacingAfterUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/SpreadOperatorSpacingAfterUnitTest.2.inc new file mode 100644 index 000000000..6a753a2a1 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Generic/Tests/WhiteSpace/SpreadOperatorSpacingAfterUnitTest.2.inc @@ -0,0 +1,4 @@ + */ - public function getErrorList() + public function getErrorList($testFile='') { - return [ - 12 => 1, - 13 => 1, - 20 => 2, - 40 => 1, - 41 => 1, - 46 => 2, - 60 => 1, - 61 => 1, - 66 => 2, - ]; + switch ($testFile) { + case 'SpreadOperatorSpacingAfterUnitTest.1.inc': + return [ + 12 => 1, + 13 => 1, + 20 => 2, + 40 => 1, + 41 => 1, + 46 => 2, + 60 => 1, + 61 => 1, + 66 => 2, + 78 => 1, + ]; + + default: + return []; + }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/CSS/BrowserSpecificStylesSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/CSS/BrowserSpecificStylesSniff.php index 904769e12..a9d9ae567 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/CSS/BrowserSpecificStylesSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/CSS/BrowserSpecificStylesSniff.php @@ -11,10 +11,11 @@ namespace PHP_CodeSniffer\Standards\MySource\Sniffs\CSS; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Files\File; -class BrowserSpecificStylesSniff implements Sniff +class BrowserSpecificStylesSniff implements Sniff, DeprecatedSniff { /** @@ -86,4 +87,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'The MySource standard will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Channels/DisallowSelfActionsSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Channels/DisallowSelfActionsSniff.php index 91004a84d..6f199bf3f 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Channels/DisallowSelfActionsSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Channels/DisallowSelfActionsSniff.php @@ -11,11 +11,12 @@ namespace PHP_CodeSniffer\Standards\MySource\Sniffs\Channels; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Util\Tokens; -class DisallowSelfActionsSniff implements Sniff +class DisallowSelfActionsSniff implements Sniff, DeprecatedSniff { @@ -124,4 +125,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'The MySource standard will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Channels/IncludeOwnSystemSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Channels/IncludeOwnSystemSniff.php index 83bb5ff31..68e498b68 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Channels/IncludeOwnSystemSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Channels/IncludeOwnSystemSniff.php @@ -11,10 +11,11 @@ namespace PHP_CodeSniffer\Standards\MySource\Sniffs\Channels; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Files\File; -class IncludeOwnSystemSniff implements Sniff +class IncludeOwnSystemSniff implements Sniff, DeprecatedSniff { @@ -97,4 +98,40 @@ protected function getIncludedClassFromToken( }//end getIncludedClassFromToken() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'The MySource standard will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Channels/IncludeSystemSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Channels/IncludeSystemSniff.php index 063dab4a8..316151460 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Channels/IncludeSystemSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Channels/IncludeSystemSniff.php @@ -12,10 +12,11 @@ namespace PHP_CodeSniffer\Standards\MySource\Sniffs\Channels; use PHP_CodeSniffer\Sniffs\AbstractScopeSniff; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Util\Tokens; -class IncludeSystemSniff extends AbstractScopeSniff +class IncludeSystemSniff extends AbstractScopeSniff implements DeprecatedSniff { /** @@ -313,4 +314,40 @@ protected function getIncludedClassFromToken(File $phpcsFile, array $tokens, $st }//end getIncludedClassFromToken() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'The MySource standard will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Channels/UnusedSystemSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Channels/UnusedSystemSniff.php index 0f20f70b9..f32279245 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Channels/UnusedSystemSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Channels/UnusedSystemSniff.php @@ -11,10 +11,11 @@ namespace PHP_CodeSniffer\Standards\MySource\Sniffs\Channels; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Files\File; -class UnusedSystemSniff implements Sniff +class UnusedSystemSniff implements Sniff, DeprecatedSniff { @@ -140,4 +141,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'The MySource standard will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Commenting/FunctionCommentSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Commenting/FunctionCommentSniff.php index da00c903f..22d4135b0 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Commenting/FunctionCommentSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Commenting/FunctionCommentSniff.php @@ -13,11 +13,12 @@ namespace PHP_CodeSniffer\Standards\MySource\Sniffs\Commenting; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Standards\Squiz\Sniffs\Commenting\FunctionCommentSniff as SquizFunctionCommentSniff; use PHP_CodeSniffer\Util\Tokens; use PHP_CodeSniffer\Files\File; -class FunctionCommentSniff extends SquizFunctionCommentSniff +class FunctionCommentSniff extends SquizFunctionCommentSniff implements DeprecatedSniff { @@ -83,4 +84,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'The MySource standard will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Debug/DebugCodeSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Debug/DebugCodeSniff.php index d40e064e8..634bdf924 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Debug/DebugCodeSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Debug/DebugCodeSniff.php @@ -11,10 +11,11 @@ namespace PHP_CodeSniffer\Standards\MySource\Sniffs\Debug; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Files\File; -class DebugCodeSniff implements Sniff +class DebugCodeSniff implements Sniff, DeprecatedSniff { @@ -54,4 +55,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'The MySource standard will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Debug/FirebugConsoleSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Debug/FirebugConsoleSniff.php index 1f56a0e28..d9c782314 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Debug/FirebugConsoleSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Debug/FirebugConsoleSniff.php @@ -11,10 +11,11 @@ namespace PHP_CodeSniffer\Standards\MySource\Sniffs\Debug; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Files\File; -class FirebugConsoleSniff implements Sniff +class FirebugConsoleSniff implements Sniff, DeprecatedSniff { /** @@ -63,4 +64,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'The MySource standard will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Objects/AssignThisSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Objects/AssignThisSniff.php index 97732872c..abfe65cbe 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Objects/AssignThisSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Objects/AssignThisSniff.php @@ -11,10 +11,11 @@ namespace PHP_CodeSniffer\Standards\MySource\Sniffs\Objects; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Files\File; -class AssignThisSniff implements Sniff +class AssignThisSniff implements Sniff, DeprecatedSniff { /** @@ -80,4 +81,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'The MySource standard will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Objects/CreateWidgetTypeCallbackSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Objects/CreateWidgetTypeCallbackSniff.php index 5d8dc9968..eef7c49a2 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Objects/CreateWidgetTypeCallbackSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Objects/CreateWidgetTypeCallbackSniff.php @@ -11,11 +11,12 @@ namespace PHP_CodeSniffer\Standards\MySource\Sniffs\Objects; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Util\Tokens; -class CreateWidgetTypeCallbackSniff implements Sniff +class CreateWidgetTypeCallbackSniff implements Sniff, DeprecatedSniff { /** @@ -217,4 +218,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'The MySource standard will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Objects/DisallowNewWidgetSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Objects/DisallowNewWidgetSniff.php index 693a03714..505da0985 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Objects/DisallowNewWidgetSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Objects/DisallowNewWidgetSniff.php @@ -11,10 +11,11 @@ namespace PHP_CodeSniffer\Standards\MySource\Sniffs\Objects; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Files\File; -class DisallowNewWidgetSniff implements Sniff +class DisallowNewWidgetSniff implements Sniff, DeprecatedSniff { @@ -58,4 +59,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'The MySource standard will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/PHP/AjaxNullComparisonSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/PHP/AjaxNullComparisonSniff.php index 06c251271..d18982762 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/PHP/AjaxNullComparisonSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/PHP/AjaxNullComparisonSniff.php @@ -14,10 +14,11 @@ namespace PHP_CodeSniffer\Standards\MySource\Sniffs\PHP; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Files\File; -class AjaxNullComparisonSniff implements Sniff +class AjaxNullComparisonSniff implements Sniff, DeprecatedSniff { @@ -102,4 +103,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'The MySource standard will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/PHP/EvalObjectFactorySniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/PHP/EvalObjectFactorySniff.php index 6684691f3..1a88beda6 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/PHP/EvalObjectFactorySniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/PHP/EvalObjectFactorySniff.php @@ -11,11 +11,12 @@ namespace PHP_CodeSniffer\Standards\MySource\Sniffs\PHP; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Util\Tokens; -class EvalObjectFactorySniff implements Sniff +class EvalObjectFactorySniff implements Sniff, DeprecatedSniff { @@ -113,4 +114,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'The MySource standard will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/PHP/GetRequestDataSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/PHP/GetRequestDataSniff.php index a07677968..fa8374fef 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/PHP/GetRequestDataSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/PHP/GetRequestDataSniff.php @@ -11,10 +11,11 @@ namespace PHP_CodeSniffer\Standards\MySource\Sniffs\PHP; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Files\File; -class GetRequestDataSniff implements Sniff +class GetRequestDataSniff implements Sniff, DeprecatedSniff { @@ -105,4 +106,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'The MySource standard will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/PHP/ReturnFunctionValueSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/PHP/ReturnFunctionValueSniff.php index 697e91dc7..fe7c3d434 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/PHP/ReturnFunctionValueSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/PHP/ReturnFunctionValueSniff.php @@ -11,10 +11,11 @@ namespace PHP_CodeSniffer\Standards\MySource\Sniffs\PHP; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Files\File; -class ReturnFunctionValueSniff implements Sniff +class ReturnFunctionValueSniff implements Sniff, DeprecatedSniff { @@ -62,4 +63,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'The MySource standard will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Strings/JoinStringsSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Strings/JoinStringsSniff.php index ee527b41b..bfa014909 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Strings/JoinStringsSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/MySource/Sniffs/Strings/JoinStringsSniff.php @@ -11,11 +11,12 @@ namespace PHP_CodeSniffer\Standards\MySource\Sniffs\Strings; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Util\Tokens; -class JoinStringsSniff implements Sniff +class JoinStringsSniff implements Sniff, DeprecatedSniff { /** @@ -75,4 +76,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'The MySource standard will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/Classes/ClassDeclarationStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/Classes/ClassDeclarationStandard.xml index b5d53fdf0..c6de4fecf 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/Classes/ClassDeclarationStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/Classes/ClassDeclarationStandard.xml @@ -1,7 +1,7 @@ - + @@ -12,10 +12,64 @@ class Foo } ]]>
- + { +class BraceOnSignatureLine { } + +class BlankLineBetween + +{ +} + ]]> + +
+ + + { +} + ]]> + + + public function __construct() {} +} + ]]> + + + + + + + + { + } +} + +class NotIndented +{ +} + ]]> + + + { +} +} + +class NotIndented + { + } ]]> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/Commenting/FileCommentStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/Commenting/FileCommentStandard.xml index eef0b4e39..190670f75 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/Commenting/FileCommentStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/Commenting/FileCommentStandard.xml @@ -1,7 +1,14 @@ @@ -231,16 +238,14 @@ */ ]]> - + @package Foo_Helpers - * @category Foo + * @category Foo + * @package Foo_Helpers * @author Marty McFly * @copyright 2013-2014 Foo Inc. * @license MIT License @@ -267,14 +272,16 @@ */ ]]> - + @package Foo_Helpers + * @category Foo * @author Marty McFly * @copyright 2013-2014 Foo Inc. * @license MIT License diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/Files/IncludingFileStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/Files/IncludingFileStandard.xml index 6d115be76..912fa5e0e 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/Files/IncludingFileStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/Files/IncludingFileStandard.xml @@ -10,12 +10,12 @@ ]]> - + - + ('PHP/CodeSniffer.php'); ]]> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/Files/LineLengthStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/Files/LineLengthStandard.xml deleted file mode 100644 index e4911ef3b..000000000 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/Files/LineLengthStandard.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/Functions/FunctionCallSignatureStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/Functions/FunctionCallSignatureStandard.xml index f87422778..2f539c9b5 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/Functions/FunctionCallSignatureStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/Functions/FunctionCallSignatureStandard.xml @@ -1,16 +1,16 @@ - + - + ( $bar, $baz, $quux ) ; ]]> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/Functions/ValidDefaultValueStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/Functions/ValidDefaultValueStandard.xml index 56196cb62..ef9bc3262 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/Functions/ValidDefaultValueStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/Functions/ValidDefaultValueStandard.xml @@ -5,7 +5,7 @@ ]]> - + $persistent = false) { @@ -13,7 +13,7 @@ function connect($dsn, $persistent = false) } ]]> - + $persistent = false, $dsn) { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/NamingConventions/ValidClassNameStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/NamingConventions/ValidClassNameStandard.xml index d16087919..052fb2bab 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/NamingConventions/ValidClassNameStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Docs/NamingConventions/ValidClassNameStandard.xml @@ -5,14 +5,14 @@ ]]> - + - + - + - + - + numTokens + 1); + return $phpcsFile->numTokens; } else if ($tokens[$commentStart]['code'] === T_COMMENT) { $error = 'You must use "/**" style comments for a file comment'; $phpcsFile->addError($error, $errorToken, 'WrongStyle'); $phpcsFile->recordMetric($stackPtr, 'File has doc comment', 'yes'); - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; } else if ($commentStart === false || $tokens[$commentStart]['code'] !== T_DOC_COMMENT_OPEN_TAG ) { $phpcsFile->addError('Missing file doc comment', $errorToken, 'Missing'); $phpcsFile->recordMetric($stackPtr, 'File has doc comment', 'no'); - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; } $commentEnd = $tokens[$commentStart]['comment_closer']; @@ -178,7 +178,7 @@ public function process(File $phpcsFile, $stackPtr) if (in_array($tokens[$nextToken]['code'], $ignore, true) === true) { $phpcsFile->addError('Missing file doc comment', $stackPtr, 'Missing'); $phpcsFile->recordMetric($stackPtr, 'File has doc comment', 'no'); - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; } $phpcsFile->recordMetric($stackPtr, 'File has doc comment', 'yes'); @@ -205,7 +205,7 @@ public function process(File $phpcsFile, $stackPtr) $this->processTags($phpcsFile, $stackPtr, $commentStart); // Ignore the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; }//end process() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Sniffs/Commenting/FunctionCommentSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Sniffs/Commenting/FunctionCommentSniff.php index ee242cf6e..d6fe2e825 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Sniffs/Commenting/FunctionCommentSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Sniffs/Commenting/FunctionCommentSniff.php @@ -119,33 +119,44 @@ public function process(File $phpcsFile, $stackPtr) return; } + // Check there are no blank lines in the preamble for the property, + // but ignore blank lines _within_ attributes as that's not the concern of this sniff. if ($tokens[$commentEnd]['line'] !== ($tokens[$stackPtr]['line'] - 1)) { for ($i = ($commentEnd + 1); $i < $stackPtr; $i++) { - if ($tokens[$i]['column'] !== 1) { + // Skip over the contents of attributes. + if (isset($tokens[$i]['attribute_closer']) === true) { + $i = $tokens[$i]['attribute_closer']; continue; } - if ($tokens[$i]['code'] === T_WHITESPACE - && $tokens[$i]['line'] !== $tokens[($i + 1)]['line'] + if ($tokens[$i]['column'] !== 1 + || $tokens[$i]['code'] !== T_WHITESPACE + || $tokens[$i]['line'] === $tokens[($i + 1)]['line'] + // Do not report blank lines after a PHPCS annotation as removing the blank lines could change the meaning. + || isset(Tokens::$phpcsCommentTokens[$tokens[($i - 1)]['code']]) === true ) { - $error = 'There must be no blank lines after the function comment'; - $fix = $phpcsFile->addFixableError($error, $commentEnd, 'SpacingAfter'); + continue; + } - if ($fix === true) { - $phpcsFile->fixer->beginChangeset(); + $nextNonWhitespace = $phpcsFile->findNext(T_WHITESPACE, ($i + 1), null, true); + $error = 'There must be no blank lines between the function comment and the declaration'; + $fix = $phpcsFile->addFixableError($error, $i, 'SpacingAfter'); - while ($i < $stackPtr - && $tokens[$i]['code'] === T_WHITESPACE - && $tokens[$i]['line'] !== $tokens[($i + 1)]['line'] - ) { - $phpcsFile->fixer->replaceToken($i++, ''); + if ($fix === true) { + $phpcsFile->fixer->beginChangeset(); + + for ($j = $i; $j < $nextNonWhitespace; $j++) { + if ($tokens[$j]['line'] === $tokens[$nextNonWhitespace]['line']) { + break; } - $phpcsFile->fixer->endChangeset(); + $phpcsFile->fixer->replaceToken($j, ''); } - break; + $phpcsFile->fixer->endChangeset(); } + + $i = $nextNonWhitespace; }//end for }//end if diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Sniffs/Functions/FunctionDeclarationSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Sniffs/Functions/FunctionDeclarationSniff.php index 548565f16..93ccd89a2 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Sniffs/Functions/FunctionDeclarationSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Sniffs/Functions/FunctionDeclarationSniff.php @@ -103,10 +103,10 @@ public function process(File $phpcsFile, $stackPtr) // enforced by the previous check because there is no content between the keywords // and the opening parenthesis. // Unfinished closures are tokenized as T_FUNCTION however, and can be excluded - // by checking for the scope_opener. - if ($tokens[$stackPtr]['code'] === T_FUNCTION - && (isset($tokens[$stackPtr]['scope_opener']) === true || $phpcsFile->getMethodProperties($stackPtr)['has_body'] === false) - ) { + // by checking if the function has a name. + $methodProps = $phpcsFile->getMethodProperties($stackPtr); + $methodName = $phpcsFile->getDeclarationName($stackPtr); + if ($tokens[$stackPtr]['code'] === T_FUNCTION && $methodName !== null) { if ($tokens[($openBracket - 1)]['content'] === $phpcsFile->eolChar) { $spaces = 'newline'; } else if ($tokens[($openBracket - 1)]['code'] === T_WHITESPACE) { @@ -125,25 +125,27 @@ public function process(File $phpcsFile, $stackPtr) } // Must be no space before semicolon in abstract/interface methods. - if ($phpcsFile->getMethodProperties($stackPtr)['has_body'] === false) { + if ($methodProps['has_body'] === false) { $end = $phpcsFile->findNext(T_SEMICOLON, $closeBracket); - if ($tokens[($end - 1)]['content'] === $phpcsFile->eolChar) { - $spaces = 'newline'; - } else if ($tokens[($end - 1)]['code'] === T_WHITESPACE) { - $spaces = $tokens[($end - 1)]['length']; - } else { - $spaces = 0; - } + if ($end !== false) { + if ($tokens[($end - 1)]['content'] === $phpcsFile->eolChar) { + $spaces = 'newline'; + } else if ($tokens[($end - 1)]['code'] === T_WHITESPACE) { + $spaces = $tokens[($end - 1)]['length']; + } else { + $spaces = 0; + } - if ($spaces !== 0) { - $error = 'Expected 0 spaces before semicolon; %s found'; - $data = [$spaces]; - $fix = $phpcsFile->addFixableError($error, $end, 'SpaceBeforeSemicolon', $data); - if ($fix === true) { - $phpcsFile->fixer->replaceToken(($end - 1), ''); + if ($spaces !== 0) { + $error = 'Expected 0 spaces before semicolon; %s found'; + $data = [$spaces]; + $fix = $phpcsFile->addFixableError($error, $end, 'SpaceBeforeSemicolon', $data); + if ($fix === true) { + $phpcsFile->fixer->replaceToken(($end - 1), ''); + } } } - } + }//end if }//end if // Must be one space before and after USE keyword for closures. diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Sniffs/NamingConventions/ValidVariableNameSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Sniffs/NamingConventions/ValidVariableNameSniff.php index 48674b1e8..483638006 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Sniffs/NamingConventions/ValidVariableNameSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Sniffs/NamingConventions/ValidVariableNameSniff.php @@ -37,6 +37,10 @@ protected function processMemberVar(File $phpcsFile, $stackPtr) $memberName = ltrim($tokens[$stackPtr]['content'], '$'); $scope = $memberProps['scope']; $scopeSpecified = $memberProps['scope_specified']; + if ($scopeSpecified === false && $memberProps['set_scope'] !== false) { + // Implicit `public` visibility for property with asymmetric visibility. + $scopeSpecified = true; + } if ($memberProps['scope'] === 'private') { $isPublic = false; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php index dd395324f..cb8e46d52 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Sniffs/WhiteSpace/ScopeClosingBraceSniff.php @@ -93,16 +93,19 @@ public function process(File $phpcsFile, $stackPtr) } // Check that the closing brace is on it's own line. - $lastContent = $phpcsFile->findPrevious( - [ - T_WHITESPACE, - T_INLINE_HTML, - T_OPEN_TAG, - ], - ($scopeEnd - 1), - $scopeStart, - true - ); + for ($lastContent = ($scopeEnd - 1); $lastContent > $scopeStart; $lastContent--) { + if ($tokens[$lastContent]['code'] === T_WHITESPACE || $tokens[$lastContent]['code'] === T_OPEN_TAG) { + continue; + } + + if ($tokens[$lastContent]['code'] === T_INLINE_HTML + && ltrim($tokens[$lastContent]['content']) === '' + ) { + continue; + } + + break; + } if ($tokens[$lastContent]['line'] === $tokens[$scopeEnd]['line']) { $error = 'Closing brace must be on a line by itself'; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Commenting/FunctionCommentUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Commenting/FunctionCommentUnitTest.inc index a20ba3a72..9c1fc014e 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Commenting/FunctionCommentUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Commenting/FunctionCommentUnitTest.inc @@ -510,3 +510,41 @@ class SpacingAfter { public function multipleLinesSomeEmpty() {} } + +class HandleBlankLinesBetweenDocblockAndDeclarationWithAttributes +{ + /** + * Blank line between docblock and attribute. + * + * @return mixed + */ + + #[ReturnTypeWillChange] + + + + + + #[ + + AnotherAttribute + + ]#[AndAThirdAsWell] + + public function blankLineDetectionA() + { + + }//end blankLineDetectionA() + + /** + * Blank line between attribute and function declaration. + * + * @return mixed + */ + #[ReturnTypeWillChange] + + public function blankLineDetectionB() + { + + }//end blankLineDetectionB() +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Commenting/FunctionCommentUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Commenting/FunctionCommentUnitTest.inc.fixed index fc6d4f7e7..f2736348b 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Commenting/FunctionCommentUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Commenting/FunctionCommentUnitTest.inc.fixed @@ -489,3 +489,33 @@ class SpacingAfter { */ public function multipleLinesSomeEmpty() {} } + +class HandleBlankLinesBetweenDocblockAndDeclarationWithAttributes +{ + /** + * Blank line between docblock and attribute. + * + * @return mixed + */ + #[ReturnTypeWillChange] + #[ + + AnotherAttribute + + ]#[AndAThirdAsWell] + public function blankLineDetectionA() + { + + }//end blankLineDetectionA() + + /** + * Blank line between attribute and function declaration. + * + * @return mixed + */ + #[ReturnTypeWillChange] + public function blankLineDetectionB() + { + + }//end blankLineDetectionB() +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Commenting/FunctionCommentUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Commenting/FunctionCommentUnitTest.php index 62863be62..7dc2e4ae6 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Commenting/FunctionCommentUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Commenting/FunctionCommentUnitTest.php @@ -75,11 +75,16 @@ public function getErrorList() 364 => 1, 406 => 1, 417 => 1, - 455 => 1, - 464 => 1, - 473 => 1, - 485 => 1, - 501 => 1, + 456 => 1, + 466 => 1, + 474 => 1, + 476 => 1, + 486 => 1, + 502 => 1, + 521 => 1, + 523 => 1, + 533 => 1, + 545 => 1, ]; }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Commenting/InlineCommentUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Commenting/InlineCommentUnitTest.inc index 187228c2a..092fbfdc3 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Commenting/InlineCommentUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Commenting/InlineCommentUnitTest.inc @@ -27,3 +27,5 @@ function test() ### use the code from the regex ### over hre ### ok? + +#️⃣ Apparently the emoji keycap number sign (hash) also works and turns this into a comment. diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Commenting/InlineCommentUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Commenting/InlineCommentUnitTest.inc.fixed index 7bb6c3fb0..4024b4d26 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Commenting/InlineCommentUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Commenting/InlineCommentUnitTest.inc.fixed @@ -27,3 +27,5 @@ function test() // use the code from the regex // over hre // ok? + +// ️⃣ Apparently the emoji keycap number sign (hash) also works and turns this into a comment. diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Commenting/InlineCommentUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Commenting/InlineCommentUnitTest.php index 457b5d896..7d107dd34 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Commenting/InlineCommentUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Commenting/InlineCommentUnitTest.php @@ -37,6 +37,7 @@ public function getErrorList() 27 => 1, 28 => 1, 29 => 1, + 31 => 1, ]; }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Functions/FunctionDeclarationUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Functions/FunctionDeclarationUnitTest.1.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Functions/FunctionDeclarationUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Functions/FunctionDeclarationUnitTest.1.inc diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Functions/FunctionDeclarationUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Functions/FunctionDeclarationUnitTest.1.inc.fixed similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Functions/FunctionDeclarationUnitTest.inc.fixed rename to app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Functions/FunctionDeclarationUnitTest.1.inc.fixed diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Functions/FunctionDeclarationUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Functions/FunctionDeclarationUnitTest.2.inc new file mode 100644 index 000000000..719f703b0 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Functions/FunctionDeclarationUnitTest.2.inc @@ -0,0 +1,7 @@ + 1, 4 => 1, 5 => 1, @@ -108,8 +109,9 @@ public function getErrorList($testFile='') 483 => 1, 490 => 2, ]; - } else { - $errors = [ + + case 'FunctionDeclarationUnitTest.js': + return [ 3 => 1, 4 => 1, 5 => 1, @@ -121,9 +123,15 @@ public function getErrorList($testFile='') 41 => 1, 48 => 1, ]; - }//end if - return $errors; + case 'FunctionDeclarationUnitTest.4.inc': + return [ + 7 => 1, + ]; + + default: + return []; + }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Functions/ValidDefaultValueUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Functions/ValidDefaultValueUnitTest.1.inc similarity index 95% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Functions/ValidDefaultValueUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Functions/ValidDefaultValueUnitTest.1.inc index 8f8d64ab7..f134c16e0 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Functions/ValidDefaultValueUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Functions/ValidDefaultValueUnitTest.1.inc @@ -109,11 +109,8 @@ class OnlyConstructorPropertyPromotion { class ConstructorPropertyPromotionMixedWithNormalParams { public function __construct( - public string $name = '', + public(set) string $name = '', ?int $optionalParam = 0, mixed $requiredParam, ) {} } - -// Intentional syntax error. Must be last thing in the file. -function diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Functions/ValidDefaultValueUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Functions/ValidDefaultValueUnitTest.2.inc new file mode 100644 index 000000000..3cfece7a1 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/Functions/ValidDefaultValueUnitTest.2.inc @@ -0,0 +1,7 @@ + */ - public function getErrorList() + public function getErrorList($testFile='') { - return [ - 29 => 1, - 34 => 1, - 39 => 1, - 71 => 1, - 76 => 1, - 81 => 1, - 91 => 1, - 99 => 1, - 101 => 1, - 106 => 1, - 114 => 1, - ]; + switch ($testFile) { + case 'ValidDefaultValueUnitTest.1.inc': + return [ + 29 => 1, + 34 => 1, + 39 => 1, + 71 => 1, + 76 => 1, + 81 => 1, + 91 => 1, + 99 => 1, + 101 => 1, + 106 => 1, + 114 => 1, + ]; + + default: + return []; + } }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/NamingConventions/ValidVariableNameUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/NamingConventions/ValidVariableNameUnitTest.inc index 3c03da3fd..e99dda197 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/NamingConventions/ValidVariableNameUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/NamingConventions/ValidVariableNameUnitTest.inc @@ -99,3 +99,17 @@ $util->setLogger( private $varName = 'hello'; private $_varName = 'hello'; }); + +class AsymVisibility { + // The read scope is public, but not specified. Enforce the naming conventions anyway. + private(set) $asymPublicImplied = 'hello'; + private(set) $_asymPublicImplied = 'hello'; + + // The read scope is private, so these properties should be handled as private properties. + private private(set) $asymPrivate = 'hello'; + private(set) private $_asymPrivate = 'hello'; + + // The read scope is public/protected, so these properties should be handled as public properties. + public private(set) $asymPublicPrivate = 'hello'; + private(set) protected $_asymPrivateProtected = 'hello'; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/NamingConventions/ValidVariableNameUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/NamingConventions/ValidVariableNameUnitTest.php index c98af3bc5..c13fb1420 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/NamingConventions/ValidVariableNameUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/NamingConventions/ValidVariableNameUnitTest.php @@ -31,13 +31,16 @@ final class ValidVariableNameUnitTest extends AbstractSniffUnitTest public function getErrorList() { return [ - 12 => 1, - 17 => 1, - 22 => 1, - 92 => 1, - 93 => 1, - 94 => 1, - 99 => 1, + 12 => 1, + 17 => 1, + 22 => 1, + 92 => 1, + 93 => 1, + 94 => 1, + 99 => 1, + 106 => 1, + 109 => 1, + 114 => 1, ]; }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/WhiteSpace/ScopeClosingBraceUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/WhiteSpace/ScopeClosingBraceUnitTest.inc index 3f9006792..a97aca760 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/WhiteSpace/ScopeClosingBraceUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/WhiteSpace/ScopeClosingBraceUnitTest.inc @@ -162,3 +162,9 @@ enum Suits {} enum Cards { } + +?> + + +
+
+ + +
+
1, 160 => 1, 164 => 1, + 170 => 1, ]; }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/WhiteSpace/ScopeIndentUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/WhiteSpace/ScopeIndentUnitTest.inc.fixed new file mode 100644 index 000000000..c6b827e7a --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PEAR/Tests/WhiteSpace/ScopeIndentUnitTest.inc.fixed @@ -0,0 +1,314 @@ +hello(); // error here + } + + function hello() // error here + { // no error here as brackets can be put anywhere in the pear standard + echo 'hello'; + } + + function hello2() + { + if (TRUE) { // error here + echo 'hello'; // no error here as its more than 4 spaces. + } else { + echo 'bye'; // error here + } + + while (TRUE) { + echo 'hello'; // error here + } + + do { // error here + echo 'hello'; // error here + } while (TRUE); + } + + function hello3() + { + switch ($hello) { + case 'hello': + break; + } + } + +} + +?> +
+
+
+validate()) {
+    $safe = $form->getSubmitValues();
+}
+?>
+
+open(); // error here + } + + public function open() + { + // Some inline stuff that shouldn't error + if (TRUE) echo 'hello'; + foreach ($tokens as $token) echo $token; + } + + /** + * This is a comment 1. + * This is a comment 2. + * This is a comment 3. + * This is a comment 4. + */ + public function close() + { + // All ok. + if (TRUE) { + if (TRUE) { + } else if (FALSE) { + foreach ($tokens as $token) { + switch ($token) { + case '1': + case '2': + if (true) { + if (false) { + if (false) { + if (false) { + echo 'hello'; + } + } + } + } + break; + case '5': + break; + } + do { + while (true) { + foreach ($tokens as $token) { + for ($i = 0; $i < $token; $i++) { + echo 'hello'; + } + } + } + } while (true); + } + } + } + } + + /* + This is another c style comment 1. + This is another c style comment 2. + This is another c style comment 3. + This is another c style comment 4. + This is another c style comment 5. + */ + + /* + * + * + * + */ + + /** + */ + + /* + This comment has a newline in it. + + */ + + public function read() + { + echo 'hello'; + + // no errors below. + $array = array( + 'this', + 'that' => array( + 'hello', + 'hello again' => array( + 'hello', + ), + ), + ); + } +} + +abstract class Test3 +{ + public function parse() + { + + foreach ($t as $ndx => $token) { + if (is_array($token)) { + echo 'here'; + } else { + $ts[] = array("token" => $token, "value" => ''); + + $last = count($ts) - 1; + + switch ($token) { + case '(': + + if ($last >= 3 && + $ts[0]['token'] != T_CLASS && + $ts[$last - 2]['token'] == T_OBJECT_OPERATOR && + $ts[$last - 3]['token'] == T_VARIABLE ) { + + + if (true) { + echo 'hello'; + } + } + array_push($braces, $token); + break; + } + } + } + } +} + +function test() +{ + $o = <<setConfigData('scope_indent_debug', '0', true); + + }//end setCliValues() + + /** * Returns the lines where errors should occur. * diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR1/Docs/Files/SideEffectsStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR1/Docs/Files/SideEffectsStandard.xml index 0ed04a07d..e82428913 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR1/Docs/Files/SideEffectsStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR1/Docs/Files/SideEffectsStandard.xml @@ -1,7 +1,7 @@ @@ -20,7 +20,7 @@ class Foo { } -echo "Class Foo loaded." +echo "Class Foo loaded."; ]]>
diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR1/Docs/Methods/CamelCapsMethodNameStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR1/Docs/Methods/CamelCapsMethodNameStandard.xml index 8db899d67..66df4e1ce 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR1/Docs/Methods/CamelCapsMethodNameStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR1/Docs/Methods/CamelCapsMethodNameStandard.xml @@ -5,7 +5,7 @@ ]]> - + - + numTokens + 1); + return $phpcsFile->numTokens; }//end process() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Docs/Functions/NullableTypeDeclarationStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Docs/Functions/NullableTypeDeclarationStandard.xml index 2032c9a62..95904c9a8 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Docs/Functions/NullableTypeDeclarationStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Docs/Functions/NullableTypeDeclarationStandard.xml @@ -1,12 +1,12 @@ - - - + - + - - + - - + psr2ControlStructureSpacing->process($phpcsFile, $stackPtr); + $this->psr2ControlStructureSpacing->process($phpcsFile, $stackPtr); + return; } $next = $phpcsFile->findNext(T_WHITESPACE, ($parenOpener + 1), $parenCloser, true); @@ -101,7 +102,19 @@ public function process(File $phpcsFile, $stackPtr) $error = 'The first expression of a multi-line control structure must be on the line after the opening parenthesis'; $fix = $phpcsFile->addFixableError($error, $next, 'FirstExpressionLine'); if ($fix === true) { + $phpcsFile->fixer->beginChangeset(); + if ($tokens[$next]['line'] > ($tokens[$parenOpener]['line'] + 1)) { + for ($i = ($parenOpener + 1); $i < $next; $i++) { + if ($tokens[$next]['line'] === $tokens[$i]['line']) { + break; + } + + $phpcsFile->fixer->replaceToken($i, ''); + } + } + $phpcsFile->fixer->addNewline($parenOpener); + $phpcsFile->fixer->endChangeset(); } } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Sniffs/Files/DeclareStatementSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Sniffs/Files/DeclareStatementSniff.php index d9615f9a4..ea21834a9 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Sniffs/Files/DeclareStatementSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Sniffs/Files/DeclareStatementSniff.php @@ -249,7 +249,7 @@ public function process(File $phpcsFile, $stackPtr) $phpcsFile->fixer->replaceToken($i, ''); } - $phpcsFile->fixer->addNewLineBefore($token); + $phpcsFile->fixer->addNewlineBefore($token); $phpcsFile->fixer->endChangeset(); } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Sniffs/Operators/OperatorSpacingSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Sniffs/Operators/OperatorSpacingSniff.php index 0e58f18c1..41628ce3a 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Sniffs/Operators/OperatorSpacingSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Sniffs/Operators/OperatorSpacingSniff.php @@ -35,6 +35,9 @@ public function register() $targets[] = T_STRING_CONCAT; $targets[] = T_INSTANCEOF; + // Also register the contexts we want to specifically skip over. + $targets[] = T_DECLARE; + return $targets; }//end register() @@ -47,12 +50,25 @@ public function register() * @param int $stackPtr The position of the current token in * the stack passed in $tokens. * - * @return void + * @return void|int Optionally returns a stack pointer. The sniff will not be + * called again on the current file until the returned stack + * pointer is reached. Return `$phpcsFile->numTokens` to skip + * the rest of the file. */ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); + // Skip over declare statements as those should be handled by different sniffs. + if ($tokens[$stackPtr]['code'] === T_DECLARE) { + if (isset($tokens[$stackPtr]['parenthesis_closer']) === false) { + // Parse error / live coding. + return $phpcsFile->numTokens; + } + + return $tokens[$stackPtr]['parenthesis_closer']; + } + if ($this->isOperator($phpcsFile, $stackPtr) === false) { return; } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Sniffs/Properties/ConstantVisibilitySniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Sniffs/Properties/ConstantVisibilitySniff.php index 8bcf0d568..077de01e3 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Sniffs/Properties/ConstantVisibilitySniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Sniffs/Properties/ConstantVisibilitySniff.php @@ -50,8 +50,14 @@ public function process(File $phpcsFile, $stackPtr) $ignore = Tokens::$emptyTokens; $ignore[] = T_FINAL; + $validVisibility = [ + T_PRIVATE => T_PRIVATE, + T_PUBLIC => T_PUBLIC, + T_PROTECTED => T_PROTECTED, + ]; + $prev = $phpcsFile->findPrevious($ignore, ($stackPtr - 1), null, true); - if (isset(Tokens::$scopeModifiers[$tokens[$prev]['code']]) === true) { + if (isset($validVisibility[$tokens[$prev]['code']]) === true) { return; } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/ControlStructures/ControlStructureSpacingUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/ControlStructures/ControlStructureSpacingUnitTest.inc index 9c037d6cd..f37069699 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/ControlStructures/ControlStructureSpacingUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/ControlStructures/ControlStructureSpacingUnitTest.inc @@ -98,3 +98,36 @@ $expr2 && $expr3) { // structure body }; + +// Ensure the sniff handles too many newlines (not just too few). +for ( + + + $i = 0; + $i < 10; + $i++ + + +) {} + +// Ensure the sniff does not remove indentation whitespace when comments are involved. +for ( + + + // comment. + $i = 0; + $i < 10; + $i++ +) {} + +// The sniff treats a comment (ie non-whitespace) as content, but only at the +// start / end of the control structure. So the inner-whitespace here is +// intentionally ignored by this sniff. Additionally, the comment is not indented +// by this sniff when fixing. +for (// comment. + + + $i = 0; + $i < 10; + $i++ +) {} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/ControlStructures/ControlStructureSpacingUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/ControlStructures/ControlStructureSpacingUnitTest.inc.fixed index 7ea61b1e2..d6c3f48c2 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/ControlStructures/ControlStructureSpacingUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/ControlStructures/ControlStructureSpacingUnitTest.inc.fixed @@ -101,3 +101,31 @@ match ( ) { // structure body }; + +// Ensure the sniff handles too many newlines (not just too few). +for ( + $i = 0; + $i < 10; + $i++ +) {} + +// Ensure the sniff does not remove indentation whitespace when comments are involved. +for ( + // comment. + $i = 0; + $i < 10; + $i++ +) {} + +// The sniff treats a comment (ie non-whitespace) as content, but only at the +// start / end of the control structure. So the inner-whitespace here is +// intentionally ignored by this sniff. Additionally, the comment is not indented +// by this sniff when fixing. +for ( +// comment. + + + $i = 0; + $i < 10; + $i++ +) {} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/ControlStructures/ControlStructureSpacingUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/ControlStructures/ControlStructureSpacingUnitTest.php index 69ef8b7c3..3763b5d3c 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/ControlStructures/ControlStructureSpacingUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/ControlStructures/ControlStructureSpacingUnitTest.php @@ -31,25 +31,29 @@ final class ControlStructureSpacingUnitTest extends AbstractSniffUnitTest public function getErrorList() { return [ - 2 => 2, - 16 => 1, - 17 => 1, - 18 => 1, - 22 => 1, - 23 => 1, - 32 => 1, - 33 => 1, - 34 => 1, - 37 => 1, - 38 => 1, - 39 => 1, - 48 => 2, - 58 => 1, - 59 => 1, - 92 => 1, - 96 => 1, - 97 => 1, - 98 => 2, + 2 => 2, + 16 => 1, + 17 => 1, + 18 => 1, + 22 => 1, + 23 => 1, + 32 => 1, + 33 => 1, + 34 => 1, + 37 => 1, + 38 => 1, + 39 => 1, + 48 => 2, + 58 => 1, + 59 => 1, + 92 => 1, + 96 => 1, + 97 => 1, + 98 => 2, + 106 => 1, + 111 => 1, + 117 => 1, + 127 => 1, ]; }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Files/FileHeaderUnitTest.19.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Files/FileHeaderUnitTest.19.inc new file mode 100644 index 000000000..f78e1aa55 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Files/FileHeaderUnitTest.19.inc @@ -0,0 +1,11 @@ + 1, - 4 => 1, - 7 => 1, + 2 => 1, + 4 => 1, + 7 => 1, + 10 => 1, ]; }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Namespaces/CompoundNamespaceDepthUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Namespaces/CompoundNamespaceDepthUnitTest.inc index 3336fc2dc..454f7fc25 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Namespaces/CompoundNamespaceDepthUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Namespaces/CompoundNamespaceDepthUnitTest.inc @@ -29,3 +29,6 @@ use Vendor\Package\SomeNamespace\{ SubnamespaceOne\ClassB, ClassZ, }; + +// Reset the property to its default value. +// phpcs:set PSR12.Namespaces.CompoundNamespaceDepth maxDepth 2 diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Operators/OperatorSpacingUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Operators/OperatorSpacingUnitTest.1.inc similarity index 98% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Operators/OperatorSpacingUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Operators/OperatorSpacingUnitTest.1.inc index c067e6a2a..14cf8e9df 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Operators/OperatorSpacingUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Operators/OperatorSpacingUnitTest.1.inc @@ -75,3 +75,5 @@ function setDefault(#[ImportValue( { // Do something } + +declare(strict_types=1); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Operators/OperatorSpacingUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Operators/OperatorSpacingUnitTest.1.inc.fixed similarity index 98% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Operators/OperatorSpacingUnitTest.inc.fixed rename to app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Operators/OperatorSpacingUnitTest.1.inc.fixed index 76764291f..0f52f1cf7 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Operators/OperatorSpacingUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Operators/OperatorSpacingUnitTest.1.inc.fixed @@ -75,3 +75,5 @@ function setDefault(#[ImportValue( { // Do something } + +declare(strict_types=1); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Operators/OperatorSpacingUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Operators/OperatorSpacingUnitTest.2.inc new file mode 100644 index 000000000..3a0dbac3e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Operators/OperatorSpacingUnitTest.2.inc @@ -0,0 +1,3 @@ + */ - public function getErrorList() + public function getErrorList($testFile='') { - return [ - 2 => 1, - 3 => 2, - 4 => 1, - 5 => 2, - 6 => 4, - 9 => 3, - 10 => 2, - 11 => 3, - 13 => 3, - 14 => 2, - 18 => 1, - 20 => 1, - 22 => 2, - 23 => 2, - 26 => 1, - 37 => 4, - 39 => 1, - 40 => 1, - 44 => 2, - 47 => 2, - ]; + switch ($testFile) { + case 'OperatorSpacingUnitTest.1.inc': + return [ + 2 => 1, + 3 => 2, + 4 => 1, + 5 => 2, + 6 => 4, + 9 => 3, + 10 => 2, + 11 => 3, + 13 => 3, + 14 => 2, + 18 => 1, + 20 => 1, + 22 => 2, + 23 => 2, + 26 => 1, + 37 => 4, + 39 => 1, + 40 => 1, + 44 => 2, + 47 => 2, + ]; + default: + return []; + }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Properties/ConstantVisibilityUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Properties/ConstantVisibilityUnitTest.1.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Properties/ConstantVisibilityUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Properties/ConstantVisibilityUnitTest.1.inc diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Properties/ConstantVisibilityUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Properties/ConstantVisibilityUnitTest.2.inc new file mode 100644 index 000000000..0ca9fb525 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/Tests/Properties/ConstantVisibilityUnitTest.2.inc @@ -0,0 +1,7 @@ + */ - public function getWarningList() + public function getWarningList($testFile='') { - return [ - 4 => 1, - 12 => 1, - 21 => 1, - ]; + switch ($testFile) { + case 'ConstantVisibilityUnitTest.1.inc': + return [ + 4 => 1, + 12 => 1, + 21 => 1, + ]; + + case 'ConstantVisibilityUnitTest.2.inc': + return [ + 6 => 1, + ]; + + default: + return []; + } }//end getWarningList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/ruleset.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/ruleset.xml index a631fed60..2f9ae0a47 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/ruleset.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR12/ruleset.xml @@ -105,7 +105,7 @@ - + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Docs/ControlStructures/SwitchDeclarationStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Docs/ControlStructures/SwitchDeclarationStandard.xml index 1d6d053df..fe4fe3b71 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Docs/ControlStructures/SwitchDeclarationStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Docs/ControlStructures/SwitchDeclarationStandard.xml @@ -1,29 +1,38 @@ - + - + case 'bar': + case 'bar': + break; + default: break; } ]]> - + case 'bar': - break; + CASE 'bar': + break; + Default: + break; } ]]> + + + - + 'bar': @@ -31,7 +40,7 @@ switch ($foo) { } ]]> - + 'bar': @@ -40,8 +49,13 @@ switch ($foo) { ]]> + + + - + : @@ -51,7 +65,7 @@ switch ($foo) { } ]]> - + : @@ -62,6 +76,57 @@ switch ($foo) { ]]> + + + + + + break; +} + ]]> + + + break; +} + ]]> + + + + + + + + return; +} + ]]> + + + echo $foo; return; +} + ]]> + + + + + - + + + + + + + : + break; + default: + break; +} + ]]> + + + ; + break; + default: { + break; + } +} + ]]> + + + + + - + // no break - default: + echo $foo; + // no break + default: break; } ]]> - + : + echo $foo; + default: break; } ]]> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Docs/Methods/MethodDeclarationStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Docs/Methods/MethodDeclarationStandard.xml index e45469e80..91ff8c2cf 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Docs/Methods/MethodDeclarationStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Docs/Methods/MethodDeclarationStandard.xml @@ -37,7 +37,7 @@ class Foo } ]]> - + + use \Baz; ]]> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Sniffs/Classes/ClassDeclarationSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Sniffs/Classes/ClassDeclarationSniff.php index 22cf2abc0..887c552ed 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Sniffs/Classes/ClassDeclarationSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Sniffs/Classes/ClassDeclarationSniff.php @@ -314,7 +314,8 @@ public function processOpen(File $phpcsFile, $stackPtr) if ($checkingImplements === true && $multiLineImplements === true && ($tokens[($className - 1)]['code'] !== T_NS_SEPARATOR - || $tokens[($className - 2)]['code'] !== T_STRING) + || ($tokens[($className - 2)]['code'] !== T_STRING + && $tokens[($className - 2)]['code'] !== T_NAMESPACE)) ) { $prev = $phpcsFile->findPrevious( [ @@ -348,7 +349,10 @@ public function processOpen(File $phpcsFile, $stackPtr) $phpcsFile->fixer->addNewline($prev); $phpcsFile->fixer->endChangeset(); } - } else if ($tokens[$prev]['line'] !== ($tokens[$className]['line'] - 1)) { + } else if ((isset(Tokens::$commentTokens[$tokens[$prev]['code']]) === false + && $tokens[$prev]['line'] !== ($tokens[$className]['line'] - 1)) + || $tokens[$prev]['line'] === $tokens[$className]['line'] + ) { if ($keywordTokenType === T_EXTENDS) { $error = 'Only one interface may be specified per line in a multi-line extends declaration'; $fix = $phpcsFile->addFixableError($error, $className, 'ExtendsInterfaceSameLine'); @@ -397,9 +401,10 @@ public function processOpen(File $phpcsFile, $stackPtr) } }//end if } else if ($tokens[($className - 1)]['code'] !== T_NS_SEPARATOR - || $tokens[($className - 2)]['code'] !== T_STRING + || ($tokens[($className - 2)]['code'] !== T_STRING + && $tokens[($className - 2)]['code'] !== T_NAMESPACE) ) { - // Not part of a longer fully qualified class name. + // Not part of a longer fully qualified or namespace relative class name. if ($tokens[($className - 1)]['code'] === T_COMMA || ($tokens[($className - 1)]['code'] === T_NS_SEPARATOR && $tokens[($className - 2)]['code'] === T_COMMA) @@ -520,11 +525,8 @@ public function processClose(File $phpcsFile, $stackPtr) $ignoreTokens[] = T_WHITESPACE; $ignoreTokens[] = T_COMMENT; $ignoreTokens[] = T_SEMICOLON; - $ignoreTokens[] = T_COMMA; $nextContent = $phpcsFile->findNext($ignoreTokens, ($closeBrace + 1), null, true); - if ($tokens[$nextContent]['content'] !== $phpcsFile->eolChar - && $tokens[$nextContent]['line'] === $tokens[$closeBrace]['line'] - ) { + if ($tokens[$nextContent]['line'] === $tokens[$closeBrace]['line']) { $type = strtolower($tokens[$stackPtr]['content']); $error = 'Closing %s brace must be on a line by itself'; $data = [$type]; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Sniffs/Classes/PropertyDeclarationSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Sniffs/Classes/PropertyDeclarationSniff.php index 550e0458e..8613f34a9 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Sniffs/Classes/PropertyDeclarationSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Sniffs/Classes/PropertyDeclarationSniff.php @@ -9,6 +9,7 @@ namespace PHP_CodeSniffer\Standards\PSR2\Sniffs\Classes; +use Exception; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\AbstractVariableSniff; use PHP_CodeSniffer\Util\Tokens; @@ -42,6 +43,7 @@ protected function processMemberVar(File $phpcsFile, $stackPtr) $find[] = T_VARIABLE; $find[] = T_VAR; $find[] = T_READONLY; + $find[] = T_FINAL; $find[] = T_SEMICOLON; $find[] = T_OPEN_CURLY_BRACKET; @@ -66,7 +68,7 @@ protected function processMemberVar(File $phpcsFile, $stackPtr) if (empty($propertyInfo) === true) { return; } - } catch (\Exception $e) { + } catch (Exception $e) { // Turns out not to be a property after all. return; } @@ -112,31 +114,89 @@ protected function processMemberVar(File $phpcsFile, $stackPtr) }//end if }//end if - if ($propertyInfo['scope_specified'] === false) { + if ($propertyInfo['scope_specified'] === false && $propertyInfo['set_scope'] === false) { $error = 'Visibility must be declared on property "%s"'; $data = [$tokens[$stackPtr]['content']]; $phpcsFile->addError($error, $stackPtr, 'ScopeMissing', $data); } /* - * Note: per PSR-PER section 4.6, the order should be: + * Note: per PSR-PER section 4.6 v 2.1/3.0, the order should be: * - Inheritance modifier: `abstract` or `final`. * - Visibility modifier: `public`, `protected`, or `private`. + * - Set-visibility modifier: `public(set)`, `protected(set)`, or `private(set)` * - Scope modifier: `static`. * - Mutation modifier: `readonly`. * - Type declaration. * - Name. * - * Ref: https://www.php-fig.org/per/coding-style/#46-modifier-keywords + * Ref: + * - https://www.php-fig.org/per/coding-style/#46-modifier-keywords + * - https://github.com/php-fig/per-coding-style/pull/99 * - * At this time (PHP 8.2), inheritance modifiers cannot be applied to properties and - * the `static` and `readonly` modifiers are mutually exclusive and cannot be used together. + * The `static` and `readonly` modifiers are mutually exclusive and cannot be used together. * * Based on that, the below modifier keyword order checks are sufficient (for now). */ - if ($propertyInfo['scope_specified'] === true && $propertyInfo['is_static'] === true) { - $scopePtr = $phpcsFile->findPrevious(Tokens::$scopeModifiers, ($stackPtr - 1)); + $hasVisibilityModifier = ($propertyInfo['scope_specified'] === true || $propertyInfo['set_scope'] !== false); + $lastVisibilityModifier = $phpcsFile->findPrevious(Tokens::$scopeModifiers, ($stackPtr - 1)); + $firstVisibilityModifier = $lastVisibilityModifier; + + if ($propertyInfo['scope_specified'] === true && $propertyInfo['set_scope'] !== false) { + $scopePtr = $phpcsFile->findPrevious([T_PUBLIC, T_PROTECTED, T_PRIVATE], ($stackPtr - 1)); + $setScopePtr = $phpcsFile->findPrevious([T_PUBLIC_SET, T_PROTECTED_SET, T_PRIVATE_SET], ($stackPtr - 1)); + if ($scopePtr > $setScopePtr) { + $error = 'The "read"-visibility must come before the "write"-visibility'; + $fix = $phpcsFile->addFixableError($error, $stackPtr, 'AvizKeywordOrder'); + if ($fix === true) { + $phpcsFile->fixer->beginChangeset(); + + for ($i = ($scopePtr + 1); $scopePtr < $stackPtr; $i++) { + if ($tokens[$i]['code'] !== T_WHITESPACE) { + break; + } + + $phpcsFile->fixer->replaceToken($i, ''); + } + + $phpcsFile->fixer->replaceToken($scopePtr, ''); + $phpcsFile->fixer->addContentBefore($setScopePtr, $tokens[$scopePtr]['content'].' '); + + $phpcsFile->fixer->endChangeset(); + } + } + + $firstVisibilityModifier = min($scopePtr, $setScopePtr); + }//end if + + if ($hasVisibilityModifier === true && $propertyInfo['is_final'] === true) { + $scopePtr = $firstVisibilityModifier; + $finalPtr = $phpcsFile->findPrevious(T_FINAL, ($stackPtr - 1)); + if ($finalPtr > $scopePtr) { + $error = 'The final declaration must come before the visibility declaration'; + $fix = $phpcsFile->addFixableError($error, $stackPtr, 'FinalAfterVisibility'); + if ($fix === true) { + $phpcsFile->fixer->beginChangeset(); + + for ($i = ($finalPtr + 1); $finalPtr < $stackPtr; $i++) { + if ($tokens[$i]['code'] !== T_WHITESPACE) { + break; + } + + $phpcsFile->fixer->replaceToken($i, ''); + } + + $phpcsFile->fixer->replaceToken($finalPtr, ''); + $phpcsFile->fixer->addContentBefore($scopePtr, $tokens[$finalPtr]['content'].' '); + + $phpcsFile->fixer->endChangeset(); + } + } + }//end if + + if ($hasVisibilityModifier === true && $propertyInfo['is_static'] === true) { + $scopePtr = $lastVisibilityModifier; $staticPtr = $phpcsFile->findPrevious(T_STATIC, ($stackPtr - 1)); if ($scopePtr > $staticPtr) { $error = 'The static declaration must come after the visibility declaration'; @@ -144,7 +204,7 @@ protected function processMemberVar(File $phpcsFile, $stackPtr) if ($fix === true) { $phpcsFile->fixer->beginChangeset(); - for ($i = ($scopePtr + 1); $scopePtr < $stackPtr; $i++) { + for ($i = ($staticPtr + 1); $staticPtr < $stackPtr; $i++) { if ($tokens[$i]['code'] !== T_WHITESPACE) { break; } @@ -152,16 +212,16 @@ protected function processMemberVar(File $phpcsFile, $stackPtr) $phpcsFile->fixer->replaceToken($i, ''); } - $phpcsFile->fixer->replaceToken($scopePtr, ''); - $phpcsFile->fixer->addContentBefore($staticPtr, $propertyInfo['scope'].' '); + $phpcsFile->fixer->replaceToken($staticPtr, ''); + $phpcsFile->fixer->addContent($scopePtr, ' '.$tokens[$staticPtr]['content']); $phpcsFile->fixer->endChangeset(); } } }//end if - if ($propertyInfo['scope_specified'] === true && $propertyInfo['is_readonly'] === true) { - $scopePtr = $phpcsFile->findPrevious(Tokens::$scopeModifiers, ($stackPtr - 1)); + if ($hasVisibilityModifier === true && $propertyInfo['is_readonly'] === true) { + $scopePtr = $lastVisibilityModifier; $readonlyPtr = $phpcsFile->findPrevious(T_READONLY, ($stackPtr - 1)); if ($scopePtr > $readonlyPtr) { $error = 'The readonly declaration must come after the visibility declaration'; @@ -169,7 +229,7 @@ protected function processMemberVar(File $phpcsFile, $stackPtr) if ($fix === true) { $phpcsFile->fixer->beginChangeset(); - for ($i = ($scopePtr + 1); $scopePtr < $stackPtr; $i++) { + for ($i = ($readonlyPtr + 1); $readonlyPtr < $stackPtr; $i++) { if ($tokens[$i]['code'] !== T_WHITESPACE) { break; } @@ -177,8 +237,8 @@ protected function processMemberVar(File $phpcsFile, $stackPtr) $phpcsFile->fixer->replaceToken($i, ''); } - $phpcsFile->fixer->replaceToken($scopePtr, ''); - $phpcsFile->fixer->addContentBefore($readonlyPtr, $propertyInfo['scope'].' '); + $phpcsFile->fixer->replaceToken($readonlyPtr, ''); + $phpcsFile->fixer->addContent($scopePtr, ' '.$tokens[$readonlyPtr]['content']); $phpcsFile->fixer->endChangeset(); } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Sniffs/ControlStructures/SwitchDeclarationSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Sniffs/ControlStructures/SwitchDeclarationSniff.php index 4b3b5ad2b..c846e43e8 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Sniffs/ControlStructures/SwitchDeclarationSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Sniffs/ControlStructures/SwitchDeclarationSniff.php @@ -152,7 +152,7 @@ public function process(File $phpcsFile, $stackPtr) $error = 'Terminating statement must be on a line by itself'; $fix = $phpcsFile->addFixableError($error, $nextCloser, 'BreakNotNewLine'); if ($fix === true) { - $phpcsFile->fixer->addNewLine($prev); + $phpcsFile->fixer->addNewline($prev); $phpcsFile->fixer->replaceToken($nextCloser, trim($tokens[$nextCloser]['content'])); } } else { @@ -380,6 +380,7 @@ private function findNestedTerminator($phpcsFile, $stackPtr, $end) T_CONTINUE => T_CONTINUE, T_THROW => T_THROW, T_EXIT => T_EXIT, + T_GOTO => T_GOTO, ]; $terminator = $phpcsFile->findStartOfStatement(($lastToken - 1)); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Sniffs/Files/EndFileNewlineSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Sniffs/Files/EndFileNewlineSniff.php index d5e3e069e..5b2d2817b 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Sniffs/Files/EndFileNewlineSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Sniffs/Files/EndFileNewlineSniff.php @@ -43,7 +43,7 @@ public function register() public function process(File $phpcsFile, $stackPtr) { if ($phpcsFile->findNext(T_INLINE_HTML, ($stackPtr + 1)) !== false) { - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; } // Skip to the end of the file. @@ -64,7 +64,7 @@ public function process(File $phpcsFile, $stackPtr) } $phpcsFile->recordMetric($stackPtr, 'Number of newlines at EOF', '0'); - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; } // Go looking for the last non-empty line. @@ -99,7 +99,7 @@ public function process(File $phpcsFile, $stackPtr) } // Skip the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; }//end process() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Sniffs/Namespaces/UseDeclarationSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Sniffs/Namespaces/UseDeclarationSniff.php index 1882fd970..39c69c8b0 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Sniffs/Namespaces/UseDeclarationSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Sniffs/Namespaces/UseDeclarationSniff.php @@ -152,10 +152,10 @@ public function process(File $phpcsFile, $stackPtr) } } while ($next !== false); - // Remove closing curly,semi-colon and any whitespace between last child and closing curly. + // Remove closing curly, semicolon and any whitespace between last child and closing curly. $next = $phpcsFile->findNext(Tokens::$emptyTokens, ($closingCurly + 1), null, true); if ($next === false || $tokens[$next]['code'] !== T_SEMICOLON) { - // Parse error, forgotten semi-colon. + // Parse error, forgotten semicolon. $next = $closingCurly; } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/Classes/ClassDeclarationUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/Classes/ClassDeclarationUnitTest.inc index 303846b72..1df40d514 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/Classes/ClassDeclarationUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/Classes/ClassDeclarationUnitTest.inc @@ -282,3 +282,65 @@ readonly class ReadonlyClassWithComment { } + +// Safeguard against fixer conflict when there are namespace relative interface names in extends. +interface FooBar extends namespace\BarFoo +{ +} + +// Safeguard against fixer conflict when there are namespace relative interface names in a multi-line implements. +class BarFoo implements + namespace\BarFoo +{ +} + +// Safeguard that the sniff ignores comments between interface names in a multiline implements. +class ClassWithMultiLineImplementsAndIgnoreAnnotation implements + SomeInterface, + // phpcs:disable Stnd.Cat.Sniff -- For reasons. + + \AnotherInterface +{ +} + +class ClassWithMultiLineImplementsAndComment implements + SomeInterface, + // Comment. + +AnotherInterface +{ +} + +class ClassWithMultiLineImplementsAndCommentOnSameLineAsInterfaceName implements + SomeInterface, + /* Comment. */ AnotherInterface +{ +} + +// Verify the `CloseBraceSameLine` error code is thrown when expected. +class ClassBraceNotOnLineByItselfError +{ + public $prop; +} $foo = new ClassBraceNotOnLineByItselfError; + +interface ClassBraceNotOnLineByItselfTrailingCommentIsAllowed +{ + public function myMethod(); +} //end interface -- this comment is allowed. + +trait ClassBraceNotOnLineByItselfTrailingAnnotationIsAllowed +{ +} // phpcs:ignore Stnd.Cat.Sniff -- this comment is also allowed. + +// Issue squizlabs/PHP_CodeSniffer#2621 - fix was superseded by fix for #2678. +$foo->bar( + new class implements Bar { + // ... + }, +); + +enum BraceNotOnLineByItselfCloseTagError +{ +} ?> + +bar( + new class implements Bar { + // ... + }, +); + +enum BraceNotOnLineByItselfCloseTagError +{ +} ?> + + 1, 276 => 1, 282 => 1, + 310 => 1, + 316 => 1, + 324 => 1, + 344 => 1, ]; }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/Classes/PropertyDeclarationUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/Classes/PropertyDeclarationUnitTest.inc index 3e086c6f2..2e1785a20 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/Classes/PropertyDeclarationUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/Classes/PropertyDeclarationUnitTest.inc @@ -85,3 +85,44 @@ class ReadOnlyProp { readonly protected ?string $wrongOrder2; } + +class FinalProperties { + final public int $foo, + $bar, + $var = null; + + final protected (D|N)|false $foo; + final array $foo; + public FINAL ?int $wrongOrder1; + static protected final ?string $wrongOrder2; +} + +class AsymmetricVisibility { + private(set) int $foo, + $bar, + $var = 5; + + public private(set) readonly ?string $spaces; + + protected(set) array $unfixed; + + protected(set) public int $wrongOrder1; + + private(set) protected ?string $wrongOrder2; + + final protected private(set) static bool $correctOrder; + + private(set) static final protected bool $wrongOrder3; + private(set) static protected final bool $wrongOrder4; + final protected(set) static public bool $wrongOrder5; + static public(set) final public bool $wrongOrder6; + + protected private(set) static final bool $wrongOrder7; + protected final private(set) static bool $wrongOrder8; + static public final protected(set) bool $wrongOrder9; + public static public(set) final bool $wrongOrder10; + + private(set) static final bool $wrongOrder11; + final static protected(set) bool $wrongOrder12; + static public(set) final bool $wrongOrder13; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/Classes/PropertyDeclarationUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/Classes/PropertyDeclarationUnitTest.inc.fixed index c4e22fc18..b398e2fe7 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/Classes/PropertyDeclarationUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/Classes/PropertyDeclarationUnitTest.inc.fixed @@ -37,8 +37,8 @@ class ABC { private static $propC; public static $propD; protected static - $propE; - private static /*comment*/ $propF; + $propE; + private static /*comment*/ $propF; } class MyClass @@ -82,3 +82,44 @@ class ReadOnlyProp { protected readonly ?string $wrongOrder2; } + +class FinalProperties { + final public int $foo, + $bar, + $var = null; + + final protected (D|N)|false $foo; + final array $foo; + FINAL public ?int $wrongOrder1; + final protected static ?string $wrongOrder2; +} + +class AsymmetricVisibility { + private(set) int $foo, + $bar, + $var = 5; + + public private(set) readonly ?string $spaces; + + protected(set) array $unfixed; + + public protected(set) int $wrongOrder1; + + protected private(set) ?string $wrongOrder2; + + final protected private(set) static bool $correctOrder; + + final protected private(set) static bool $wrongOrder3; + final protected private(set) static bool $wrongOrder4; + final public protected(set) static bool $wrongOrder5; + final public public(set) static bool $wrongOrder6; + + final protected private(set) static bool $wrongOrder7; + final protected private(set) static bool $wrongOrder8; + final public protected(set) static bool $wrongOrder9; + final public public(set) static bool $wrongOrder10; + + final private(set) static bool $wrongOrder11; + final protected(set) static bool $wrongOrder12; + final public(set) static bool $wrongOrder13; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/Classes/PropertyDeclarationUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/Classes/PropertyDeclarationUnitTest.php index bf7dc29a3..bce3d9f1d 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/Classes/PropertyDeclarationUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/Classes/PropertyDeclarationUnitTest.php @@ -31,31 +31,51 @@ final class PropertyDeclarationUnitTest extends AbstractSniffUnitTest public function getErrorList() { return [ - 7 => 1, - 9 => 2, - 10 => 1, - 11 => 1, - 17 => 1, - 18 => 1, - 23 => 1, - 38 => 1, - 41 => 1, - 42 => 1, - 50 => 2, - 51 => 1, - 55 => 1, - 56 => 1, - 61 => 1, - 62 => 1, - 68 => 1, - 69 => 1, - 71 => 1, - 72 => 1, - 76 => 1, - 80 => 1, - 82 => 1, - 84 => 1, - 86 => 1, + 7 => 1, + 9 => 2, + 10 => 1, + 11 => 1, + 17 => 1, + 18 => 1, + 23 => 1, + 38 => 1, + 41 => 1, + 42 => 1, + 50 => 2, + 51 => 1, + 55 => 1, + 56 => 1, + 61 => 1, + 62 => 1, + 68 => 1, + 69 => 1, + 71 => 1, + 72 => 1, + 76 => 1, + 80 => 1, + 82 => 1, + 84 => 1, + 86 => 1, + 90 => 1, + 94 => 1, + 95 => 1, + 96 => 1, + 97 => 2, + 101 => 1, + 105 => 1, + 109 => 1, + 111 => 1, + 115 => 3, + 116 => 3, + 117 => 2, + 118 => 3, + 120 => 1, + 121 => 1, + 122 => 2, + 123 => 2, + 125 => 1, + 126 => 1, + 127 => 2, ]; }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/ControlStructures/SwitchDeclarationUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/ControlStructures/SwitchDeclarationUnitTest.inc index 2ca60a93e..440cf8a38 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/ControlStructures/SwitchDeclarationUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/ControlStructures/SwitchDeclarationUnitTest.inc @@ -596,3 +596,16 @@ switch (rand()) { default: break; } + +// Fix: goto should be recognized as terminating statement. +switch ( $a ) { + case 1: + doSomething(); + goto jumpOut; + default: + $other = $code; + break; +} + +jumpOut: +doSomething(); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/ControlStructures/SwitchDeclarationUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/ControlStructures/SwitchDeclarationUnitTest.inc.fixed index bbc8b7c48..ca39c76d0 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/ControlStructures/SwitchDeclarationUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/ControlStructures/SwitchDeclarationUnitTest.inc.fixed @@ -591,3 +591,16 @@ switch (rand()) { default: break; } + +// Fix: goto should be recognized as terminating statement. +switch ( $a ) { + case 1: + doSomething(); + goto jumpOut; + default: + $other = $code; + break; +} + +jumpOut: +doSomething(); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/Namespaces/UseDeclarationUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/Namespaces/UseDeclarationUnitTest.1.inc index 61befc9e7..977a7fb22 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/Namespaces/UseDeclarationUnitTest.1.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/Namespaces/UseDeclarationUnitTest.1.inc @@ -38,6 +38,3 @@ enum SomeEnum $x = $foo ? function ($foo) use /* comment */ ($bar): int { return 1; } : $bar; - -// Testcase must be on last line in the file. -use diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/Namespaces/UseDeclarationUnitTest.18.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/Namespaces/UseDeclarationUnitTest.18.inc new file mode 100644 index 000000000..8195f2f58 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/PSR2/Tests/Namespaces/UseDeclarationUnitTest.18.inc @@ -0,0 +1,4 @@ + ['bar']; -]]> + ]]> [ 'bar' ]; -]]> + ]]> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Arrays/ArrayDeclarationStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Arrays/ArrayDeclarationStandard.xml index ce4b9ae68..568fac305 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Arrays/ArrayDeclarationStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Arrays/ArrayDeclarationStandard.xml @@ -10,12 +10,12 @@ ]]> - + - + @@ -27,7 +27,7 @@ $array = Array('val1', 'val2'); ]]> - + 'value1', @@ -35,7 +35,7 @@ $array = array( ); ]]> - + 'value1', 'key2' => 'value2', @@ -49,7 +49,7 @@ $array = array('key1' => 'value1', ]]> - + 'key1' => 'value1', @@ -57,7 +57,7 @@ $array = array( ); ]]> - + 'key1' => 'value1', @@ -72,7 +72,7 @@ $array = array( ]]> - + => 'ValueTen', @@ -80,7 +80,7 @@ $array = array( ); ]]> - + => 'ValueTen', @@ -95,7 +95,7 @@ $array = array( ]]> - + 'value1', @@ -104,7 +104,7 @@ $array = array( ); ]]> - + 'value1', diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Classes/ClassFileNameStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Classes/ClassFileNameStandard.xml new file mode 100644 index 000000000..b25296923 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Classes/ClassFileNameStandard.xml @@ -0,0 +1,47 @@ + + + + + + + Foo.php contents: */ + +class Foo +{ +} + ]]> + + + Foo.php contents: */ + +class MyFoo +{ +} + ]]> + + + + + MyFoo.php contents: */ + +class MyFoo +{ +} + ]]> + + + myFoo.php contents: */ + +class MyFoo +{ +} + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Classes/LowercaseClassKeywordsStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Classes/LowercaseClassKeywordsStandard.xml index 89fcb5de8..610edf62f 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Classes/LowercaseClassKeywordsStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Classes/LowercaseClassKeywordsStandard.xml @@ -1,7 +1,7 @@ @@ -10,14 +10,14 @@ final class Foo extends Bar { } -]]> + ]]> Final Class Foo Extends Bar { } -]]> + ]]> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Classes/SelfMemberReferenceStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Classes/SelfMemberReferenceStandard.xml index 59d193ffd..c4e2e52c9 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Classes/SelfMemberReferenceStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Classes/SelfMemberReferenceStandard.xml @@ -1,63 +1,81 @@ self::foo(); -]]> +class Bar { + public function baz() { + self::foo(); + } +} + ]]> SELF::foo(); -]]> +class Bar { + public function baz() { + SELF::foo(); + } +} + ]]> + + + - + ::foo(); -]]> +class Bar { + public function baz() { + self::foo(); + } +} + ]]> - + :: foo(); -]]> +class Bar { + public function baz() { + self :: foo(); + } +} + ]]> + + + self::bar(); } } -]]> + ]]> Foo -{ - public static function bar() - { - } +class Foo { + public function bar() {} - public static function baz() - { + public function baz() { Foo::bar(); } } -]]> + ]]> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Classes/ValidClassNameStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Classes/ValidClassNameStandard.xml new file mode 100644 index 000000000..cc1a4e9d7 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Classes/ValidClassNameStandard.xml @@ -0,0 +1,39 @@ + + + + + + + PascalCaseStandard +{ +} + ]]> + + + notPascalCaseStandard +{ +} + ]]> + + + + + PSR7Response +{ +} + ]]> + + + PSR7_Response +{ +} + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Commenting/BlockCommentStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Commenting/BlockCommentStandard.xml new file mode 100644 index 000000000..0e6a6b85b --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Commenting/BlockCommentStandard.xml @@ -0,0 +1,280 @@ + + + + + + + /* + A block comment. +*/ + ]]> + + + /** + A block comment. +**/ + ]]> + + + + + /* + * A block comment + * with multiple lines. + */ + ]]> + + + // A block comment +// with multiple lines. + +# A block comment +# with multiple lines. + ]]> + + + + + + + + /* + A block comment. +*/ + ]]> + + + /* A block comment. */ + ]]> + + + + + + + + A block comment. +*/ + ]]> + + + +*/ + ]]> + + + + + + + + A block comment. +*/ + ]]> + + + A block comment. +*/ + ]]> + + + + + + + + A block comment + with multiple lines. + And a second paragraph. +*/ + ]]> + + + A block comment + with + multiple lines. +*/ + ]]> + + + + + + + + * + * A block comment + * with + * multiple lines. + */ + ]]> + + + * with + * multiple lines. +*/ + ]]> + + + + + + + + A block comment. +*/ + ]]> + + + a block comment. +*/ + ]]> + + + + + + + + */ + ]]> + + + */ + ]]> + + + + If asterisks are used, the closer's asterisk should be aligned with these. Otherwise, the closer's asterisk should be aligned with the opener's slash. + + + + * + * A block comment + */ + ]]> + + + */ + ]]> + + + + + /* + A block comment. +*/ + ]]> + + + */ + ]]> + + + + + + + + +echo 'Content'; + ]]> + + + echo 'Content'; + ]]> + + + + + + + + /* + * A block comment + * with + * multiple lines. + */ + ]]> + + + +/* + * A block comment + * with + * multiple lines. + */ + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Commenting/DocCommentAlignmentStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Commenting/DocCommentAlignmentStandard.xml index 414b89a34..17fed42cf 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Commenting/DocCommentAlignmentStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Commenting/DocCommentAlignmentStandard.xml @@ -10,14 +10,14 @@ /** * @see foo() */ -]]> + ]]> * @see foo() */ -]]> + ]]> @@ -26,14 +26,14 @@ /** * @see foo() */ -]]> + ]]> @see foo() */ -]]> + ]]>
diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Commenting/FunctionCommentThrowTagStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Commenting/FunctionCommentThrowTagStandard.xml index 81df2e3fd..e3638a49c 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Commenting/FunctionCommentThrowTagStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Commenting/FunctionCommentThrowTagStandard.xml @@ -15,7 +15,7 @@ function foo() { throw new Exception('Danger!'); } -]]> + ]]> + ]]>
diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/ControlStructures/ForEachLoopDeclarationStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/ControlStructures/ForEachLoopDeclarationStandard.xml index 87c618137..42fa6f439 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/ControlStructures/ForEachLoopDeclarationStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/ControlStructures/ForEachLoopDeclarationStandard.xml @@ -10,14 +10,14 @@ foreach ($foo as $bar => $baz) { echo $baz; } -]]> + ]]> $foo as $bar=>$baz ) { echo $baz; } -]]> + ]]>
@@ -26,14 +26,14 @@ foreach ( $foo as $bar=>$baz foreach ($foo as $bar => $baz) { echo $baz; } -]]> + ]]> AS $bar => $baz) { echo $baz; } -]]> + ]]>
diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/ControlStructures/ForLoopDeclarationStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/ControlStructures/ForLoopDeclarationStandard.xml index bbc439230..37caaded0 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/ControlStructures/ForLoopDeclarationStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/ControlStructures/ForLoopDeclarationStandard.xml @@ -10,14 +10,14 @@ for ($i = 0; $i < 10; $i++) { echo $i; } -]]> + ]]> $i = 0; $i < 10; $i++ ) { echo $i; } -]]> + ]]>
@@ -26,14 +26,14 @@ for ( $i = 0; $i < 10; $i++ ) { for ($i = 0; $i < 10; $i++) { echo $i; } -]]> + ]]> ; $i < 10 ; $i++) { echo $i; } -]]> + ]]>
@@ -42,14 +42,14 @@ for ($i = 0 ; $i < 10 ; $i++) { for ($i = 0; $i < 10; $i++) { echo $i; } -]]> + ]]> $i < 10;$i++) { echo $i; } -]]> + ]]>
diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/ControlStructures/LowercaseDeclarationStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/ControlStructures/LowercaseDeclarationStandard.xml index 699f1f092..d281400be 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/ControlStructures/LowercaseDeclarationStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/ControlStructures/LowercaseDeclarationStandard.xml @@ -1,7 +1,7 @@ @@ -10,14 +10,14 @@ if ($foo) { $bar = true; } -]]> + ]]> IF ($foo) { $bar = true; } -]]> + ]]>
diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Functions/FunctionDuplicateArgumentStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Functions/FunctionDuplicateArgumentStandard.xml deleted file mode 100644 index a890aba68..000000000 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Functions/FunctionDuplicateArgumentStandard.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - isset($foo)) { - echo $foo; -} -]]> - - - isSet($foo)) { - echo $foo; -} -]]> - - - diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Functions/LowercaseFunctionKeywordsStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Functions/LowercaseFunctionKeywordsStandard.xml index 46e8a8f32..fb2ef443c 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Functions/LowercaseFunctionKeywordsStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Functions/LowercaseFunctionKeywordsStandard.xml @@ -1,7 +1,7 @@ @@ -11,7 +11,7 @@ { return true; } -]]> + ]]> + ]]> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/PHP/HeredocStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/PHP/HeredocStandard.xml new file mode 100644 index 000000000..b2a63be39 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/PHP/HeredocStandard.xml @@ -0,0 +1,32 @@ + + + + + + + +some text + + + + <<; + +echo <<<'EOD' +some text +EOD; + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Scope/StaticThisUsageStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Scope/StaticThisUsageStandard.xml index 3c97f54e6..0145657d3 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Scope/StaticThisUsageStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Scope/StaticThisUsageStandard.xml @@ -14,7 +14,7 @@ class Foo return self::$staticMember; } } -]]> + ]]> $this->$staticMember; } } -]]> + ]]> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Strings/EchoedStringsStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Strings/EchoedStringsStandard.xml index 030f2a68c..2bc536ebb 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Strings/EchoedStringsStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/Strings/EchoedStringsStandard.xml @@ -8,12 +8,12 @@ "Hello"; -]]> + ]]> ("Hello"); -]]> + ]]> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/CastSpacingStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/CastSpacingStandard.xml index 0fb195cb6..9529b1fda 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/CastSpacingStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/CastSpacingStandard.xml @@ -8,12 +8,12 @@ int)'42'; -]]> + ]]> int )'42'; -]]> + ]]> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/FunctionClosingBraceSpaceStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/FunctionClosingBraceSpaceStandard.xml new file mode 100644 index 000000000..ccbdfa214 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/FunctionClosingBraceSpaceStandard.xml @@ -0,0 +1,73 @@ + + + + + + + { + +} +]]> + + + {} +]]> + + + + + + + + + { + } + +} +]]> + + + {} + +} +]]> + + + + + + + + + { + } + +} +]]> + + + { + + } + +} +]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/FunctionOpeningBraceSpaceStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/FunctionOpeningBraceSpaceStandard.xml new file mode 100644 index 000000000..c0663c2bd --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/FunctionOpeningBraceSpaceStandard.xml @@ -0,0 +1,26 @@ + + + + + + + return 42; +} + ]]> + + + + return 42; +} + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/FunctionOpeningBraceStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/FunctionOpeningBraceStandard.xml deleted file mode 100644 index d2bc26479..000000000 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/FunctionOpeningBraceStandard.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - { -} -]]> - - - { -} -]]> - - - - - return 42; -} -]]> - - - - return 42; -} -]]> - - - diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/LanguageConstructSpacingStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/LanguageConstructSpacingStandard.xml index 608bed0b4..85838ec32 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/LanguageConstructSpacingStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/LanguageConstructSpacingStandard.xml @@ -1,19 +1,19 @@ "hi"; -]]> + ]]> "hi"; -]]> + ]]> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/MemberVarSpacingStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/MemberVarSpacingStandard.xml new file mode 100644 index 000000000..a551af8a9 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/MemberVarSpacingStandard.xml @@ -0,0 +1,91 @@ + + + + + + + + + protected $var1 = 'value'; +} + ]]> + + + + protected $var1 = 'value'; +} + ]]> + + + + + + + + + + public $var2 = 'value2'; + + public $var3 = 'value3'; +} + ]]> + + + + + + public $var2 = 'value2'; + public $var3 = 'value3'; +} + ]]> + + + + + + + + + public $actions = array(); +}; + ]]> + + + + + public $actions = array(); +}; + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/ObjectOperatorSpacingStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/ObjectOperatorSpacingStandard.xml index c6194d71f..44edc7b5d 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/ObjectOperatorSpacingStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/ObjectOperatorSpacingStandard.xml @@ -8,12 +8,12 @@ ->bar(); -]]> + ]]> -> bar(); -]]> + ]]> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/ScopeClosingBraceStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/ScopeClosingBraceStandard.xml new file mode 100644 index 000000000..3284df973 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/ScopeClosingBraceStandard.xml @@ -0,0 +1,59 @@ + + + + + + + } + +if (!class_exists('Foo')) { + class Foo { + } +} + + + some output + ?> + ]]> + + + } + +if (!class_exists('Foo')) { + class Foo { +} + } + + + some output + ?> + ]]> + + + + + + + + } + ]]> + + + } + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/ScopeKeywordSpacingStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/ScopeKeywordSpacingStandard.xml index 8cadf6692..f226a128b 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/ScopeKeywordSpacingStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/ScopeKeywordSpacingStandard.xml @@ -1,7 +1,7 @@ @@ -10,14 +10,14 @@ public static function foo() { } -]]> + ]]> static function foo() { } -]]> + ]]> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/SemicolonSpacingStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/SemicolonSpacingStandard.xml index 7b2279529..bb9bf8f0c 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/SemicolonSpacingStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/SemicolonSpacingStandard.xml @@ -8,12 +8,12 @@ ; -]]> + ]]> ; -]]> + ]]> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/SuperfluousWhitespaceStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/SuperfluousWhitespaceStandard.xml new file mode 100644 index 000000000..b4ad03d0b --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Docs/WhiteSpace/SuperfluousWhitespaceStandard.xml @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + ]]> + + + + + + + + + + + + + echo 'code here'; +} + ]]> + + + + + + + + + + ]]> + + + + + + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Arrays/ArrayDeclarationSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Arrays/ArrayDeclarationSniff.php index 9cd419822..efad97e4b 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Arrays/ArrayDeclarationSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Arrays/ArrayDeclarationSniff.php @@ -45,6 +45,26 @@ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); + // Prevent acting on short lists inside a foreach (see + // https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/527). + if ($tokens[$stackPtr]['code'] === T_OPEN_SHORT_ARRAY + && isset($tokens[$stackPtr]['nested_parenthesis']) === true + ) { + $nestedParens = $tokens[$stackPtr]['nested_parenthesis']; + $lastParenthesisCloser = end($nestedParens); + $lastParenthesisOpener = key($nestedParens); + + if (isset($tokens[$lastParenthesisCloser]['parenthesis_owner']) === true + && $tokens[$tokens[$lastParenthesisCloser]['parenthesis_owner']]['code'] === T_FOREACH + ) { + $asKeyword = $phpcsFile->findNext(T_AS, ($lastParenthesisOpener + 1), $lastParenthesisCloser); + + if ($asKeyword !== false && $asKeyword < $stackPtr) { + return; + } + } + } + if ($tokens[$stackPtr]['code'] === T_ARRAY) { $phpcsFile->recordMetric($stackPtr, 'Short array syntax used', 'no'); @@ -654,7 +674,11 @@ public function processMultiLineArray($phpcsFile, $stackPtr, $arrayStart, $array if ($tokens[$valuePointer]['code'] === T_CLOSURE || $tokens[$valuePointer]['code'] === T_FN ) { - $ignoreTokens += [T_STATIC => T_STATIC]; + // Check if the closure is static, if it is, override the value pointer as indices before skip static. + $staticPointer = $phpcsFile->findPrevious($ignoreTokens, ($valuePointer - 1), ($arrayStart + 1), true); + if ($staticPointer !== false && $tokens[$staticPointer]['code'] === T_STATIC) { + $valuePointer = $staticPointer; + } } $previous = $phpcsFile->findPrevious($ignoreTokens, ($valuePointer - 1), ($arrayStart + 1), true); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ClassDefinitionClosingBraceSpaceSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ClassDefinitionClosingBraceSpaceSniff.php index 384a8f2b8..608b23a2b 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ClassDefinitionClosingBraceSpaceSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ClassDefinitionClosingBraceSpaceSniff.php @@ -12,10 +12,11 @@ namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\CSS; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Tokens; -class ClassDefinitionClosingBraceSpaceSniff implements Sniff +class ClassDefinitionClosingBraceSpaceSniff implements Sniff, DeprecatedSniff { /** @@ -133,4 +134,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning CSS files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ClassDefinitionNameSpacingSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ClassDefinitionNameSpacingSniff.php index 796bbbaa1..c8bef79a5 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ClassDefinitionNameSpacingSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ClassDefinitionNameSpacingSniff.php @@ -12,10 +12,11 @@ namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\CSS; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Tokens; -class ClassDefinitionNameSpacingSniff implements Sniff +class ClassDefinitionNameSpacingSniff implements Sniff, DeprecatedSniff { /** @@ -110,4 +111,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning CSS files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ClassDefinitionOpeningBraceSpaceSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ClassDefinitionOpeningBraceSpaceSniff.php index 7750fa1de..92e3750a2 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ClassDefinitionOpeningBraceSpaceSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ClassDefinitionOpeningBraceSpaceSniff.php @@ -12,10 +12,11 @@ namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\CSS; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Tokens; -class ClassDefinitionOpeningBraceSpaceSniff implements Sniff +class ClassDefinitionOpeningBraceSpaceSniff implements Sniff, DeprecatedSniff { /** @@ -175,4 +176,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning CSS files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ColonSpacingSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ColonSpacingSniff.php index 6459e035c..21e49b1a2 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ColonSpacingSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ColonSpacingSniff.php @@ -12,10 +12,11 @@ namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\CSS; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Tokens; -class ColonSpacingSniff implements Sniff +class ColonSpacingSniff implements Sniff, DeprecatedSniff { /** @@ -106,4 +107,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning CSS files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ColourDefinitionSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ColourDefinitionSniff.php index 5114a0cb0..ff89dd8d7 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ColourDefinitionSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ColourDefinitionSniff.php @@ -12,9 +12,10 @@ namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\CSS; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; -class ColourDefinitionSniff implements Sniff +class ColourDefinitionSniff implements Sniff, DeprecatedSniff { /** @@ -87,4 +88,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning CSS files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/DisallowMultipleStyleDefinitionsSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/DisallowMultipleStyleDefinitionsSniff.php index 72448a30b..f8db90924 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/DisallowMultipleStyleDefinitionsSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/DisallowMultipleStyleDefinitionsSniff.php @@ -12,9 +12,10 @@ namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\CSS; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; -class DisallowMultipleStyleDefinitionsSniff implements Sniff +class DisallowMultipleStyleDefinitionsSniff implements Sniff, DeprecatedSniff { /** @@ -70,4 +71,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning CSS files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/DuplicateClassDefinitionSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/DuplicateClassDefinitionSniff.php index 82a974c8a..f6b245905 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/DuplicateClassDefinitionSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/DuplicateClassDefinitionSniff.php @@ -12,10 +12,11 @@ namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\CSS; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Tokens; -class DuplicateClassDefinitionSniff implements Sniff +class DuplicateClassDefinitionSniff implements Sniff, DeprecatedSniff { /** @@ -115,4 +116,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning CSS files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/DuplicateStyleDefinitionSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/DuplicateStyleDefinitionSniff.php index e9221470e..4426ad112 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/DuplicateStyleDefinitionSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/DuplicateStyleDefinitionSniff.php @@ -12,9 +12,10 @@ namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\CSS; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; -class DuplicateStyleDefinitionSniff implements Sniff +class DuplicateStyleDefinitionSniff implements Sniff, DeprecatedSniff { /** @@ -87,4 +88,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning CSS files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/EmptyClassDefinitionSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/EmptyClassDefinitionSniff.php index b7671d3e4..eb8b92ede 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/EmptyClassDefinitionSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/EmptyClassDefinitionSniff.php @@ -12,10 +12,11 @@ namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\CSS; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Tokens; -class EmptyClassDefinitionSniff implements Sniff +class EmptyClassDefinitionSniff implements Sniff, DeprecatedSniff { /** @@ -60,4 +61,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning CSS files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/EmptyStyleDefinitionSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/EmptyStyleDefinitionSniff.php index cc3007f2e..5a549372a 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/EmptyStyleDefinitionSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/EmptyStyleDefinitionSniff.php @@ -12,10 +12,11 @@ namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\CSS; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Tokens; -class EmptyStyleDefinitionSniff implements Sniff +class EmptyStyleDefinitionSniff implements Sniff, DeprecatedSniff { /** @@ -63,4 +64,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning CSS files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ForbiddenStylesSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ForbiddenStylesSniff.php index 982f46970..a28f02f83 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ForbiddenStylesSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ForbiddenStylesSniff.php @@ -12,9 +12,10 @@ namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\CSS; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; -class ForbiddenStylesSniff implements Sniff +class ForbiddenStylesSniff implements Sniff, DeprecatedSniff { /** @@ -176,4 +177,40 @@ protected function addError($phpcsFile, $stackPtr, $style, $pattern=null) }//end addError() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning CSS files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/IndentationSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/IndentationSniff.php index 56406ccb3..3b0336b8c 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/IndentationSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/IndentationSniff.php @@ -12,10 +12,11 @@ namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\CSS; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Tokens; -class IndentationSniff implements Sniff +class IndentationSniff implements Sniff, DeprecatedSniff { /** @@ -149,4 +150,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning CSS files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/LowercaseStyleDefinitionSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/LowercaseStyleDefinitionSniff.php index c8393c51c..8246cf5aa 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/LowercaseStyleDefinitionSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/LowercaseStyleDefinitionSniff.php @@ -12,9 +12,10 @@ namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\CSS; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; -class LowercaseStyleDefinitionSniff implements Sniff +class LowercaseStyleDefinitionSniff implements Sniff, DeprecatedSniff { /** @@ -96,4 +97,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning CSS files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/MissingColonSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/MissingColonSniff.php index 83f2a6c82..d86debe05 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/MissingColonSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/MissingColonSniff.php @@ -12,9 +12,10 @@ namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\CSS; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; -class MissingColonSniff implements Sniff +class MissingColonSniff implements Sniff, DeprecatedSniff { /** @@ -90,4 +91,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning CSS files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/NamedColoursSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/NamedColoursSniff.php index 586b4730a..fea0a1551 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/NamedColoursSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/NamedColoursSniff.php @@ -12,9 +12,10 @@ namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\CSS; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; -class NamedColoursSniff implements Sniff +class NamedColoursSniff implements Sniff, DeprecatedSniff { /** @@ -92,4 +93,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning CSS files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/OpacitySniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/OpacitySniff.php index 0c1c553a5..e9dfe7c3e 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/OpacitySniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/OpacitySniff.php @@ -12,10 +12,11 @@ namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\CSS; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Tokens; -class OpacitySniff implements Sniff +class OpacitySniff implements Sniff, DeprecatedSniff { /** @@ -100,4 +101,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning CSS files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/SemicolonSpacingSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/SemicolonSpacingSniff.php index d51431bfc..7c205d818 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/SemicolonSpacingSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/SemicolonSpacingSniff.php @@ -1,6 +1,6 @@ * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) @@ -12,10 +12,11 @@ namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\CSS; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Tokens; -class SemicolonSpacingSniff implements Sniff +class SemicolonSpacingSniff implements Sniff, DeprecatedSniff { /** @@ -73,7 +74,7 @@ public function process(File $phpcsFile, $stackPtr) return; } - // There is a semi-colon, so now find the last token in the statement. + // There is a semicolon, so now find the last token in the statement. $prevNonEmpty = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($endOfThisStatement - 1), null, true); $found = $tokens[($endOfThisStatement - 1)]['length']; if ($tokens[$prevNonEmpty]['line'] !== $tokens[$endOfThisStatement]['line']) { @@ -102,4 +103,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning CSS files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ShorthandSizeSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ShorthandSizeSniff.php index 76e7330c7..252a06d19 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ShorthandSizeSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/CSS/ShorthandSizeSniff.php @@ -12,9 +12,10 @@ namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\CSS; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; -class ShorthandSizeSniff implements Sniff +class ShorthandSizeSniff implements Sniff, DeprecatedSniff { /** @@ -180,4 +181,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning CSS files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Classes/ClassDeclarationSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Classes/ClassDeclarationSniff.php index 3f5e1fbc7..9df6b3939 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Classes/ClassDeclarationSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Classes/ClassDeclarationSniff.php @@ -167,11 +167,28 @@ public function processClose(File $phpcsFile, $stackPtr) }//end if if ($difference !== -1 && $difference !== 1) { - if ($tokens[$nextContent]['code'] === T_DOC_COMMENT_OPEN_TAG) { - $next = $phpcsFile->findNext(T_WHITESPACE, ($tokens[$nextContent]['comment_closer'] + 1), null, true); - if ($next !== false && $tokens[$next]['code'] === T_FUNCTION) { - return; + for ($nextSignificant = $nextContent; $nextSignificant < $phpcsFile->numTokens; $nextSignificant++) { + if ($tokens[$nextSignificant]['code'] === T_WHITESPACE) { + continue; } + + if ($tokens[$nextSignificant]['code'] === T_DOC_COMMENT_OPEN_TAG) { + $nextSignificant = $tokens[$nextSignificant]['comment_closer']; + continue; + } + + if ($tokens[$nextSignificant]['code'] === T_ATTRIBUTE + && isset($tokens[$nextSignificant]['attribute_closer']) === true + ) { + $nextSignificant = $tokens[$nextSignificant]['attribute_closer']; + continue; + } + + break; + } + + if ($tokens[$nextSignificant]['code'] === T_FUNCTION) { + return; } $error = 'Closing brace of a %s must be followed by a single blank line; found %s'; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Classes/ClassFileNameSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Classes/ClassFileNameSniff.php index fc3ec0473..346534ba4 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Classes/ClassFileNameSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Classes/ClassFileNameSniff.php @@ -11,6 +11,7 @@ use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\Sniff; +use PHP_CodeSniffer\Util\Tokens; class ClassFileNameSniff implements Sniff { @@ -23,12 +24,10 @@ class ClassFileNameSniff implements Sniff */ public function register() { - return [ - T_CLASS, - T_INTERFACE, - T_TRAIT, - T_ENUM, - ]; + $targets = Tokens::$ooScopeTokens; + unset($targets[T_ANON_CLASS]); + + return $targets; }//end register() @@ -40,26 +39,32 @@ public function register() * @param int $stackPtr The position of the current token in * the stack passed in $tokens. * - * @return void + * @return int|void Integer stack pointer to skip forward or void to continue + * normal file processing. */ public function process(File $phpcsFile, $stackPtr) { - $fullPath = basename($phpcsFile->getFilename()); - $fileName = substr($fullPath, 0, strrpos($fullPath, '.')); - if ($fileName === '') { - // No filename probably means STDIN, so we can't do this check. - return; + $fullPath = $phpcsFile->getFilename(); + if ($fullPath === 'STDIN') { + return $phpcsFile->numTokens; } - $tokens = $phpcsFile->getTokens(); - $decName = $phpcsFile->findNext(T_STRING, $stackPtr); + $fileName = basename($fullPath); + $fileNoExt = substr($fileName, 0, strrpos($fileName, '.')); + $extension = substr($fileName, (strrpos($fileName, '.') + 1)); + + $tokens = $phpcsFile->getTokens(); + $ooName = $phpcsFile->getDeclarationName($stackPtr); + if ($ooName === null) { + // Probably parse error/live coding. + return; + } - if ($tokens[$decName]['content'] !== $fileName) { - $error = '%s name doesn\'t match filename; expected "%s %s"'; + if ($ooName !== $fileNoExt) { + $error = 'Filename doesn\'t match %s name; expected file name "%s"'; $data = [ - ucfirst($tokens[$stackPtr]['content']), $tokens[$stackPtr]['content'], - $fileName, + $ooName.'.'.$extension, ]; $phpcsFile->addError($error, $stackPtr, 'NoMatch', $data); } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Classes/DuplicatePropertySniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Classes/DuplicatePropertySniff.php index 12d8a2456..225a29659 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Classes/DuplicatePropertySniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Classes/DuplicatePropertySniff.php @@ -12,9 +12,10 @@ namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\Classes; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; -class DuplicatePropertySniff implements Sniff +class DuplicatePropertySniff implements Sniff, DeprecatedSniff { /** @@ -81,4 +82,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning JavaScript files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Classes/SelfMemberReferenceSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Classes/SelfMemberReferenceSniff.php index 407d3dae2..8ee4de45a 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Classes/SelfMemberReferenceSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Classes/SelfMemberReferenceSniff.php @@ -182,7 +182,7 @@ protected function processTokenOutsideScope(File $phpcsFile, $stackPtr) /** * Returns the declaration names for classes/interfaces/functions with a namespace. * - * @param array $tokens Token stack for this file + * @param array $tokens Token stack for this file. * @param int $stackPtr The position where the namespace building will start. * * @return string @@ -221,15 +221,23 @@ protected function getDeclarationNameWithNamespace(array $tokens, $stackPtr) */ protected function getNamespaceOfScope(File $phpcsFile, $stackPtr) { - $namespace = '\\'; - $namespaceDeclaration = $phpcsFile->findPrevious(T_NAMESPACE, $stackPtr); + $namespace = '\\'; + $tokens = $phpcsFile->getTokens(); + + while (($namespaceDeclaration = $phpcsFile->findPrevious(T_NAMESPACE, $stackPtr)) !== false) { + $nextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, ($namespaceDeclaration + 1), null, true); + if ($tokens[$nextNonEmpty]['code'] === T_NS_SEPARATOR) { + // Namespace operator. Ignore. + $stackPtr = ($namespaceDeclaration - 1); + continue; + } - if ($namespaceDeclaration !== false) { - $endOfNamespaceDeclaration = $phpcsFile->findNext([T_SEMICOLON, T_OPEN_CURLY_BRACKET], $namespaceDeclaration); + $endOfNamespaceDeclaration = $phpcsFile->findNext([T_SEMICOLON, T_OPEN_CURLY_BRACKET, T_CLOSE_TAG], $namespaceDeclaration); $namespace = $this->getDeclarationNameWithNamespace( $phpcsFile->getTokens(), ($endOfNamespaceDeclaration - 1) ); + break; } return $namespace; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Classes/ValidClassNameSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Classes/ValidClassNameSniff.php index a8975353f..5f4f261fc 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Classes/ValidClassNameSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Classes/ValidClassNameSniff.php @@ -12,6 +12,7 @@ use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Common; +use PHP_CodeSniffer\Util\Tokens; class ValidClassNameSniff implements Sniff { @@ -58,8 +59,8 @@ public function process(File $phpcsFile, $stackPtr) // simply look for the first T_STRING because a class name // starting with the number will be multiple tokens. $opener = $tokens[$stackPtr]['scope_opener']; - $nameStart = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), $opener, true); - $nameEnd = $phpcsFile->findNext([T_WHITESPACE, T_COLON], $nameStart, $opener); + $nameStart = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), $opener, true); + $nameEnd = $phpcsFile->findNext((Tokens::$emptyTokens + [T_COLON => T_COLON]), $nameStart, $opener); if ($nameEnd === false) { $name = $tokens[$nameStart]['content']; } else { @@ -75,7 +76,7 @@ public function process(File $phpcsFile, $stackPtr) $type, $name, ]; - $phpcsFile->addError($error, $stackPtr, 'NotCamelCaps', $data); + $phpcsFile->addError($error, $nameStart, 'NotCamelCaps', $data); $phpcsFile->recordMetric($stackPtr, 'PascalCase class name', 'no'); } else { $phpcsFile->recordMetric($stackPtr, 'PascalCase class name', 'yes'); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/BlockCommentSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/BlockCommentSniff.php index 9a565123b..c117d2ed5 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/BlockCommentSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/BlockCommentSniff.php @@ -66,7 +66,7 @@ public function process(File $phpcsFile, $stackPtr) return; } - // If this is a function/class/interface doc block comment, skip it. + // If this is a function/class/interface/enum/property/const doc block comment, skip it. // We are only interested in inline doc block comments. if ($tokens[$stackPtr]['code'] === T_DOC_COMMENT_OPEN_TAG) { $nextToken = $stackPtr; @@ -80,16 +80,14 @@ public function process(File $phpcsFile, $stackPtr) break; } while (true); - $ignore = [ + $ignore = Tokens::$scopeModifiers; + $ignore += [ T_CLASS => true, T_INTERFACE => true, T_TRAIT => true, T_ENUM => true, T_FUNCTION => true, - T_PUBLIC => true, - T_PRIVATE => true, T_FINAL => true, - T_PROTECTED => true, T_STATIC => true, T_ABSTRACT => true, T_CONST => true, diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/ClosingDeclarationCommentSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/ClosingDeclarationCommentSniff.php index afc7ac071..44bd4388d 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/ClosingDeclarationCommentSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/ClosingDeclarationCommentSniff.php @@ -1,6 +1,6 @@ * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600) @@ -24,10 +24,11 @@ class ClosingDeclarationCommentSniff implements Sniff public function register() { return [ - T_FUNCTION, T_CLASS, - T_INTERFACE, T_ENUM, + T_FUNCTION, + T_INTERFACE, + T_TRAIT, ]; }//end register() @@ -72,6 +73,8 @@ public function process(File $phpcsFile, $stackPtr) $comment = '//end class'; } else if ($tokens[$stackPtr]['code'] === T_INTERFACE) { $comment = '//end interface'; + } else if ($tokens[$stackPtr]['code'] === T_TRAIT) { + $comment = '//end trait'; } else { $comment = '//end enum'; }//end if @@ -85,15 +88,10 @@ public function process(File $phpcsFile, $stackPtr) $closingBracket = $tokens[$stackPtr]['scope_closer']; - if ($closingBracket === null) { - // Possible inline structure. Other tests will handle it. - return; - } - $data = [$comment]; if (isset($tokens[($closingBracket + 1)]) === false || $tokens[($closingBracket + 1)]['code'] !== T_COMMENT) { $next = $phpcsFile->findNext(T_WHITESPACE, ($closingBracket + 1), null, true); - if (rtrim($tokens[$next]['content']) === $comment) { + if ($next !== false && rtrim($tokens[$next]['content']) === $comment) { // The comment isn't really missing; it is just in the wrong place. $fix = $phpcsFile->addFixableError('Expected %s directly after closing brace', $closingBracket, 'Misplaced', $data); if ($fix === true) { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/DocCommentAlignmentSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/DocCommentAlignmentSniff.php index 453ff89c1..13099c8b5 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/DocCommentAlignmentSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/DocCommentAlignmentSniff.php @@ -52,7 +52,7 @@ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); - // We are only interested in function/class/interface doc block comments. + // We are only interested in function/class/interface/enum/property/const doc block comments. $ignore = Tokens::$emptyTokens; if ($phpcsFile->tokenizerType === 'JS') { $ignore[] = T_EQUAL; @@ -61,17 +61,17 @@ public function process(File $phpcsFile, $stackPtr) } $nextToken = $phpcsFile->findNext($ignore, ($stackPtr + 1), null, true); - $ignore = [ + + $ignore = Tokens::$scopeModifiers; + $ignore += [ T_CLASS => true, T_INTERFACE => true, T_ENUM => true, T_ENUM_CASE => true, T_FUNCTION => true, - T_PUBLIC => true, - T_PRIVATE => true, - T_PROTECTED => true, T_STATIC => true, T_ABSTRACT => true, + T_FINAL => true, T_PROPERTY => true, T_OBJECT => true, T_PROTOTYPE => true, diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/FileCommentSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/FileCommentSniff.php index d9241f1b6..cfff91fc6 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/FileCommentSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/FileCommentSniff.php @@ -55,11 +55,11 @@ public function process(File $phpcsFile, $stackPtr) if ($tokens[$commentStart]['code'] === T_COMMENT) { $phpcsFile->addError('You must use "/**" style comments for a file comment', $commentStart, 'WrongStyle'); $phpcsFile->recordMetric($stackPtr, 'File has doc comment', 'yes'); - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; } else if ($commentStart === false || $tokens[$commentStart]['code'] !== T_DOC_COMMENT_OPEN_TAG) { $phpcsFile->addError('Missing file doc comment', $stackPtr, 'Missing'); $phpcsFile->recordMetric($stackPtr, 'File has doc comment', 'no'); - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; } if (isset($tokens[$commentStart]['comment_closer']) === false @@ -67,7 +67,7 @@ public function process(File $phpcsFile, $stackPtr) && $tokens[$commentStart]['comment_closer'] === ($phpcsFile->numTokens - 1)) ) { // Don't process an unfinished file comment during live coding. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; } $commentEnd = $tokens[$commentStart]['comment_closer']; @@ -116,7 +116,7 @@ public function process(File $phpcsFile, $stackPtr) if (in_array($tokens[$nextToken]['code'], $ignore, true) === true) { $phpcsFile->addError('Missing file doc comment', $stackPtr, 'Missing'); $phpcsFile->recordMetric($stackPtr, 'File has doc comment', 'no'); - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; } $phpcsFile->recordMetric($stackPtr, 'File has doc comment', 'yes'); @@ -220,7 +220,7 @@ public function process(File $phpcsFile, $stackPtr) }//end foreach // Ignore the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; }//end process() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/FunctionCommentSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/FunctionCommentSniff.php index 672818337..3531758a4 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/FunctionCommentSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/FunctionCommentSniff.php @@ -86,7 +86,7 @@ protected function processReturn(File $phpcsFile, $stackPtr, $commentStart) // Check return type (can be multiple, separated by '|'). $typeNames = explode('|', $returnType); $suggestedNames = []; - foreach ($typeNames as $i => $typeName) { + foreach ($typeNames as $typeName) { $suggestedName = Common::suggestType($typeName); if (in_array($suggestedName, $suggestedNames, true) === false) { $suggestedNames[] = $suggestedName; @@ -311,7 +311,7 @@ protected function processParams(File $phpcsFile, $stackPtr, $commentStart) $commentLines = []; if ($tokens[($tag + 2)]['code'] === T_DOC_COMMENT_STRING) { $matches = []; - preg_match('/([^$&.]+)(?:((?:\.\.\.)?(?:\$|&)[^\s]+)(?:(\s+)(.*))?)?/', $tokens[($tag + 2)]['content'], $matches); + preg_match('/((?:(?![$.]|&(?=\$)).)*)(?:((?:\.\.\.)?(?:\$|&)[^\s]+)(?:(\s+)(.*))?)?/', $tokens[($tag + 2)]['content'], $matches); if (empty($matches) === false) { $typeLen = strlen($matches[1]); @@ -323,7 +323,10 @@ protected function processParams(File $phpcsFile, $stackPtr, $commentStart) } } - if (isset($matches[2]) === true) { + if ($tokens[($tag + 2)]['content'][0] === '$') { + $error = 'Missing parameter type'; + $phpcsFile->addError($error, $tag, 'MissingParamType'); + } else if (isset($matches[2]) === true) { $var = $matches[2]; $varLen = strlen($var); if ($varLen > $maxVar) { @@ -366,9 +369,6 @@ protected function processParams(File $phpcsFile, $stackPtr, $commentStart) $phpcsFile->addError($error, $tag, 'MissingParamComment'); $commentLines[] = ['comment' => '']; }//end if - } else if ($tokens[($tag + 2)]['content'][0] === '$') { - $error = 'Missing parameter type'; - $phpcsFile->addError($error, $tag, 'MissingParamType'); } else { $error = 'Missing parameter name'; $phpcsFile->addError($error, $tag, 'MissingParamName'); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/FunctionCommentThrowTagSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/FunctionCommentThrowTagSniff.php index 4fb332cf4..b6604a7fc 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/FunctionCommentThrowTagSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/FunctionCommentThrowTagSniff.php @@ -47,10 +47,24 @@ public function process(File $phpcsFile, $stackPtr) return; } - $find = Tokens::$methodPrefixes; - $find[] = T_WHITESPACE; + $ignore = Tokens::$methodPrefixes; + $ignore[T_WHITESPACE] = T_WHITESPACE; + + for ($commentEnd = ($stackPtr - 1); $commentEnd >= 0; $commentEnd--) { + if (isset($ignore[$tokens[$commentEnd]['code']]) === true) { + continue; + } + + if ($tokens[$commentEnd]['code'] === T_ATTRIBUTE_END + && isset($tokens[$commentEnd]['attribute_opener']) === true + ) { + $commentEnd = $tokens[$commentEnd]['attribute_opener']; + continue; + } + + break; + } - $commentEnd = $phpcsFile->findPrevious($find, ($stackPtr - 1), null, true); if ($tokens[$commentEnd]['code'] !== T_DOC_COMMENT_CLOSE_TAG) { // Function doesn't have a doc comment or is using the wrong type of comment. return; @@ -90,7 +104,7 @@ public function process(File $phpcsFile, $stackPtr) don't know the exception class. */ - $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($currPos + 1), null, true); + $nextToken = $phpcsFile->findNext(Tokens::$emptyTokens, ($currPos + 1), null, true); if ($tokens[$nextToken]['code'] === T_NEW || $tokens[$nextToken]['code'] === T_NS_SEPARATOR || $tokens[$nextToken]['code'] === T_STRING diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/LongConditionClosingCommentSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/LongConditionClosingCommentSniff.php index 439fc38a8..9ae49096f 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/LongConditionClosingCommentSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/LongConditionClosingCommentSniff.php @@ -28,7 +28,7 @@ class LongConditionClosingCommentSniff implements Sniff /** * The openers that we are interested in. * - * @var integer[] + * @var array */ private static $openers = [ T_SWITCH, @@ -156,7 +156,7 @@ public function process(File $phpcsFile, $stackPtr) } if ($startCondition['code'] === T_MATCH) { - // Move the stackPtr to after the semi-colon/comma if there is one. + // Move the stackPtr to after the semicolon/comma if there is one. $nextToken = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); if ($nextToken !== false && ($tokens[$nextToken]['code'] === T_SEMICOLON diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/PostStatementCommentSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/PostStatementCommentSniff.php index 9b36abe76..82b934a79 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/PostStatementCommentSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/PostStatementCommentSniff.php @@ -109,6 +109,14 @@ public function process(File $phpcsFile, $stackPtr) } } + if ($phpcsFile->tokenizerType === 'PHP' + && preg_match('|^//[ \t]*@[^\s]+|', $tokens[$stackPtr]['content']) === 1 + ) { + $error = 'Annotations may not appear after statements'; + $phpcsFile->addError($error, $stackPtr, 'AnnotationFound'); + return; + } + $error = 'Comments may not appear after statements'; $fix = $phpcsFile->addFixableError($error, $stackPtr, 'Found'); if ($fix === true) { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/VariableCommentSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/VariableCommentSniff.php index 76fbc6dca..afb1be03c 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/VariableCommentSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Commenting/VariableCommentSniff.php @@ -12,6 +12,7 @@ use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\AbstractVariableSniff; use PHP_CodeSniffer\Util\Common; +use PHP_CodeSniffer\Util\Tokens; class VariableCommentSniff extends AbstractVariableSniff { @@ -28,26 +29,27 @@ class VariableCommentSniff extends AbstractVariableSniff */ public function processMemberVar(File $phpcsFile, $stackPtr) { - $tokens = $phpcsFile->getTokens(); - $ignore = [ - T_PUBLIC => T_PUBLIC, - T_PRIVATE => T_PRIVATE, - T_PROTECTED => T_PROTECTED, - T_VAR => T_VAR, - T_STATIC => T_STATIC, - T_READONLY => T_READONLY, - T_WHITESPACE => T_WHITESPACE, - T_STRING => T_STRING, - T_NS_SEPARATOR => T_NS_SEPARATOR, - T_NAMESPACE => T_NAMESPACE, - T_NULLABLE => T_NULLABLE, - T_TYPE_UNION => T_TYPE_UNION, - T_TYPE_INTERSECTION => T_TYPE_INTERSECTION, - T_NULL => T_NULL, - T_TRUE => T_TRUE, - T_FALSE => T_FALSE, - T_SELF => T_SELF, - T_PARENT => T_PARENT, + $tokens = $phpcsFile->getTokens(); + $ignore = Tokens::$scopeModifiers; + $ignore += [ + T_VAR => T_VAR, + T_STATIC => T_STATIC, + T_READONLY => T_READONLY, + T_FINAL => T_FINAL, + T_WHITESPACE => T_WHITESPACE, + T_STRING => T_STRING, + T_NS_SEPARATOR => T_NS_SEPARATOR, + T_NAMESPACE => T_NAMESPACE, + T_NULLABLE => T_NULLABLE, + T_TYPE_UNION => T_TYPE_UNION, + T_TYPE_INTERSECTION => T_TYPE_INTERSECTION, + T_TYPE_OPEN_PARENTHESIS => T_TYPE_OPEN_PARENTHESIS, + T_TYPE_CLOSE_PARENTHESIS => T_TYPE_CLOSE_PARENTHESIS, + T_NULL => T_NULL, + T_TRUE => T_TRUE, + T_FALSE => T_FALSE, + T_SELF => T_SELF, + T_PARENT => T_PARENT, ]; for ($commentEnd = ($stackPtr - 1); $commentEnd >= 0; $commentEnd--) { @@ -135,7 +137,7 @@ public function processMemberVar(File $phpcsFile, $stackPtr) // Check var type (can be multiple, separated by '|'). $typeNames = explode('|', $varType); $suggestedNames = []; - foreach ($typeNames as $i => $typeName) { + foreach ($typeNames as $typeName) { $suggestedName = Common::suggestType($typeName); if (in_array($suggestedName, $suggestedNames, true) === false) { $suggestedNames[] = $suggestedName; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/ControlStructures/ForEachLoopDeclarationSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/ControlStructures/ForEachLoopDeclarationSniff.php index bd51b265f..456886b36 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/ControlStructures/ForEachLoopDeclarationSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/ControlStructures/ForEachLoopDeclarationSniff.php @@ -90,7 +90,7 @@ public function process(File $phpcsFile, $stackPtr) $this->requiredSpacesAfterOpen, $spaceAfterOpen, ]; - $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpacingAfterOpen', $data); + $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpaceAfterOpen', $data); if ($fix === true) { $padding = str_repeat(' ', $this->requiredSpacesAfterOpen); if ($spaceAfterOpen === 0) { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/ControlStructures/ForLoopDeclarationSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/ControlStructures/ForLoopDeclarationSniff.php index e5e4e66f8..38313e166 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/ControlStructures/ForLoopDeclarationSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/ControlStructures/ForLoopDeclarationSniff.php @@ -76,8 +76,8 @@ public function process(File $phpcsFile, $stackPtr) $tokens = $phpcsFile->getTokens(); $openingBracket = $phpcsFile->findNext(T_OPEN_PARENTHESIS, $stackPtr); - if ($openingBracket === false) { - $error = 'Possible parse error: no opening parenthesis for FOR keyword'; + if ($openingBracket === false || isset($tokens[$openingBracket]['parenthesis_closer']) === false) { + $error = 'Possible parse error: no opening/closing parenthesis for FOR keyword'; $phpcsFile->addWarning($error, $stackPtr, 'NoOpenBracket'); return; } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/ControlStructures/SwitchDeclarationSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/ControlStructures/SwitchDeclarationSniff.php index be46aed55..2a9d2c731 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/ControlStructures/SwitchDeclarationSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/ControlStructures/SwitchDeclarationSniff.php @@ -153,6 +153,7 @@ public function process(File $phpcsFile, $stackPtr) || $tokens[$nextBreak]['code'] === T_CONTINUE || $tokens[$nextBreak]['code'] === T_THROW || $tokens[$nextBreak]['code'] === T_EXIT + || $tokens[$nextBreak]['code'] === T_GOTO ) { if ($tokens[$nextBreak]['scope_condition'] === $nextCase) { // Only need to check a couple of things once, even if the diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Debug/JSLintSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Debug/JSLintSniff.php index 30b3071d7..9d4d79bee 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Debug/JSLintSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Debug/JSLintSniff.php @@ -13,10 +13,11 @@ use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Common; -class JSLintSniff implements Sniff +class JSLintSniff implements Sniff, DeprecatedSniff { /** @@ -47,14 +48,14 @@ public function register() * the token was found. * * @return int - * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If jslint.js could not be run + * @throws \PHP_CodeSniffer\Exceptions\RuntimeException If jslint.js could not be run. */ public function process(File $phpcsFile, $stackPtr) { $rhinoPath = Config::getExecutablePath('rhino'); $jslintPath = Config::getExecutablePath('jslint'); if ($rhinoPath === null || $jslintPath === null) { - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; } $fileName = $phpcsFile->getFilename(); @@ -80,9 +81,45 @@ public function process(File $phpcsFile, $stackPtr) } // Ignore the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning JavaScript files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Debug/JavaScriptLintSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Debug/JavaScriptLintSniff.php index eb2b29455..a1fe215e2 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Debug/JavaScriptLintSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Debug/JavaScriptLintSniff.php @@ -14,10 +14,11 @@ use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Exceptions\RuntimeException; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Common; -class JavaScriptLintSniff implements Sniff +class JavaScriptLintSniff implements Sniff, DeprecatedSniff { /** @@ -54,7 +55,7 @@ public function process(File $phpcsFile, $stackPtr) { $jslPath = Config::getExecutablePath('jsl'); if ($jslPath === null) { - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; } $fileName = $phpcsFile->getFilename(); @@ -67,7 +68,7 @@ public function process(File $phpcsFile, $stackPtr) // provide useful error reporting. if ($retval === 2 || $retval === 4) { if (is_array($output) === true) { - $msg = join('\n', $output); + $msg = implode('\n', $output); } throw new RuntimeException("Failed invoking JavaScript Lint, retval was [$retval], output was [$msg]"); @@ -83,9 +84,45 @@ public function process(File $phpcsFile, $stackPtr) } // Ignore the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning JavaScript files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Files/FileExtensionSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Files/FileExtensionSniff.php index 4ba28a3ee..aceecffd3 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Files/FileExtensionSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Files/FileExtensionSniff.php @@ -60,7 +60,7 @@ public function process(File $phpcsFile, $stackPtr) } // Ignore the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; }//end process() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Formatting/OperatorBracketSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Formatting/OperatorBracketSniff.php index b79e6b3ec..821f9b7f4 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Formatting/OperatorBracketSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Formatting/OperatorBracketSniff.php @@ -133,24 +133,23 @@ public function process(File $phpcsFile, $stackPtr) // Tokens that are allowed inside a bracketed operation. $allowed = [ - T_VARIABLE, - T_LNUMBER, - T_DNUMBER, - T_STRING, - T_WHITESPACE, - T_NS_SEPARATOR, - T_THIS, - T_SELF, - T_STATIC, - T_PARENT, - T_OBJECT_OPERATOR, - T_NULLSAFE_OBJECT_OPERATOR, - T_DOUBLE_COLON, - T_OPEN_SQUARE_BRACKET, - T_CLOSE_SQUARE_BRACKET, - T_MODULUS, - T_NONE, - T_BITWISE_NOT, + T_VARIABLE => T_VARIABLE, + T_LNUMBER => T_LNUMBER, + T_DNUMBER => T_DNUMBER, + T_STRING => T_STRING, + T_WHITESPACE => T_WHITESPACE, + T_NS_SEPARATOR => T_NS_SEPARATOR, + T_THIS => T_THIS, + T_SELF => T_SELF, + T_STATIC => T_STATIC, + T_PARENT => T_PARENT, + T_OBJECT_OPERATOR => T_OBJECT_OPERATOR, + T_NULLSAFE_OBJECT_OPERATOR => T_NULLSAFE_OBJECT_OPERATOR, + T_DOUBLE_COLON => T_DOUBLE_COLON, + T_OPEN_SQUARE_BRACKET => T_OPEN_SQUARE_BRACKET, + T_CLOSE_SQUARE_BRACKET => T_CLOSE_SQUARE_BRACKET, + T_NONE => T_NONE, + T_BITWISE_NOT => T_BITWISE_NOT, ]; $allowed += Tokens::$operators; @@ -172,7 +171,7 @@ public function process(File $phpcsFile, $stackPtr) // We allow simple operations to not be bracketed. // For example, ceil($one / $two). for ($prev = ($stackPtr - 1); $prev > $bracket; $prev--) { - if (in_array($tokens[$prev]['code'], $allowed, true) === true) { + if (isset($allowed[$tokens[$prev]['code']]) === true) { continue; } @@ -188,7 +187,7 @@ public function process(File $phpcsFile, $stackPtr) } for ($next = ($stackPtr + 1); $next < $endBracket; $next++) { - if (in_array($tokens[$next]['code'], $allowed, true) === true) { + if (isset($allowed[$tokens[$next]['code']]) === true) { continue; } @@ -290,7 +289,6 @@ public function addMissingBracketsError($phpcsFile, $stackPtr) T_OBJECT_OPERATOR => true, T_NULLSAFE_OBJECT_OPERATOR => true, T_DOUBLE_COLON => true, - T_MODULUS => true, T_ISSET => true, T_ARRAY => true, T_NONE => true, @@ -354,16 +352,23 @@ public function addMissingBracketsError($phpcsFile, $stackPtr) } if ($tokens[$after]['code'] === T_OPEN_PARENTHESIS) { + if (isset($tokens[$after]['parenthesis_closer']) === false) { + // Live coding/parse error. Ignore. + return; + } + $after = $tokens[$after]['parenthesis_closer']; continue; } - if ($tokens[$after]['code'] === T_OPEN_SQUARE_BRACKET) { - $after = $tokens[$after]['bracket_closer']; - continue; - } + if (($tokens[$after]['code'] === T_OPEN_SQUARE_BRACKET + || $tokens[$after]['code'] === T_OPEN_SHORT_ARRAY) + ) { + if (isset($tokens[$after]['bracket_closer']) === false) { + // Live coding/parse error. Ignore. + return; + } - if ($tokens[$after]['code'] === T_OPEN_SHORT_ARRAY) { $after = $tokens[$after]['bracket_closer']; continue; } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Functions/FunctionDeclarationArgumentSpacingSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Functions/FunctionDeclarationArgumentSpacingSniff.php index 7357a507e..f33d19bc1 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Functions/FunctionDeclarationArgumentSpacingSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Functions/FunctionDeclarationArgumentSpacingSniff.php @@ -11,6 +11,7 @@ use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\Sniff; +use PHP_CodeSniffer\Util\Common; use PHP_CodeSniffer\Util\Tokens; class FunctionDeclarationArgumentSpacingSniff implements Sniff @@ -130,25 +131,30 @@ public function processBracket($phpcsFile, $openBracket) $data = [$found]; $fix = $phpcsFile->addFixableError($error, $openBracket, 'SpacingBetween', $data); if ($fix === true) { - $phpcsFile->fixer->replaceToken(($openBracket + 1), ''); + $phpcsFile->fixer->beginChangeset(); + for ($i = ($openBracket + 1); $tokens[$i]['code'] === T_WHITESPACE; $i++) { + $phpcsFile->fixer->replaceToken($i, ''); + } + + $phpcsFile->fixer->endChangeset(); } } // No params, so we don't check normal spacing rules. return; - } + }//end if }//end if foreach ($params as $paramNumber => $param) { if ($param['pass_by_reference'] === true) { $refToken = $param['reference_token']; - $gap = 0; if ($tokens[($refToken + 1)]['code'] === T_WHITESPACE) { $gap = $tokens[($refToken + 1)]['length']; - } + if ($tokens[$refToken]['line'] !== $tokens[($refToken + 2)]['line']) { + $gap = 'newline'; + } - if ($gap !== 0) { $error = 'Expected 0 spaces after reference operator for argument "%s"; %s found'; $data = [ $param['name'], @@ -156,20 +162,25 @@ public function processBracket($phpcsFile, $openBracket) ]; $fix = $phpcsFile->addFixableError($error, $refToken, 'SpacingAfterReference', $data); if ($fix === true) { - $phpcsFile->fixer->replaceToken(($refToken + 1), ''); + $phpcsFile->fixer->beginChangeset(); + for ($i = ($refToken + 1); $tokens[$i]['code'] === T_WHITESPACE; $i++) { + $phpcsFile->fixer->replaceToken($i, ''); + } + + $phpcsFile->fixer->endChangeset(); } - } + }//end if }//end if if ($param['variable_length'] === true) { $variadicToken = $param['variadic_token']; - $gap = 0; if ($tokens[($variadicToken + 1)]['code'] === T_WHITESPACE) { $gap = $tokens[($variadicToken + 1)]['length']; - } + if ($tokens[$variadicToken]['line'] !== $tokens[($variadicToken + 2)]['line']) { + $gap = 'newline'; + } - if ($gap !== 0) { $error = 'Expected 0 spaces after variadic operator for argument "%s"; %s found'; $data = [ $param['name'], @@ -177,16 +188,23 @@ public function processBracket($phpcsFile, $openBracket) ]; $fix = $phpcsFile->addFixableError($error, $variadicToken, 'SpacingAfterVariadic', $data); if ($fix === true) { - $phpcsFile->fixer->replaceToken(($variadicToken + 1), ''); + $phpcsFile->fixer->beginChangeset(); + for ($i = ($variadicToken + 1); $tokens[$i]['code'] === T_WHITESPACE; $i++) { + $phpcsFile->fixer->replaceToken($i, ''); + } + + $phpcsFile->fixer->endChangeset(); } - } + }//end if }//end if if (isset($param['default_equal_token']) === true) { $equalToken = $param['default_equal_token']; $spacesBefore = 0; - if (($equalToken - $param['token']) > 1) { + if ($tokens[$param['token']]['line'] !== $tokens[$equalToken]['line']) { + $spacesBefore = 'newline'; + } else if ($tokens[($param['token'] + 1)]['code'] === T_WHITESPACE) { $spacesBefore = $tokens[($param['token'] + 1)]['length']; } @@ -197,19 +215,30 @@ public function processBracket($phpcsFile, $openBracket) $spacesBefore, ]; - $fix = $phpcsFile->addFixableError($error, $equalToken, 'SpaceBeforeEquals', $data); - if ($fix === true) { - $padding = str_repeat(' ', $this->equalsSpacing); - if ($spacesBefore === 0) { - $phpcsFile->fixer->addContentBefore($equalToken, $padding); - } else { - $phpcsFile->fixer->replaceToken(($equalToken - 1), $padding); + $nextNonWhitespace = $phpcsFile->findNext(T_WHITESPACE, ($param['token'] + 1), $equalToken, true); + if ($nextNonWhitespace !== false) { + $phpcsFile->addError($error, $equalToken, 'SpaceBeforeEquals', $data); + } else { + $fix = $phpcsFile->addFixableError($error, $equalToken, 'SpaceBeforeEquals', $data); + if ($fix === true) { + $padding = str_repeat(' ', $this->equalsSpacing); + + $phpcsFile->fixer->beginChangeset(); + $phpcsFile->fixer->addContent($param['token'], $padding); + + for ($i = ($param['token'] + 1); $tokens[$i]['code'] === T_WHITESPACE; $i++) { + $phpcsFile->fixer->replaceToken($i, ''); + } + + $phpcsFile->fixer->endChangeset(); } } }//end if $spacesAfter = 0; - if ($tokens[($equalToken + 1)]['code'] === T_WHITESPACE) { + if ($tokens[$equalToken]['line'] !== $tokens[$param['default_token']]['line']) { + $spacesAfter = 'newline'; + } else if ($tokens[($equalToken + 1)]['code'] === T_WHITESPACE) { $spacesAfter = $tokens[($equalToken + 1)]['length']; } @@ -220,13 +249,22 @@ public function processBracket($phpcsFile, $openBracket) $spacesAfter, ]; - $fix = $phpcsFile->addFixableError($error, $equalToken, 'SpaceAfterEquals', $data); - if ($fix === true) { - $padding = str_repeat(' ', $this->equalsSpacing); - if ($spacesAfter === 0) { + $nextNonWhitespace = $phpcsFile->findNext(T_WHITESPACE, ($equalToken + 1), $param['default_token'], true); + if ($nextNonWhitespace !== false) { + $phpcsFile->addError($error, $equalToken, 'SpaceAfterEquals', $data); + } else { + $fix = $phpcsFile->addFixableError($error, $equalToken, 'SpaceAfterEquals', $data); + if ($fix === true) { + $padding = str_repeat(' ', $this->equalsSpacing); + + $phpcsFile->fixer->beginChangeset(); $phpcsFile->fixer->addContent($equalToken, $padding); - } else { - $phpcsFile->fixer->replaceToken(($equalToken + 1), $padding); + + for ($i = ($equalToken + 1); $tokens[$i]['code'] === T_WHITESPACE; $i++) { + $phpcsFile->fixer->replaceToken($i, ''); + } + + $phpcsFile->fixer->endChangeset(); } } }//end if @@ -235,26 +273,136 @@ public function processBracket($phpcsFile, $openBracket) if ($param['type_hint_token'] !== false) { $typeHintToken = $param['type_hint_end_token']; - $gap = 0; - if ($tokens[($typeHintToken + 1)]['code'] === T_WHITESPACE) { - $gap = $tokens[($typeHintToken + 1)]['length']; + $gap = ''; + $i = $typeHintToken; + while ($tokens[++$i]['code'] === T_WHITESPACE) { + $gap .= $tokens[$i]['content']; } - if ($gap !== 1) { + if ($gap !== ' ') { $error = 'Expected 1 space between type hint and argument "%s"; %s found'; $data = [ $param['name'], - $gap, ]; - $fix = $phpcsFile->addFixableError($error, $typeHintToken, 'SpacingAfterHint', $data); + if (trim($gap, ' ') === '') { + // Gap contains only space characters: report the number of spaces. + $data[] = strlen($gap); + } else { + // Gap contains more than just spaces: render these for better clarity. + $data[] = '"'.Common::prepareForOutput($gap).'"'; + } + + $fix = $phpcsFile->addFixableError($error, $typeHintToken, 'SpacingAfterHint', $data); if ($fix === true) { - if ($gap === 0) { - $phpcsFile->fixer->addContent($typeHintToken, ' '); - } else { - $phpcsFile->fixer->replaceToken(($typeHintToken + 1), ' '); + $phpcsFile->fixer->beginChangeset(); + $phpcsFile->fixer->addContent($typeHintToken, ' '); + + for ($i = ($typeHintToken + 1); $tokens[$i]['code'] === T_WHITESPACE; $i++) { + $phpcsFile->fixer->replaceToken($i, ''); + } + + $phpcsFile->fixer->endChangeset(); + } + }//end if + }//end if + + if (isset($param['visibility_token']) === true && $param['visibility_token'] !== false) { + $visibilityToken = $param['visibility_token']; + $afterVisibilityToken = $phpcsFile->findNext(T_WHITESPACE, ($visibilityToken + 1), $param['token'], true); + + $spacesAfter = 0; + if ($afterVisibilityToken !== false + && $tokens[$visibilityToken]['line'] !== $tokens[$afterVisibilityToken]['line'] + ) { + $spacesAfter = 'newline'; + } else if ($tokens[($visibilityToken + 1)]['code'] === T_WHITESPACE) { + $spacesAfter = $tokens[($visibilityToken + 1)]['length']; + } + + if ($spacesAfter !== 1) { + $error = 'Expected 1 space after visibility modifier "%s"; %s found'; + $data = [ + $tokens[$visibilityToken]['content'], + $spacesAfter, + ]; + + $fix = $phpcsFile->addFixableError($error, $visibilityToken, 'SpacingAfterVisbility', $data); + if ($fix === true) { + $phpcsFile->fixer->beginChangeset(); + $phpcsFile->fixer->addContent($visibilityToken, ' '); + + for ($i = ($visibilityToken + 1); $tokens[$i]['code'] === T_WHITESPACE; $i++) { + $phpcsFile->fixer->replaceToken($i, ''); + } + + $phpcsFile->fixer->endChangeset(); + } + }//end if + }//end if + + if (isset($param['set_visibility_token']) === true && $param['set_visibility_token'] !== false) { + $visibilityToken = $param['set_visibility_token']; + $afterVisibilityToken = $phpcsFile->findNext(T_WHITESPACE, ($visibilityToken + 1), $param['token'], true); + + $spacesAfter = 0; + if ($afterVisibilityToken !== false + && $tokens[$visibilityToken]['line'] !== $tokens[$afterVisibilityToken]['line'] + ) { + $spacesAfter = 'newline'; + } else if ($tokens[($visibilityToken + 1)]['code'] === T_WHITESPACE) { + $spacesAfter = $tokens[($visibilityToken + 1)]['length']; + } + + if ($spacesAfter !== 1) { + $error = 'Expected 1 space after set-visibility modifier "%s"; %s found'; + $data = [ + $tokens[$visibilityToken]['content'], + $spacesAfter, + ]; + + $fix = $phpcsFile->addFixableError($error, $visibilityToken, 'SpacingAfterSetVisibility', $data); + if ($fix === true) { + $phpcsFile->fixer->beginChangeset(); + $phpcsFile->fixer->addContent($visibilityToken, ' '); + + for ($i = ($visibilityToken + 1); $tokens[$i]['code'] === T_WHITESPACE; $i++) { + $phpcsFile->fixer->replaceToken($i, ''); } + + $phpcsFile->fixer->endChangeset(); } + }//end if + }//end if + + if (isset($param['readonly_token']) === true) { + $readonlyToken = $param['readonly_token']; + $afterReadonlyToken = $phpcsFile->findNext(T_WHITESPACE, ($readonlyToken + 1), $param['token'], true); + + $spacesAfter = 0; + if ($afterReadonlyToken !== false + && $tokens[$readonlyToken]['line'] !== $tokens[$afterReadonlyToken]['line'] + ) { + $spacesAfter = 'newline'; + } else if ($tokens[($readonlyToken + 1)]['code'] === T_WHITESPACE) { + $spacesAfter = $tokens[($readonlyToken + 1)]['length']; } + + if ($spacesAfter !== 1) { + $error = 'Expected 1 space after readonly modifier; %s found'; + $data = [$spacesAfter]; + + $fix = $phpcsFile->addFixableError($error, $readonlyToken, 'SpacingAfterReadonly', $data); + if ($fix === true) { + $phpcsFile->fixer->beginChangeset(); + $phpcsFile->fixer->addContent($readonlyToken, ' '); + + for ($i = ($readonlyToken + 1); $tokens[$i]['code'] === T_WHITESPACE; $i++) { + $phpcsFile->fixer->replaceToken($i, ''); + } + + $phpcsFile->fixer->endChangeset(); + } + }//end if }//end if $commaToken = false; @@ -263,18 +411,53 @@ public function processBracket($phpcsFile, $openBracket) } if ($commaToken !== false) { - if ($tokens[($commaToken - 1)]['code'] === T_WHITESPACE) { + $endOfPreviousParam = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($commaToken - 1), null, true); + + $spaceBeforeComma = 0; + if ($tokens[$endOfPreviousParam]['line'] !== $tokens[$commaToken]['line']) { + $spaceBeforeComma = 'newline'; + } else if ($tokens[($commaToken - 1)]['code'] === T_WHITESPACE) { + $spaceBeforeComma = $tokens[($commaToken - 1)]['length']; + } + + if ($spaceBeforeComma !== 0) { $error = 'Expected 0 spaces between argument "%s" and comma; %s found'; $data = [ $params[($paramNumber - 1)]['name'], - $tokens[($commaToken - 1)]['length'], + $spaceBeforeComma, ]; $fix = $phpcsFile->addFixableError($error, $commaToken, 'SpaceBeforeComma', $data); if ($fix === true) { - $phpcsFile->fixer->replaceToken(($commaToken - 1), ''); - } - } + $startOfCurrentParam = $phpcsFile->findNext(Tokens::$emptyTokens, ($commaToken + 1), null, true); + + $phpcsFile->fixer->beginChangeset(); + $phpcsFile->fixer->addContent($endOfPreviousParam, ','); + $phpcsFile->fixer->replaceToken($commaToken, ''); + + if ($tokens[$commaToken]['line'] === $tokens[$startOfCurrentParam]['line']) { + for ($i = ($commaToken + 1); $tokens[$i]['code'] === T_WHITESPACE; $i++) { + $phpcsFile->fixer->replaceToken($i, ''); + } + } else { + for ($i = ($commaToken - 1); + $tokens[$i]['code'] === T_WHITESPACE && $tokens[$endOfPreviousParam]['line'] !== $tokens[$i]['line']; + $i-- + ) { + $phpcsFile->fixer->replaceToken($i, ''); + } + + for ($i = ($commaToken + 1); + $tokens[$i]['code'] === T_WHITESPACE && $tokens[$commaToken]['line'] === $tokens[$i]['line']; + $i++ + ) { + $phpcsFile->fixer->replaceToken($i, ''); + } + } + + $phpcsFile->fixer->endChangeset(); + }//end if + }//end if // Don't check spacing after the comma if it is the last content on the line. $checkComma = true; @@ -286,58 +469,51 @@ public function processBracket($phpcsFile, $openBracket) } if ($checkComma === true) { - if ($param['type_hint_token'] === false) { - $spacesAfter = 0; - if ($tokens[($commaToken + 1)]['code'] === T_WHITESPACE) { - $spacesAfter = $tokens[($commaToken + 1)]['length']; - } + $typeOfNext = 'argument'; + $typeOfNextShort = 'Arg'; + $contentOfNext = $param['name']; + + if (isset($param['property_visibility']) === true) { + $typeOfNext = 'property modifier'; + $typeOfNextShort = 'PropertyModifier'; + $modifier = $phpcsFile->findNext(Tokens::$emptyTokens, ($commaToken + 1), $param['token'], true); + $contentOfNext = $tokens[$modifier]['content']; + } else if ($param['type_hint_token'] !== false) { + $typeOfNext = 'type hint'; + $typeOfNextShort = 'Hint'; + $contentOfNext = $param['type_hint']; + } - if ($spacesAfter === 0) { - $error = 'Expected 1 space between comma and argument "%s"; 0 found'; - $data = [$param['name']]; - $fix = $phpcsFile->addFixableError($error, $commaToken, 'NoSpaceBeforeArg', $data); - if ($fix === true) { - $phpcsFile->fixer->addContent($commaToken, ' '); - } - } else if ($spacesAfter !== 1) { - $error = 'Expected 1 space between comma and argument "%s"; %s found'; - $data = [ - $param['name'], - $spacesAfter, - ]; - - $fix = $phpcsFile->addFixableError($error, $commaToken, 'SpacingBeforeArg', $data); - if ($fix === true) { - $phpcsFile->fixer->replaceToken(($commaToken + 1), ' '); - } - }//end if - } else { - $hint = $phpcsFile->getTokensAsString($param['type_hint_token'], (($param['type_hint_end_token'] - $param['type_hint_token']) + 1)); - if ($param['nullable_type'] === true) { - $hint = '?'.$hint; - } + $spacesAfter = 0; + if ($tokens[($commaToken + 1)]['code'] === T_WHITESPACE) { + $spacesAfter = $tokens[($commaToken + 1)]['length']; + } - if ($tokens[($commaToken + 1)]['code'] !== T_WHITESPACE) { - $error = 'Expected 1 space between comma and type hint "%s"; 0 found'; - $data = [$hint]; - $fix = $phpcsFile->addFixableError($error, $commaToken, 'NoSpaceBeforeHint', $data); - if ($fix === true) { - $phpcsFile->fixer->addContent($commaToken, ' '); - } - } else { - $gap = $tokens[($commaToken + 1)]['length']; - if ($gap !== 1) { - $error = 'Expected 1 space between comma and type hint "%s"; %s found'; - $data = [ - $hint, - $gap, - ]; - $fix = $phpcsFile->addFixableError($error, $commaToken, 'SpacingBeforeHint', $data); - if ($fix === true) { - $phpcsFile->fixer->replaceToken(($commaToken + 1), ' '); - } - } - }//end if + if ($spacesAfter === 0) { + $error = 'Expected 1 space between comma and %s "%s"; 0 found'; + $errorCode = 'NoSpaceBefore'.$typeOfNextShort; + $data = [ + $typeOfNext, + $contentOfNext, + ]; + + $fix = $phpcsFile->addFixableError($error, $commaToken, $errorCode, $data); + if ($fix === true) { + $phpcsFile->fixer->addContent($commaToken, ' '); + } + } else if ($spacesAfter !== 1) { + $error = 'Expected 1 space between comma and %s "%s"; %s found'; + $errorCode = 'SpacingBefore'.$typeOfNextShort; + $data = [ + $typeOfNext, + $contentOfNext, + $spacesAfter, + ]; + + $fix = $phpcsFile->addFixableError($error, $commaToken, $errorCode, $data); + if ($fix === true) { + $phpcsFile->fixer->replaceToken(($commaToken + 1), ' '); + } }//end if }//end if }//end if diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Functions/MultiLineFunctionDeclarationSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Functions/MultiLineFunctionDeclarationSniff.php index 626b330f1..e88d5c9a9 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Functions/MultiLineFunctionDeclarationSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Functions/MultiLineFunctionDeclarationSniff.php @@ -225,19 +225,23 @@ public function processBracket($phpcsFile, $openBracket, $tokens, $type='functio }//end if // Each line between the brackets should contain a single parameter. - $lastComma = null; for ($i = ($openBracket + 1); $i < $closeBracket; $i++) { // Skip brackets, like arrays, as they can contain commas. - if (isset($tokens[$i]['bracket_opener']) === true) { + if (isset($tokens[$i]['bracket_closer']) === true) { $i = $tokens[$i]['bracket_closer']; continue; } - if (isset($tokens[$i]['parenthesis_opener']) === true) { + if (isset($tokens[$i]['parenthesis_closer']) === true) { $i = $tokens[$i]['parenthesis_closer']; continue; } + if (isset($tokens[$i]['attribute_closer']) === true) { + $i = $tokens[$i]['attribute_closer']; + continue; + } + if ($tokens[$i]['code'] !== T_COMMA) { continue; } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Objects/DisallowObjectStringIndexSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Objects/DisallowObjectStringIndexSniff.php index b619924e8..a956a7c4c 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Objects/DisallowObjectStringIndexSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Objects/DisallowObjectStringIndexSniff.php @@ -12,9 +12,10 @@ namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\Objects; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; -class DisallowObjectStringIndexSniff implements Sniff +class DisallowObjectStringIndexSniff implements Sniff, DeprecatedSniff { /** @@ -84,4 +85,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning JavaScript files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Objects/ObjectMemberCommaSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Objects/ObjectMemberCommaSniff.php index dbbc1b842..b7fc84dfd 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Objects/ObjectMemberCommaSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Objects/ObjectMemberCommaSniff.php @@ -12,10 +12,11 @@ namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\Objects; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Tokens; -class ObjectMemberCommaSniff implements Sniff +class ObjectMemberCommaSniff implements Sniff, DeprecatedSniff { /** @@ -63,4 +64,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning JavaScript files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Operators/ComparisonOperatorUsageSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Operators/ComparisonOperatorUsageSniff.php index e9b41d691..425cedb15 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Operators/ComparisonOperatorUsageSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Operators/ComparisonOperatorUsageSniff.php @@ -44,7 +44,7 @@ class ComparisonOperatorUsageSniff implements Sniff /** * A list of invalid operators with their alternatives. * - * @var array> + * @var array> */ private static $invalidOps = [ 'PHP' => [ diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/PHP/CommentedOutCodeSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/PHP/CommentedOutCodeSniff.php index 59e91f07c..c8e1a4030 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/PHP/CommentedOutCodeSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/PHP/CommentedOutCodeSniff.php @@ -238,23 +238,18 @@ public function process(File $phpcsFile, $stackPtr) ]; $emptyTokens += Tokens::$phpcsCommentTokens; - $numComment = 0; - $numPossible = 0; $numCode = 0; $numNonWhitespace = 0; for ($i = 0; $i < $numTokens; $i++) { - if (isset($emptyTokens[$stringTokens[$i]['code']]) === true) { - // Looks like comment. - $numComment++; - } else if (isset(Tokens::$comparisonTokens[$stringTokens[$i]['code']]) === true - || isset(Tokens::$arithmeticTokens[$stringTokens[$i]['code']]) === true - || $stringTokens[$i]['code'] === T_GOTO_LABEL - ) { + // Do not count comments. + if (isset($emptyTokens[$stringTokens[$i]['code']]) === false // Commented out HTML/XML and other docs contain a lot of these // characters, so it is best to not use them directly. - $numPossible++; - } else { + && isset(Tokens::$comparisonTokens[$stringTokens[$i]['code']]) === false + && isset(Tokens::$arithmeticTokens[$stringTokens[$i]['code']]) === false + && $stringTokens[$i]['code'] !== T_GOTO_LABEL + ) { // Looks like code. $numCode++; } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/PHP/DisallowMultipleAssignmentsSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/PHP/DisallowMultipleAssignmentsSniff.php index 06df65204..2a953b462 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/PHP/DisallowMultipleAssignmentsSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/PHP/DisallowMultipleAssignmentsSniff.php @@ -45,6 +45,11 @@ public function process(File $phpcsFile, $stackPtr) // Ignore default value assignments in function definitions. $function = $phpcsFile->findPrevious([T_FUNCTION, T_CLOSURE, T_FN], ($stackPtr - 1), null, false, null, true); if ($function !== false) { + if (isset($tokens[$function]['parenthesis_closer']) === false) { + // Live coding/parse error. Bow out. + return; + } + $opener = $tokens[$function]['parenthesis_opener']; $closer = $tokens[$function]['parenthesis_closer']; if ($opener < $stackPtr && $closer > $stackPtr) { @@ -83,9 +88,8 @@ public function process(File $phpcsFile, $stackPtr) */ for ($varToken = ($stackPtr - 1); $varToken >= 0; $varToken--) { - if (in_array($tokens[$varToken]['code'], [T_SEMICOLON, T_OPEN_CURLY_BRACKET], true) === true) { - // We've reached the next statement, so we - // didn't find a variable. + if (in_array($tokens[$varToken]['code'], [T_SEMICOLON, T_OPEN_CURLY_BRACKET, T_CLOSE_TAG], true) === true) { + // We've reached the previous statement, so we didn't find a variable. return; } @@ -101,6 +105,13 @@ public function process(File $phpcsFile, $stackPtr) } if ($tokens[$varToken]['code'] === T_VARIABLE) { + $prevNonEmpty = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($varToken - 1), null, true); + if ($tokens[$prevNonEmpty]['code'] === T_OBJECT_OPERATOR) { + // Dynamic property access, the real "start" variable still needs to be found. + $varToken = $prevNonEmpty; + continue; + } + // We found our variable. break; } @@ -115,15 +126,14 @@ public function process(File $phpcsFile, $stackPtr) $allowed = Tokens::$emptyTokens; - $allowed[T_STRING] = T_STRING; - $allowed[T_NS_SEPARATOR] = T_NS_SEPARATOR; - $allowed[T_DOUBLE_COLON] = T_DOUBLE_COLON; - $allowed[T_OBJECT_OPERATOR] = T_OBJECT_OPERATOR; - $allowed[T_ASPERAND] = T_ASPERAND; - $allowed[T_DOLLAR] = T_DOLLAR; - $allowed[T_SELF] = T_SELF; - $allowed[T_PARENT] = T_PARENT; - $allowed[T_STATIC] = T_STATIC; + $allowed[T_STRING] = T_STRING; + $allowed[T_NS_SEPARATOR] = T_NS_SEPARATOR; + $allowed[T_DOUBLE_COLON] = T_DOUBLE_COLON; + $allowed[T_ASPERAND] = T_ASPERAND; + $allowed[T_DOLLAR] = T_DOLLAR; + $allowed[T_SELF] = T_SELF; + $allowed[T_PARENT] = T_PARENT; + $allowed[T_STATIC] = T_STATIC; $varToken = $phpcsFile->findPrevious($allowed, ($varToken - 1), null, true); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/PHP/EmbeddedPhpSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/PHP/EmbeddedPhpSniff.php index 0be6118e4..240b46e55 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/PHP/EmbeddedPhpSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/PHP/EmbeddedPhpSniff.php @@ -102,8 +102,7 @@ private function validateMultilineEmbeddedPhp($phpcsFile, $stackPtr, $closingTag $error = 'Opening PHP tag must be on a line by itself'; $fix = $phpcsFile->addFixableError($error, $stackPtr, 'ContentAfterOpen'); if ($fix === true) { - $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $stackPtr, true); - $padding = (strlen($tokens[$first]['content']) - strlen(ltrim($tokens[$first]['content']))); + $padding = $this->calculateLineIndent($phpcsFile, $stackPtr); $phpcsFile->fixer->beginChangeset(); $phpcsFile->fixer->replaceToken($stackPtr, rtrim($tokens[$stackPtr]['content'])); @@ -147,17 +146,7 @@ private function validateMultilineEmbeddedPhp($phpcsFile, $stackPtr, $closingTag } }//end if - $indent = 0; - $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $stackPtr); - if ($first === false) { - $first = $phpcsFile->findFirstOnLine(T_INLINE_HTML, $stackPtr); - if ($first !== false) { - $indent = (strlen($tokens[$first]['content']) - strlen(ltrim($tokens[$first]['content']))); - } - } else { - $indent = ($tokens[($first + 1)]['column'] - 1); - } - + $indent = $this->calculateLineIndent($phpcsFile, $stackPtr); $contentColumn = ($tokens[$firstContent]['column'] - 1); if ($contentColumn !== $indent) { $error = 'First line of embedded PHP code must be indented %s spaces; %s found'; @@ -180,24 +169,28 @@ private function validateMultilineEmbeddedPhp($phpcsFile, $stackPtr, $closingTag $lastContentBeforeBlock = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); if ($tokens[$lastContentBeforeBlock]['line'] === $tokens[$stackPtr]['line'] - && trim($tokens[$lastContentBeforeBlock]['content']) !== '' + && (($tokens[$lastContentBeforeBlock]['code'] === T_INLINE_HTML + && trim($tokens[$lastContentBeforeBlock]['content']) !== '') + || ($tokens[($lastContentBeforeBlock - 1)]['code'] !== T_INLINE_HTML + && $tokens[($lastContentBeforeBlock - 1)]['line'] === $tokens[$stackPtr]['line'])) ) { $error = 'Opening PHP tag must be on a line by itself'; $fix = $phpcsFile->addFixableError($error, $stackPtr, 'ContentBeforeOpen'); if ($fix === true) { - $padding = 0; - $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $stackPtr); - if ($first === false) { - $first = $phpcsFile->findFirstOnLine(T_INLINE_HTML, $stackPtr); - if ($first !== false) { - $padding = (strlen($tokens[$first]['content']) - strlen(ltrim($tokens[$first]['content']))); - } - } else { - $padding = ($tokens[($first + 1)]['column'] - 1); - } + $padding = $this->calculateLineIndent($phpcsFile, $lastContentBeforeBlock); + $phpcsFile->fixer->beginChangeset(); $phpcsFile->fixer->addContentBefore($stackPtr, $phpcsFile->eolChar.str_repeat(' ', $padding)); - } + + // Make sure we don't leave trailing whitespace behind. + if ($tokens[($stackPtr - 1)]['code'] === T_INLINE_HTML + && trim($tokens[($stackPtr - 1)]['content']) === '' + ) { + $phpcsFile->fixer->replaceToken(($stackPtr - 1), ''); + } + + $phpcsFile->fixer->endChangeset(); + }//end if } else { // Find the first token on the first non-empty line we find. for ($first = ($lastContentBeforeBlock - 1); $first > 0; $first--) { @@ -205,27 +198,11 @@ private function validateMultilineEmbeddedPhp($phpcsFile, $stackPtr, $closingTag continue; } else if (trim($tokens[$first]['content']) !== '') { $first = $phpcsFile->findFirstOnLine([], $first, true); - if ($tokens[$first]['code'] === T_COMMENT - && $tokens[$first]['content'] !== ltrim($tokens[$first]['content']) - ) { - // This is a subsequent line in a star-slash comment containing leading indent. - // We'll need the first line of the comment to correctly determine the indent. - continue; - } - break; } } - $expected = 0; - if ($tokens[$first]['code'] === T_INLINE_HTML - && trim($tokens[$first]['content']) !== '' - ) { - $expected = (strlen($tokens[$first]['content']) - strlen(ltrim($tokens[$first]['content']))); - } else if ($tokens[$first]['code'] === T_WHITESPACE) { - $expected = ($tokens[($first + 1)]['column'] - 1); - } - + $expected = $this->calculateLineIndent($phpcsFile, $first); $expected += 4; $found = ($tokens[$stackPtr]['column'] - 1); if ($found > $expected) { @@ -261,17 +238,7 @@ private function validateMultilineEmbeddedPhp($phpcsFile, $stackPtr, $closingTag ) { $closerIndent = $indent; } else { - $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $closingTag, true); - - while ($tokens[$first]['code'] === T_COMMENT - && $tokens[$first]['content'] !== ltrim($tokens[$first]['content']) - ) { - // This is a subsequent line in a star-slash comment containing leading indent. - // We'll need the first line of the comment to correctly determine the indent. - $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, ($first - 1), true); - } - - $closerIndent = ($tokens[$first]['column'] - 1); + $closerIndent = $this->calculateLineIndent($phpcsFile, $closingTag); } $phpcsFile->fixer->beginChangeset(); @@ -290,10 +257,10 @@ private function validateMultilineEmbeddedPhp($phpcsFile, $stackPtr, $closingTag $error = 'Closing PHP tag must be on a line by itself'; $fix = $phpcsFile->addFixableError($error, $closingTag, 'ContentAfterEnd'); if ($fix === true) { - $first = $phpcsFile->findFirstOnLine(T_WHITESPACE, $closingTag, true); + $indent = $this->calculateLineIndent($phpcsFile, $closingTag); $phpcsFile->fixer->beginChangeset(); $phpcsFile->fixer->addNewline($closingTag); - $phpcsFile->fixer->addContent($closingTag, str_repeat(' ', ($tokens[$first]['column'] - 1))); + $phpcsFile->fixer->addContent($closingTag, str_repeat(' ', $indent)); if ($tokens[$firstContentAfterBlock]['code'] === T_INLINE_HTML) { $trimmedHtmlContent = ltrim($tokens[$firstContentAfterBlock]['content']); @@ -325,8 +292,9 @@ private function validateMultilineEmbeddedPhp($phpcsFile, $stackPtr, $closingTag } // Check for a blank line at the bottom. - if ((isset($tokens[$lastContent]['scope_closer']) === false - || $tokens[$lastContent]['scope_closer'] !== $lastContent) + $lastNonEmpty = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($closingTag - 1), ($stackPtr + 1), true); + if ((isset($tokens[$lastNonEmpty]['scope_closer']) === false + || $tokens[$lastNonEmpty]['scope_closer'] !== $lastNonEmpty) && $tokens[$lastContent]['line'] < ($tokens[$closingTag]['line'] - 1) ) { // Find a token on the blank line to throw the error on. @@ -379,10 +347,14 @@ private function validateInlineEmbeddedPhp($phpcsFile, $stackPtr, $closeTag) } // Check that there is one, and only one space at the start of the statement. - $leadingSpace = 0; - if ($tokens[$stackPtr]['code'] === T_OPEN_TAG) { + $leadingSpace = 0; + $isLongOpenTag = false; + if ($tokens[$stackPtr]['code'] === T_OPEN_TAG + && stripos($tokens[$stackPtr]['content'], 'addFixableError($error, $stackPtr, 'SpacingAfterOpen', $data); if ($fix === true) { - if ($tokens[$stackPtr]['code'] === T_OPEN_TAG) { + if ($isLongOpenTag === true) { $phpcsFile->fixer->replaceToken(($stackPtr + 1), ''); } else if ($tokens[($stackPtr + 1)]['code'] === T_WHITESPACE) { // Short open tag with too much whitespace. @@ -471,7 +443,7 @@ private function validateInlineEmbeddedPhp($phpcsFile, $stackPtr, $closeTag) /** - * Report and fix an set of empty PHP tags. + * Report and fix a set of empty PHP tags. * * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. * @param int $stackPtr The position of the current token in the @@ -509,4 +481,44 @@ private function reportEmptyTagSet(File $phpcsFile, $stackPtr, $closeTag) }//end reportEmptyTagSet() + /** + * Calculate the indent of the line containing the stackPtr. + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token in the + * stack passed in $tokens. + * + * @return int + */ + private function calculateLineIndent(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + + for ($firstOnLine = $stackPtr; $tokens[$firstOnLine]['column'] !== 1; $firstOnLine--); + + // Check if this is a subsequent line in a star-slash comment containing leading indent. + // In that case, we'll need the first line of the comment to correctly determine the indent. + while ($tokens[$firstOnLine]['code'] === T_COMMENT + && $tokens[$firstOnLine]['content'] !== ltrim($tokens[$firstOnLine]['content']) + ) { + for (--$firstOnLine; $tokens[$firstOnLine]['column'] !== 1; $firstOnLine--); + } + + $indent = 0; + if ($tokens[$firstOnLine]['code'] === T_WHITESPACE) { + $indent = ($tokens[($firstOnLine + 1)]['column'] - 1); + } else if ($tokens[$firstOnLine]['code'] === T_INLINE_HTML + || $tokens[$firstOnLine]['code'] === T_END_HEREDOC + || $tokens[$firstOnLine]['code'] === T_END_NOWDOC + ) { + $indent = (strlen($tokens[$firstOnLine]['content']) - strlen(ltrim($tokens[$firstOnLine]['content']))); + } else if ($tokens[$firstOnLine]['code'] === T_DOC_COMMENT_WHITESPACE) { + $indent = (strlen($tokens[$firstOnLine]['content']) - strlen(ltrim($tokens[$firstOnLine]['content'])) - 1); + } + + return $indent; + + }//end calculateLineIndent() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Scope/MemberVarScopeSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Scope/MemberVarScopeSniff.php index 3d1c83f01..912cbdb22 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Scope/MemberVarScopeSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Scope/MemberVarScopeSniff.php @@ -33,9 +33,15 @@ protected function processMemberVar(File $phpcsFile, $stackPtr) return; } - $error = 'Scope modifier not specified for member variable "%s"'; - $data = [$tokens[$stackPtr]['content']]; - $phpcsFile->addError($error, $stackPtr, 'Missing', $data); + if ($properties['set_scope'] === false) { + $error = 'Scope modifier not specified for member variable "%s"'; + $data = [$tokens[$stackPtr]['content']]; + $phpcsFile->addError($error, $stackPtr, 'Missing', $data); + } else { + $error = 'Read scope modifier not specified for member variable "%s"'; + $data = [$tokens[$stackPtr]['content']]; + $phpcsFile->addError($error, $stackPtr, 'AsymReadMissing', $data); + } }//end processMemberVar() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Strings/EchoedStringsSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Strings/EchoedStringsSniff.php index c167d024c..ec516a99a 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Strings/EchoedStringsSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/Strings/EchoedStringsSniff.php @@ -51,7 +51,7 @@ public function process(File $phpcsFile, $stackPtr) $end = $phpcsFile->findNext([T_SEMICOLON, T_CLOSE_TAG], $stackPtr, null, false); - // If the token before the semi-colon is not a closing parenthesis, then we are not concerned. + // If the token before the semicolon is not a closing parenthesis, then we are not concerned. $prev = $phpcsFile->findPrevious(T_WHITESPACE, ($end - 1), null, true); if ($tokens[$prev]['code'] !== T_CLOSE_PARENTHESIS) { $phpcsFile->recordMetric($stackPtr, 'Brackets around echoed strings', 'no'); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/FunctionSpacingSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/FunctionSpacingSniff.php index 01cbd647f..8e25717e1 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/FunctionSpacingSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/FunctionSpacingSniff.php @@ -116,14 +116,39 @@ public function process(File $phpcsFile, $stackPtr) $prev = $phpcsFile->findPrevious($ignore, ($stackPtr - 1), null, true); - while ($tokens[$prev]['code'] === T_ATTRIBUTE_END) { - // Skip past function attributes. - $prev = $phpcsFile->findPrevious($ignore, ($tokens[$prev]['attribute_opener'] - 1), null, true); + $startOfDeclarationLine = $phpcsFile->findNext(T_WHITESPACE, ($prev + 1), null, true); + for ($i = $startOfDeclarationLine; $i >= 0; $i--) { + if ($tokens[$i]['line'] === $tokens[$startOfDeclarationLine]['line']) { + $startOfDeclarationLine = $i; + continue; + } + + break; } - if ($tokens[$prev]['code'] === T_DOC_COMMENT_CLOSE_TAG) { - // Skip past function docblocks. - $prev = $phpcsFile->findPrevious($ignore, ($tokens[$prev]['comment_opener'] - 1), null, true); + // Skip past function docblocks and attributes. + // Only the first docblock is a function docblock. Other docblocks should be disregarded. + $prev = $startOfDeclarationLine; + $seenDocblock = false; + if ($startOfDeclarationLine > 0) { + for ($prev = ($startOfDeclarationLine - 1); $prev > 0; $prev--) { + if ($tokens[$prev]['code'] === T_WHITESPACE) { + continue; + } + + if ($seenDocblock === false && $tokens[$prev]['code'] === T_DOC_COMMENT_CLOSE_TAG) { + $prev = $tokens[$prev]['comment_opener']; + $seenDocblock = true; + continue; + } + + if ($tokens[$prev]['code'] === T_ATTRIBUTE_END) { + $prev = $tokens[$prev]['attribute_opener']; + continue; + } + + break; + } } if ($tokens[$prev]['code'] === T_OPEN_CURLY_BRACKET) { @@ -149,6 +174,12 @@ public function process(File $phpcsFile, $stackPtr) // Allow for comments on the same line as the closer. for ($nextLineToken = ($closer + 1); $nextLineToken < $phpcsFile->numTokens; $nextLineToken++) { + // A doc comment belongs to the next statement and must not be on + // this line. + if ($tokens[$nextLineToken]['code'] === T_DOC_COMMENT_OPEN_TAG) { + break; + } + if ($tokens[$nextLineToken]['line'] !== $tokens[$closer]['line']) { break; } @@ -218,9 +249,11 @@ public function process(File $phpcsFile, $stackPtr) before the function. */ + $startOfPreamble = $phpcsFile->findNext(T_WHITESPACE, ($prev + 1), null, true); + $prevLineToken = null; - for ($i = $stackPtr; $i >= 0; $i--) { - if ($tokens[$i]['line'] === $tokens[$stackPtr]['line']) { + for ($i = $startOfPreamble; $i >= 0; $i--) { + if ($tokens[$i]['line'] === $tokens[$startOfPreamble]['line']) { continue; } @@ -235,33 +268,15 @@ public function process(File $phpcsFile, $stackPtr) $prevContent = 0; $prevLineToken = 0; } else { - $currentLine = $tokens[$stackPtr]['line']; - - $prevContent = $phpcsFile->findPrevious(T_WHITESPACE, $prevLineToken, null, true); - - if ($tokens[$prevContent]['code'] === T_COMMENT - || isset(Tokens::$phpcsCommentTokens[$tokens[$prevContent]['code']]) === true + $firstBefore = $phpcsFile->findPrevious(T_WHITESPACE, ($startOfDeclarationLine - 1), null, true); + if ($tokens[$firstBefore]['code'] === T_COMMENT + || isset(Tokens::$phpcsCommentTokens[$tokens[$firstBefore]['code']]) === true ) { // Ignore comments as they can have different spacing rules, and this // isn't a proper function comment anyway. return; } - while ($tokens[$prevContent]['code'] === T_ATTRIBUTE_END - && $tokens[$prevContent]['line'] === ($currentLine - 1) - ) { - // Account for function attributes. - $currentLine = $tokens[$tokens[$prevContent]['attribute_opener']]['line']; - $prevContent = $phpcsFile->findPrevious(T_WHITESPACE, ($tokens[$prevContent]['attribute_opener'] - 1), null, true); - } - - if ($tokens[$prevContent]['code'] === T_DOC_COMMENT_CLOSE_TAG - && $tokens[$prevContent]['line'] === ($currentLine - 1) - ) { - // Account for function comments. - $prevContent = $phpcsFile->findPrevious(T_WHITESPACE, ($tokens[$prevContent]['comment_opener'] - 1), null, true); - } - // Before we throw an error, check that we are not throwing an error // for another function. We don't want to error for no blank lines after // the previous function and no blank lines before this one as well. @@ -272,38 +287,33 @@ public function process(File $phpcsFile, $stackPtr) $stopAt = array_pop($conditions); } - $prevLineToken = $prevContent; - $prevLine = ($tokens[$prevContent]['line'] - 1); - $i = ($stackPtr - 1); - $foundLines = 0; + $currentLine = $tokens[$startOfPreamble]['line']; + $prevContent = $prev; + $prevLine = ($tokens[$prevContent]['line'] - 1); + $foundLines = ($currentLine - $tokens[$prevContent]['line'] - 1); + + for ($i = $prevContent; $i > $stopAt; $i--) { + if ($tokens[$i]['code'] === T_CLOSE_CURLY_BRACKET) { + if (isset($tokens[$i]['scope_condition']) === true + && $tokens[$tokens[$i]['scope_condition']]['code'] === T_FUNCTION + ) { + // Found a previous function. + return; + } else { + break; + } + } - while ($currentLine !== $prevLine && $currentLine > 1 && $i > $stopAt) { if ($tokens[$i]['code'] === T_FUNCTION) { // Found another interface or abstract function. return; } - if ($tokens[$i]['code'] === T_CLOSE_CURLY_BRACKET - && $tokens[$tokens[$i]['scope_condition']]['code'] === T_FUNCTION - ) { - // Found a previous function. - return; - } - $currentLine = $tokens[$i]['line']; if ($currentLine === $prevLine) { break; } - - if ($tokens[($i - 1)]['line'] < $currentLine && $tokens[($i + 1)]['line'] > $currentLine) { - // This token is on a line by itself. If it is whitespace, the line is empty. - if ($tokens[$i]['code'] === T_WHITESPACE) { - $foundLines++; - } - } - - $i--; - }//end while + }//end for }//end if $requiredSpacing = $this->spacing; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/LanguageConstructSpacingSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/LanguageConstructSpacingSniff.php index c4faf158b..7890dd5fd 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/LanguageConstructSpacingSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/LanguageConstructSpacingSniff.php @@ -12,10 +12,11 @@ namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util; -class LanguageConstructSpacingSniff implements Sniff +class LanguageConstructSpacingSniff implements Sniff, DeprecatedSniff { @@ -88,4 +89,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.3.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Use the Generic.WhiteSpace.LanguageConstructSpacing sniff instead.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/MemberVarSpacingSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/MemberVarSpacingSniff.php index 773d25d4f..56c1fd7a7 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/MemberVarSpacingSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/MemberVarSpacingSniff.php @@ -45,22 +45,31 @@ protected function processMemberVar(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); - $validPrefixes = Tokens::$methodPrefixes; + $stopPoints = [ + T_SEMICOLON, + T_OPEN_CURLY_BRACKET, + T_CLOSE_CURLY_BRACKET, + ]; + + $endOfPreviousStatement = $phpcsFile->findPrevious($stopPoints, ($stackPtr - 1), null, false, null, true); + + $validPrefixes = Tokens::$scopeModifiers; + $validPrefixes[] = T_STATIC; + $validPrefixes[] = T_FINAL; $validPrefixes[] = T_VAR; + $validPrefixes[] = T_READONLY; - $startOfStatement = $phpcsFile->findPrevious($validPrefixes, ($stackPtr - 1), null, false, null, true); + $startOfStatement = $phpcsFile->findNext($validPrefixes, ($endOfPreviousStatement + 1), $stackPtr, false, null, true); if ($startOfStatement === false) { + // Parse error/live coding - property without modifier. Bow out. return; } $endOfStatement = $phpcsFile->findNext(T_SEMICOLON, ($stackPtr + 1), null, false, null, true); - $ignore = $validPrefixes; - $ignore[T_WHITESPACE] = T_WHITESPACE; - $start = $startOfStatement; for ($prev = ($startOfStatement - 1); $prev >= 0; $prev--) { - if (isset($ignore[$tokens[$prev]['code']]) === true) { + if ($tokens[$prev]['code'] === T_WHITESPACE) { continue; } @@ -75,60 +84,56 @@ protected function processMemberVar(File $phpcsFile, $stackPtr) break; } - if (isset(Tokens::$commentTokens[$tokens[$prev]['code']]) === true) { + if ($tokens[$prev]['code'] === T_DOC_COMMENT_CLOSE_TAG) { + $start = $prev; + } else if (isset(Tokens::$commentTokens[$tokens[$prev]['code']]) === true) { // Assume the comment belongs to the member var if it is on a line by itself. $prevContent = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($prev - 1), null, true); if ($tokens[$prevContent]['line'] !== $tokens[$prev]['line']) { - // Check the spacing, but then skip it. - $foundLines = ($tokens[$startOfStatement]['line'] - $tokens[$prev]['line'] - 1); - if ($foundLines > 0) { - for ($i = ($prev + 1); $i < $startOfStatement; $i++) { - if ($tokens[$i]['column'] !== 1) { - continue; - } - - if ($tokens[$i]['code'] === T_WHITESPACE - && $tokens[$i]['line'] !== $tokens[($i + 1)]['line'] - ) { - $error = 'Expected 0 blank lines after member var comment; %s found'; - $data = [$foundLines]; - $fix = $phpcsFile->addFixableError($error, $prev, 'AfterComment', $data); - if ($fix === true) { - $phpcsFile->fixer->beginChangeset(); - // Inline comments have the newline included in the content but - // docblocks do not. - if ($tokens[$prev]['code'] === T_COMMENT) { - $phpcsFile->fixer->replaceToken($prev, rtrim($tokens[$prev]['content'])); - } - - for ($i = ($prev + 1); $i <= $startOfStatement; $i++) { - if ($tokens[$i]['line'] === $tokens[$startOfStatement]['line']) { - break; - } - - // Remove the newline after the docblock, and any entirely - // empty lines before the member var. - if (($tokens[$i]['code'] === T_WHITESPACE - && $tokens[$i]['line'] === $tokens[$prev]['line']) - || ($tokens[$i]['column'] === 1 - && $tokens[$i]['line'] !== $tokens[($i + 1)]['line']) - ) { - $phpcsFile->fixer->replaceToken($i, ''); - } - } - - $phpcsFile->fixer->addNewline($prev); - $phpcsFile->fixer->endChangeset(); - }//end if - - break; - }//end if - }//end for - }//end if - $start = $prev; - }//end if - }//end if + } + } + + // Check for blank lines between the docblock/comment and the property declaration. + for ($i = ($start + 1); $i < $startOfStatement; $i++) { + if (isset($tokens[$i]['attribute_closer']) === true) { + $i = $tokens[$i]['attribute_closer']; + continue; + } + + if ($tokens[$i]['column'] !== 1 + || $tokens[$i]['code'] !== T_WHITESPACE + || $tokens[$i]['line'] === $tokens[($i + 1)]['line'] + // Do not report blank lines after a PHPCS annotation as removing the blank lines could change the meaning. + || isset(Tokens::$phpcsCommentTokens[$tokens[($i - 1)]['code']]) === true + ) { + continue; + } + + // We found a blank line which should be reported. + $nextNonWhitespace = $phpcsFile->findNext(T_WHITESPACE, ($i + 1), null, true); + $foundLines = ($tokens[$nextNonWhitespace]['line'] - $tokens[$i]['line']); + + $error = 'Expected no blank lines between the member var comment and the declaration; %s found'; + $data = [$foundLines]; + $fix = $phpcsFile->addFixableError($error, $i, 'AfterComment', $data); + + if ($fix === true) { + $phpcsFile->fixer->beginChangeset(); + + for ($j = $i; $j < $nextNonWhitespace; $j++) { + if ($tokens[$j]['line'] === $tokens[$nextNonWhitespace]['line']) { + break; + } + + $phpcsFile->fixer->replaceToken($j, ''); + } + + $phpcsFile->fixer->endChangeset(); + } + + $i = $nextNonWhitespace; + }//end for // There needs to be n blank lines before the var, not counting comments. if ($start === $startOfStatement) { diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php index 87dbed881..2a87978a0 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php @@ -114,6 +114,9 @@ public function register() $targets[] = T_INLINE_ELSE; $targets[] = T_INSTANCEOF; + // Also register the contexts we want to specifically skip over. + $targets[] = T_DECLARE; + return $targets; }//end register() @@ -126,12 +129,25 @@ public function register() * @param int $stackPtr The position of the current token in * the stack passed in $tokens. * - * @return void + * @return void|int Optionally returns a stack pointer. The sniff will not be + * called again on the current file until the returned stack + * pointer is reached. Return `$phpcsFile->numTokens` to skip + * the rest of the file. */ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); + // Skip over declare statements as those should be handled by different sniffs. + if ($tokens[$stackPtr]['code'] === T_DECLARE) { + if (isset($tokens[$stackPtr]['parenthesis_closer']) === false) { + // Parse error / live coding. + return $phpcsFile->numTokens; + } + + return $tokens[$stackPtr]['parenthesis_closer']; + } + if ($this->isOperator($phpcsFile, $stackPtr) === false) { return; } @@ -222,7 +238,8 @@ public function process(File $phpcsFile, $stackPtr) ) { // Throw an error for assignments only if enabled using the sniff property // because other standards allow multiple spaces to align assignments. - if ($tokens[($stackPtr - 2)]['line'] !== $tokens[$stackPtr]['line']) { + $prevNonWhitespace = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true); + if ($tokens[$prevNonWhitespace]['line'] !== $tokens[$stackPtr]['line']) { $found = 'newline'; } else { $found = $tokens[($stackPtr - 1)]['length']; @@ -237,20 +254,29 @@ public function process(File $phpcsFile, $stackPtr) $operator, $found, ]; - $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpacingBefore', $data); - if ($fix === true) { - $phpcsFile->fixer->beginChangeset(); - if ($found === 'newline') { - $i = ($stackPtr - 2); - while ($tokens[$i]['code'] === T_WHITESPACE) { - $phpcsFile->fixer->replaceToken($i, ''); - $i--; + + if (isset(Tokens::$commentTokens[$tokens[$prevNonWhitespace]['code']]) === true) { + // Throw a non-fixable error if the token on the previous line is a comment token, + // as in that case it's not for the sniff to decide where the comment should be moved to + // and it would get us into unfixable situations as the new line char is included + // in the contents of the comment token. + $phpcsFile->addError($error, $stackPtr, 'SpacingBefore', $data); + } else { + $fix = $phpcsFile->addFixableError($error, $stackPtr, 'SpacingBefore', $data); + if ($fix === true) { + $phpcsFile->fixer->beginChangeset(); + if ($found === 'newline') { + $i = ($stackPtr - 2); + while ($tokens[$i]['code'] === T_WHITESPACE) { + $phpcsFile->fixer->replaceToken($i, ''); + $i--; + } } - } - $phpcsFile->fixer->replaceToken(($stackPtr - 1), ' '); - $phpcsFile->fixer->endChangeset(); - } + $phpcsFile->fixer->replaceToken(($stackPtr - 1), ' '); + $phpcsFile->fixer->endChangeset(); + } + }//end if }//end if }//end if @@ -327,11 +353,13 @@ protected function isOperator(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); + if ($tokens[$stackPtr]['code'] === T_DECLARE) { + return false; + } + // Skip default values in function declarations. // Skip declare statements. - if ($tokens[$stackPtr]['code'] === T_EQUAL - || $tokens[$stackPtr]['code'] === T_MINUS - ) { + if ($tokens[$stackPtr]['code'] === T_EQUAL) { if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) { $parenthesis = array_keys($tokens[$stackPtr]['nested_parenthesis']); $bracket = array_pop($parenthesis); @@ -340,7 +368,6 @@ protected function isOperator(File $phpcsFile, $stackPtr) if ($tokens[$function]['code'] === T_FUNCTION || $tokens[$function]['code'] === T_CLOSURE || $tokens[$function]['code'] === T_FN - || $tokens[$function]['code'] === T_DECLARE ) { return false; } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/PropertyLabelSpacingSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/PropertyLabelSpacingSniff.php index ec8218fef..7e5bf9c20 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/PropertyLabelSpacingSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/PropertyLabelSpacingSniff.php @@ -12,9 +12,10 @@ namespace PHP_CodeSniffer\Standards\Squiz\Sniffs\WhiteSpace; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\DeprecatedSniff; use PHP_CodeSniffer\Sniffs\Sniff; -class PropertyLabelSpacingSniff implements Sniff +class PropertyLabelSpacingSniff implements Sniff, DeprecatedSniff { /** @@ -78,4 +79,40 @@ public function process(File $phpcsFile, $stackPtr) }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return 'Support for scanning JavaScript files will be removed completely in v4.0.0.'; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/ScopeKeywordSpacingSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/ScopeKeywordSpacingSniff.php index 65cc13f91..7c3ce113d 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/ScopeKeywordSpacingSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/ScopeKeywordSpacingSniff.php @@ -24,9 +24,9 @@ class ScopeKeywordSpacingSniff implements Sniff */ public function register() { - $register = Tokens::$scopeModifiers; - $register[] = T_STATIC; - $register[] = T_READONLY; + $register = Tokens::$methodPrefixes; + $register += Tokens::$scopeModifiers; + $register[T_READONLY] = T_READONLY; return $register; }//end register() @@ -45,7 +45,9 @@ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); - if (isset($tokens[($stackPtr + 1)]) === false) { + $nextNonWhitespace = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + if ($nextNonWhitespace === false) { + // Parse error/live coding. Bow out. return; } @@ -127,9 +129,6 @@ public function process(File $phpcsFile, $stackPtr) if ($tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE) { $spacing = 0; - } else if (isset($tokens[($stackPtr + 2)]) === false) { - // Parse error/live coding. Bow out. - return; } else { if ($tokens[($stackPtr + 2)]['line'] !== $tokens[$stackPtr]['line']) { $spacing = 'newline'; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/SemicolonSpacingSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/SemicolonSpacingSniff.php index e10c5cee7..dbf719d20 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/SemicolonSpacingSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Sniffs/WhiteSpace/SemicolonSpacingSniff.php @@ -59,7 +59,7 @@ public function process(File $phpcsFile, $stackPtr) $nonSpace = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 2), null, true); - // Detect whether this is a semi-colon for a condition in a `for()` control structure. + // Detect whether this is a semicolon for a condition in a `for()` control structure. $forCondition = false; if (isset($tokens[$stackPtr]['nested_parenthesis']) === true) { $nestedParens = $tokens[$stackPtr]['nested_parenthesis']; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.1.inc index 5b539a372..6a25ab907 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.1.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.1.inc @@ -19,7 +19,7 @@ class TestClass 'height' => '', ); - private $_bad = Array( + private $_bad = ARRAY( 'width' => '', 'height' => '' ); @@ -535,3 +535,26 @@ $x = array( 'a', 'b', ); + +$x = array( + 1, static fn (float $item): float => match ($item) { + 2.0 => 3.0, + default => $item + }, + ); + +$x = array( + 1, static::helloWorld(), $class instanceof static, + 2, + ); + +$noSpaceBeforeDoubleArrow = array( + 'width'=> '', + 'height' => '', + ); + +$newlineAfterDoubleArrow = array( + 'width' => + '', + 'height' => '', + ); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.1.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.1.inc.fixed index 5ebf71502..048f898c8 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.1.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.1.inc.fixed @@ -571,3 +571,28 @@ $x = array( 'a', 'b', ); + +$x = array( + 1, + static fn (float $item): float => match ($item) { + 2.0 => 3.0, + default => $item + }, + ); + +$x = array( + 1, + static::helloWorld(), + $class instanceof static, + 2, + ); + +$noSpaceBeforeDoubleArrow = array( + 'width' => '', + 'height' => '', + ); + +$newlineAfterDoubleArrow = array( + 'width' => '', + 'height' => '', + ); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.2.inc index 7bcc5e044..415042d89 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.2.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.2.inc @@ -524,3 +524,32 @@ $x = [ 'a', 'b', ]; + +$x = [ + 1, static fn (float $item): float => match ($item) { + 2.0 => 3.0, + default => $item + }, + ]; + +$x = [ + 1, static::helloWorld(), $class instanceof static, + 2, + ]; + +$noSpaceBeforeDoubleArrow = [ + 'width'=> '', + 'height' => '', + ]; + +$newlineAfterDoubleArrow = [ + 'width' => + '', + 'height' => '', + ]; + +// Sniff should ignore short lists when inside a foreach. +// https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/527 +foreach ($data as [, , $value]) {} +foreach ($array as $k => [$v1, , $v3]) {} +foreach ([$a ,$b] as $c) {} // Not a short list. Sniff should handle it. diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.2.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.2.inc.fixed index d156357c9..d835064ba 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.2.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.2.inc.fixed @@ -558,3 +558,34 @@ $x = [ 'a', 'b', ]; + +$x = [ + 1, + static fn (float $item): float => match ($item) { + 2.0 => 3.0, + default => $item + }, + ]; + +$x = [ + 1, + static::helloWorld(), + $class instanceof static, + 2, + ]; + +$noSpaceBeforeDoubleArrow = [ + 'width' => '', + 'height' => '', + ]; + +$newlineAfterDoubleArrow = [ + 'width' => '', + 'height' => '', + ]; + +// Sniff should ignore short lists when inside a foreach. +// https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/527 +foreach ($data as [, , $value]) {} +foreach ($array as $k => [$v1, , $v3]) {} +foreach ([$a, $b] as $c) {} // Not a short list. Sniff should handle it. diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.3.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.3.inc new file mode 100644 index 000000000..beb5ae1ae --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Arrays/ArrayDeclarationUnitTest.3.inc @@ -0,0 +1,7 @@ + 1, 530 => 1, 537 => 1, + 540 => 1, + 547 => 2, + 552 => 1, + 557 => 1, ]; case 'ArrayDeclarationUnitTest.2.inc': return [ @@ -225,7 +229,14 @@ public function getErrorList($testFile='') 512 => 1, 519 => 1, 526 => 1, + 529 => 1, + 536 => 2, + 541 => 1, + 546 => 1, + 555 => 2, ]; + case 'ArrayDeclarationUnitTest.4.inc': + return [8 => 1]; default: return []; }//end switch diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/CSS/ShorthandSizeUnitTest.css b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/CSS/ShorthandSizeUnitTest.1.css similarity index 89% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/CSS/ShorthandSizeUnitTest.css rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/CSS/ShorthandSizeUnitTest.1.css index cfc4503c4..c3d07ef5c 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/CSS/ShorthandSizeUnitTest.css +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/CSS/ShorthandSizeUnitTest.1.css @@ -39,7 +39,3 @@ 2px /* phpcs:disable Standard.Category.SniffName -- for reasons */ 4px; } - -/* Intentional parse error. Live coding resilience. This has to be the last test in the file. */ -#live-coding { - margin: 8px 8px 8px 8px diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/CSS/ShorthandSizeUnitTest.css.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/CSS/ShorthandSizeUnitTest.1.css.fixed similarity index 88% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/CSS/ShorthandSizeUnitTest.css.fixed rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/CSS/ShorthandSizeUnitTest.1.css.fixed index 3472cb174..36297dd60 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/CSS/ShorthandSizeUnitTest.css.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/CSS/ShorthandSizeUnitTest.1.css.fixed @@ -35,7 +35,3 @@ 2px /* phpcs:disable Standard.Category.SniffName -- for reasons */ 4px; } - -/* Intentional parse error. Live coding resilience. This has to be the last test in the file. */ -#live-coding { - margin: 8px 8px 8px 8px diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/CSS/ShorthandSizeUnitTest.2.css b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/CSS/ShorthandSizeUnitTest.2.css new file mode 100644 index 000000000..2a91cf71a --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/CSS/ShorthandSizeUnitTest.2.css @@ -0,0 +1,3 @@ +/* Intentional parse error. Live coding resilience. */ +#live-coding { + margin: 8px 8px 8px 8px diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/CSS/ShorthandSizeUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/CSS/ShorthandSizeUnitTest.php index 91ba7fb09..7394b77c2 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/CSS/ShorthandSizeUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/CSS/ShorthandSizeUnitTest.php @@ -26,22 +26,30 @@ final class ShorthandSizeUnitTest extends AbstractSniffUnitTest * The key of the array should represent the line number and the value * should represent the number of errors that should occur on that line. * + * @param string $testFile The name of the file being tested. + * * @return array */ - public function getErrorList() + public function getErrorList($testFile='') { - return [ - 8 => 1, - 9 => 1, - 10 => 1, - 11 => 1, - 12 => 1, - 13 => 1, - 15 => 1, - 16 => 1, - 17 => 1, - 21 => 1, - ]; + switch ($testFile) { + case 'ShorthandSizeUnitTest.1.css': + return [ + 8 => 1, + 9 => 1, + 10 => 1, + 11 => 1, + 12 => 1, + 13 => 1, + 15 => 1, + 16 => 1, + 17 => 1, + 21 => 1, + ]; + + default: + return []; + }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ClassDeclarationUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ClassDeclarationUnitTest.inc index 2af42d372..25d8d3021 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ClassDeclarationUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ClassDeclarationUnitTest.inc @@ -128,3 +128,25 @@ class Test readonly class Test { } + +class TooMuchSpacingBelowClassButShouldNotBeFlaggedWhenNextThingIsFunctionWithAttribute +{ + var $x; +} + + +#[AttributesShouldBeJumpedOver] +function ThisIsFineAndHasAttribute() {} + +class TooMuchSpacingBelowClassButShouldNotBeFlaggedWhenNextThingIsFunctionWithDocblockAndAttribute +{ + var $x; +} + + +/** + * No error. + */ +#[AttributesShouldBeJumpedOver] +#[ASecondAttributeShouldBeJumpedOverToo]#[AndAThirdAsWell] +function ThisIsFineAndHasDocblockAndAttribute() {} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ClassDeclarationUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ClassDeclarationUnitTest.inc.fixed index 5d01b68e0..bf042f932 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ClassDeclarationUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ClassDeclarationUnitTest.inc.fixed @@ -138,3 +138,25 @@ readonly class Test readonly class Test { } + +class TooMuchSpacingBelowClassButShouldNotBeFlaggedWhenNextThingIsFunctionWithAttribute +{ + var $x; +} + + +#[AttributesShouldBeJumpedOver] +function ThisIsFineAndHasAttribute() {} + +class TooMuchSpacingBelowClassButShouldNotBeFlaggedWhenNextThingIsFunctionWithDocblockAndAttribute +{ + var $x; +} + + +/** + * No error. + */ +#[AttributesShouldBeJumpedOver] +#[ASecondAttributeShouldBeJumpedOverToo]#[AndAThirdAsWell] +function ThisIsFineAndHasDocblockAndAttribute() {} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ClassDeclarationUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ClassDeclarationUnitTest.php index 635fd5d10..be3fd5997 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ClassDeclarationUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ClassDeclarationUnitTest.php @@ -68,6 +68,8 @@ public function getErrorList() 121 => 1, 124 => 2, 128 => 2, + 132 => 1, + 141 => 1, ]; }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ClassFileName Spaces In FilenameUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ClassFileName Spaces In FilenameUnitTest.inc new file mode 100644 index 000000000..a89e3d03c --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ClassFileName Spaces In FilenameUnitTest.inc @@ -0,0 +1,7 @@ + +enum + // Comment + ExtraClassFileNameUnitTest {} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ClassFileNameUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ClassFileNameUnitTest.php index 7a01e9c09..2678a0526 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ClassFileNameUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ClassFileNameUnitTest.php @@ -9,6 +9,7 @@ namespace PHP_CodeSniffer\Standards\Squiz\Tests\Classes; +use DirectoryIterator; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; /** @@ -20,46 +21,109 @@ final class ClassFileNameUnitTest extends AbstractSniffUnitTest { + /** + * Get a list of all test files to check. + * + * These will have the same base as the sniff name but different extensions. + * We ignore the .php file as it is the class. + * + * @param string $testFileBase The base path that the unit tests files will have. + * + * @return string[] + */ + protected function getTestFiles($testFileBase) + { + $testFiles = []; + + $dir = substr($testFileBase, 0, strrpos($testFileBase, DIRECTORY_SEPARATOR)); + $di = new DirectoryIterator($dir); + + // Strip off the path and the "UnitTest." suffix from the $testFileBase to allow + // for some less conventionally named test case files. + $fileBase = str_replace($dir, '', $testFileBase); + $fileBase = substr($fileBase, 1, -9); + + foreach ($di as $file) { + $fileName = $file->getBasename('UnitTest.inc'); + $extension = $file->getExtension(); + if (substr($fileName, 0, strlen($fileBase)) === $fileBase + && $extension === 'inc' + ) { + $testFiles[] = $file->getPathname(); + } + } + + // Put them in order. + sort($testFiles, SORT_NATURAL); + + return $testFiles; + + }//end getTestFiles() + + /** * Returns the lines where errors should occur. * * The key of the array should represent the line number and the value * should represent the number of errors that should occur on that line. * + * @param string $testFile The name of the file being tested. + * * @return array */ - public function getErrorList() + public function getErrorList($testFile='') { - return [ - 12 => 1, - 13 => 1, - 14 => 1, - 15 => 1, - 16 => 1, - 17 => 1, - 18 => 1, - 19 => 1, - 20 => 1, - 21 => 1, - 22 => 1, - 23 => 1, - 27 => 1, - 28 => 1, - 29 => 1, - 30 => 1, - 31 => 1, - 32 => 1, - 33 => 1, - 34 => 1, - 35 => 1, - 36 => 1, - 37 => 1, - 38 => 1, - 39 => 1, - 40 => 1, - 41 => 1, - 42 => 1, - ]; + switch ($testFile) { + case 'ClassFileNameUnitTest.inc': + return [ + 12 => 1, + 13 => 1, + 14 => 1, + 15 => 1, + 16 => 1, + 17 => 1, + 18 => 1, + 19 => 1, + 20 => 1, + 21 => 1, + 22 => 1, + 23 => 1, + 27 => 1, + 28 => 1, + 29 => 1, + 30 => 1, + 31 => 1, + 32 => 1, + 33 => 1, + 34 => 1, + 35 => 1, + 36 => 1, + 37 => 1, + 38 => 1, + 39 => 1, + 40 => 1, + 41 => 1, + 42 => 1, + ]; + + case 'ClassFileNameLiveCodingFailUnitTest.inc': + return [ + 6 => 1, + ]; + + case 'ClassFileName Spaces In FilenameUnitTest.inc': + return [ + 7 => 1, + ]; + + case 'ClassFileName-Dashes-In-FilenameUnitTest.inc': + return [ + 7 => 1, + ]; + + default: + return []; + }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/LowercaseClassKeywordsUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/LowercaseClassKeywordsUnitTest.inc index da47fa179..5f726623f 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/LowercaseClassKeywordsUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/LowercaseClassKeywordsUnitTest.inc @@ -14,3 +14,7 @@ ReadOnly class MyClass $a = new CLASS() {}; $anon = new ReadOnly class() {}; + +class FinalProperties { + FINAL int $prop = 1; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/LowercaseClassKeywordsUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/LowercaseClassKeywordsUnitTest.inc.fixed index 0c18bc86b..210748389 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/LowercaseClassKeywordsUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/LowercaseClassKeywordsUnitTest.inc.fixed @@ -14,3 +14,7 @@ readonly class MyClass $a = new class() {}; $anon = new readonly class() {}; + +class FinalProperties { + final int $prop = 1; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/LowercaseClassKeywordsUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/LowercaseClassKeywordsUnitTest.php index 7fc45e786..0bf0010b8 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/LowercaseClassKeywordsUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/LowercaseClassKeywordsUnitTest.php @@ -41,6 +41,7 @@ public function getErrorList() 11 => 1, 14 => 1, 16 => 1, + 19 => 1, ]; return $errors; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/SelfMemberReferenceUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/SelfMemberReferenceUnitTest.inc index 0a0729a0a..4f1781386 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/SelfMemberReferenceUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/SelfMemberReferenceUnitTest.inc @@ -172,3 +172,28 @@ namespace Foo /*comment*/ \ Bah { } } } + +namespace EndsIn\CloseTag ?> + + 2, 162 => 1, 171 => 1, + 183 => 1, + 197 => 1, ]; }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ValidClassNameUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ValidClassNameUnitTest.inc index 3fe39435b..7ec00650b 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ValidClassNameUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ValidClassNameUnitTest.inc @@ -189,3 +189,13 @@ $foo = new class( } ) extends DateTime { }; + +class /*comment*/ CommentsShouldBeIgnoredValidName {} +trait //comment + commentsshouldbeignoredInvalidName {} +interface // phpcs:ignore Stnd.Cat.SniffName -- just testing + annotationshouldbeignored_InvalidName {} + +class CommentsShouldBeIgnoredValid/*comment*/ {} +interface annotations_should_be_ignored_InvalidName// phpcs:ignore Stnd.Cat.SniffName -- just testing +{} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ValidClassNameUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ValidClassNameUnitTest.php index 8e505a418..d23816591 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ValidClassNameUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Classes/ValidClassNameUnitTest.php @@ -57,6 +57,9 @@ public function getErrorList() 150 => 1, 151 => 1, 156 => 1, + 195 => 1, + 197 => 1, + 200 => 1, ]; }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/BlockCommentUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/BlockCommentUnitTest.inc index 7cd04a211..0e5d87acd 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/BlockCommentUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/BlockCommentUnitTest.inc @@ -307,3 +307,27 @@ abstract class MyClass enum MyEnum { } + +class FinalProperties { + /** + * Comment should be ignored. + */ + final int $prop = 1; +} + +class AsymVisibility { + /** + * Comment should be ignored. + */ + public(set) int $prop = 1; + + /** + * Comment should be ignored. + */ + protected(set) int $prop = 1; + + /** + * Comment should be ignored. + */ + private(set) int $prop = 1; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/BlockCommentUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/BlockCommentUnitTest.inc.fixed index 2e97614e2..0935d4ae9 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/BlockCommentUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/BlockCommentUnitTest.inc.fixed @@ -309,3 +309,27 @@ abstract class MyClass enum MyEnum { } + +class FinalProperties { + /** + * Comment should be ignored. + */ + final int $prop = 1; +} + +class AsymVisibility { + /** + * Comment should be ignored. + */ + public(set) int $prop = 1; + + /** + * Comment should be ignored. + */ + protected(set) int $prop = 1; + + /** + * Comment should be ignored. + */ + private(set) int $prop = 1; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/ClosingDeclarationCommentUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/ClosingDeclarationCommentUnitTest.1.inc similarity index 58% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/ClosingDeclarationCommentUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/ClosingDeclarationCommentUnitTest.1.inc index 1a57149b2..560370bfb 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/ClosingDeclarationCommentUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/ClosingDeclarationCommentUnitTest.1.inc @@ -84,3 +84,41 @@ enum MissingClosingComment { enum HasClosingComment { }//end enum + +function misplacedClosingCommentWhitespace() { +} //end misplacedClosingCommentWhitespace() + +function misplacedClosingCommentMultipleNewlines() { +} + + +//end misplacedClosingCommentMultipleNewlines() + +function missingClosingComment() { +} + +function commentHasMoreIndentationThanFunction() { +} + //end commentHasMoreIndentationThanFunction() + +class Foo { + function commentHasLessIndentationThanFunction() { + } + //end commentHasLessIndentationThanFunction() + + function misplacedClosingCommentWithIndentation() { + } + //end misplacedClosingCommentWithIndentation() +}//end class + +// Anonymous classes don't need end comments. +$anon = new class {}; + +// Arrow functions don't need end comments. +$arrow = fn($a) => $a; + +trait TestTrait { +}//end trait + +trait TestTrait { +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/ClosingDeclarationCommentUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/ClosingDeclarationCommentUnitTest.1.inc.fixed similarity index 59% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/ClosingDeclarationCommentUnitTest.inc.fixed rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/ClosingDeclarationCommentUnitTest.1.inc.fixed index 4515c41a4..8c6901452 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/ClosingDeclarationCommentUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/ClosingDeclarationCommentUnitTest.1.inc.fixed @@ -83,3 +83,35 @@ enum MissingClosingComment { enum HasClosingComment { }//end enum + +function misplacedClosingCommentWhitespace() { +}//end misplacedClosingCommentWhitespace() + +function misplacedClosingCommentMultipleNewlines() { +}//end misplacedClosingCommentMultipleNewlines() + +function missingClosingComment() { +}//end missingClosingComment() + +function commentHasMoreIndentationThanFunction() { +}//end commentHasMoreIndentationThanFunction() + +class Foo { + function commentHasLessIndentationThanFunction() { + }//end commentHasLessIndentationThanFunction() + + function misplacedClosingCommentWithIndentation() { + }//end misplacedClosingCommentWithIndentation() +}//end class + +// Anonymous classes don't need end comments. +$anon = new class {}; + +// Arrow functions don't need end comments. +$arrow = fn($a) => $a; + +trait TestTrait { +}//end trait + +trait TestTrait { +}//end trait diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/ClosingDeclarationCommentUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/ClosingDeclarationCommentUnitTest.2.inc new file mode 100644 index 000000000..25913dd8f --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/ClosingDeclarationCommentUnitTest.2.inc @@ -0,0 +1,7 @@ + */ - public function getErrorList() + public function getErrorList($testFile='') { - return [ - 13 => 1, - 17 => 1, - 31 => 1, - 41 => 1, - 59 => 1, - 63 => 1, - 67 => 1, - 79 => 1, - 83 => 1, - ]; + switch ($testFile) { + case 'ClosingDeclarationCommentUnitTest.1.inc': + return [ + 13 => 1, + 17 => 1, + 31 => 1, + 41 => 1, + 59 => 1, + 63 => 1, + 67 => 1, + 79 => 1, + 83 => 1, + 89 => 1, + 92 => 1, + 98 => 1, + 101 => 1, + 106 => 1, + 110 => 1, + 124 => 1, + ]; + + case 'ClosingDeclarationCommentUnitTest.4.inc': + return [8 => 1]; + + case 'ClosingDeclarationCommentUnitTest.5.inc': + return [11 => 1]; + + default: + return []; + }//end switch }//end getErrorList() @@ -51,11 +72,23 @@ public function getErrorList() * The key of the array should represent the line number and the value * should represent the number of warnings that should occur on that line. * + * @param string $testFile The name of the test file being tested. + * * @return array */ - public function getWarningList() + public function getWarningList($testFile='') { - return [71 => 1]; + switch ($testFile) { + case 'ClosingDeclarationCommentUnitTest.1.inc': + return [71 => 1]; + + case 'ClosingDeclarationCommentUnitTest.2.inc': + case 'ClosingDeclarationCommentUnitTest.3.inc': + return [7 => 1]; + + default: + return []; + } }//end getWarningList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/DocCommentAlignmentUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/DocCommentAlignmentUnitTest.inc index d95acd2ce..e8b135697 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/DocCommentAlignmentUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/DocCommentAlignmentUnitTest.inc @@ -101,3 +101,33 @@ enum Suits: string * Example with no errors. **************************************************************************/ function example() {} + +/** + * Some info about the class here. + */ +final class FinalClassWithFinalProp +{ + /** + *Some info about the property here. + * + * @var int + */ + final $property = 10; +} + +class AsymVisibility { + /** + * Stars should be aligned. + */ + public(set) int $prop = 1; + + /** + * Stars should be aligned. + */ + protected(set) int $prop = 1; + + /** + * Stars should be aligned. + */ + private(set) int $prop = 1; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/DocCommentAlignmentUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/DocCommentAlignmentUnitTest.inc.fixed index ea6488a02..0b8a68e8c 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/DocCommentAlignmentUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/DocCommentAlignmentUnitTest.inc.fixed @@ -101,3 +101,33 @@ enum Suits: string * Example with no errors. **************************************************************************/ function example() {} + +/** + * Some info about the class here. + */ +final class FinalClassWithFinalProp +{ + /** + * Some info about the property here. + * + * @var int + */ + final $property = 10; +} + +class AsymVisibility { + /** + * Stars should be aligned. + */ + public(set) int $prop = 1; + + /** + * Stars should be aligned. + */ + protected(set) int $prop = 1; + + /** + * Stars should be aligned. + */ + private(set) int $prop = 1; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/DocCommentAlignmentUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/DocCommentAlignmentUnitTest.php index a1ab9c327..eac7a9ec1 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/DocCommentAlignmentUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/DocCommentAlignmentUnitTest.php @@ -56,7 +56,19 @@ public function getErrorList($testFile='') $errors[91] = 1; $errors[95] = 1; $errors[96] = 1; - } + + $errors[106] = 1; + $errors[107] = 1; + $errors[111] = 2; + $errors[112] = 1; + $errors[113] = 1; + $errors[114] = 1; + + $errors[120] = 1; + $errors[121] = 1; + $errors[125] = 1; + $errors[126] = 1; + }//end if return $errors; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/FileCommentUnitTest.1.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/FileCommentUnitTest.1.inc.fixed index f584c5527..dbf886545 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/FileCommentUnitTest.1.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/FileCommentUnitTest.1.inc.fixed @@ -25,7 +25,7 @@ * @author * @copyright 1997 Squiz Pty Ltd (ABN 77 084 670 600) * @copyright 1994-1997 Squiz Pty Ltd (ABN 77 084 670 600) -* @copyright 2024 Squiz Pty Ltd (ABN 77 084 670 600) +* @copyright 2025 Squiz Pty Ltd (ABN 77 084 670 600) * @license http://www.php.net/license/3_0.txt * @summary An unknown summary tag * diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/FileCommentUnitTest.1.js.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/FileCommentUnitTest.1.js.fixed index c7f54ffdf..44ff449ac 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/FileCommentUnitTest.1.js.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/FileCommentUnitTest.1.js.fixed @@ -25,7 +25,7 @@ * @author * @copyright 1997 Squiz Pty Ltd (ABN 77 084 670 600) * @copyright 1994-1997 Squiz Pty Ltd (ABN 77 084 670 600) -* @copyright 2024 Squiz Pty Ltd (ABN 77 084 670 600) +* @copyright 2025 Squiz Pty Ltd (ABN 77 084 670 600) * @license http://www.php.net/license/3_0.txt * @summary An unknown summary tag * diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/FunctionCommentThrowTagUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/FunctionCommentThrowTagUnitTest.inc index 7e94bb265..25da5021d 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/FunctionCommentThrowTagUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/FunctionCommentThrowTagUnitTest.inc @@ -509,3 +509,25 @@ namespace { } } } + +$anon = new class { + /** + * Tag and token number mismatch. + * + * @throws PHP_Exception1 + * @throws PHP_Exception2 + */ + #[AnAttribute] + #[AnotherAttribute] + public function JumpOverAttributesToFindDocblock() { + throw new PHP_Exception1('Error'); + } +}; + + +/** + * @throws Wrong_Exception + */ +public function ImproveCommentTolerance() { + throw /*comment*/ new /*comment*/ Right_Exception('Error'); +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/FunctionCommentThrowTagUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/FunctionCommentThrowTagUnitTest.php index 178b85a26..e34af8a7f 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/FunctionCommentThrowTagUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/FunctionCommentThrowTagUnitTest.php @@ -42,6 +42,8 @@ public function getErrorList() 219 => 1, 287 => 1, 397 => 1, + 519 => 1, + 530 => 1, ]; }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/FunctionCommentUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/FunctionCommentUnitTest.inc index 4fcbb6dbe..79060f4fe 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/FunctionCommentUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/FunctionCommentUnitTest.inc @@ -1158,3 +1158,12 @@ function paramVariation3($hasTypeNoComment): void {} * @return void */ function paramVariation4($hasTypehasComment): void {} + +/** + * @param (Foo&Bar)|null $a Comment. + * @return void + */ +public function setTranslator($a): void +{ + $this->translator = $translator; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/FunctionCommentUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/FunctionCommentUnitTest.inc.fixed index 817630b5b..76fa862ab 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/FunctionCommentUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/FunctionCommentUnitTest.inc.fixed @@ -1158,3 +1158,12 @@ function paramVariation3($hasTypeNoComment): void {} * @return void */ function paramVariation4($hasTypehasComment): void {} + +/** + * @param (Foo&Bar)|null $a Comment. + * @return void + */ +public function setTranslator($a): void +{ + $this->translator = $translator; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/InlineCommentUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/InlineCommentUnitTest.inc index 024876842..220b916e4 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/InlineCommentUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/InlineCommentUnitTest.inc @@ -186,6 +186,9 @@ readonly class MyClass readonly $property = 10; } +#️⃣ Apparently the emoji keycap number sign (hash) also works and turns this into a comment. +echo 'hello!'; + /* * N.B.: The below test line must be the last test in the file. * Testing that a new line after an inline comment when it's the last non-whitespace diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/InlineCommentUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/InlineCommentUnitTest.inc.fixed index 949a9ff94..2cc700c6b 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/InlineCommentUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/InlineCommentUnitTest.inc.fixed @@ -179,6 +179,9 @@ readonly class MyClass readonly $property = 10; } +// ️⃣ Apparently the emoji keycap number sign (hash) also works and turns this into a comment. +echo 'hello!'; + /* * N.B.: The below test line must be the last test in the file. * Testing that a new line after an inline comment when it's the last non-whitespace diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/InlineCommentUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/InlineCommentUnitTest.php index c559c5ae6..a2bbc4eb6 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/InlineCommentUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/InlineCommentUnitTest.php @@ -52,6 +52,7 @@ public function getErrorList($testFile='') 126 => 2, 130 => 2, 149 => 1, + 189 => 1, ]; return $errors; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/PostStatementCommentUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/PostStatementCommentUnitTest.inc index b83469613..3374c4760 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/PostStatementCommentUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/PostStatementCommentUnitTest.inc @@ -52,3 +52,13 @@ $match = match($foo // comment ) { 1 => 1, // comment }; + +// Issue #560: Annotations should be reported separately and be non-auto-fixable as their meaning may change when moved. +$a = 1; //@codeCoverageIgnore +$b = 2; // @phpstan-ignore variable.undefined +$c = 3; // @phpstan-ignore variable.undefined +$d = 4; // @tabInsteadOfSpace + +// Comments that include `@`, but are not recognized as annotations by this sniff. +$a = 1; // @ = add tag. +$b = 2; // Some comment. // @username diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/PostStatementCommentUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/PostStatementCommentUnitTest.inc.fixed index 21a4bbe03..bd6b171b0 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/PostStatementCommentUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/PostStatementCommentUnitTest.inc.fixed @@ -57,3 +57,15 @@ $match = match($foo // comment 1 => 1, // comment }; + +// Issue #560: Annotations should be reported separately and be non-auto-fixable as their meaning may change when moved. +$a = 1; //@codeCoverageIgnore +$b = 2; // @phpstan-ignore variable.undefined +$c = 3; // @phpstan-ignore variable.undefined +$d = 4; // @tabInsteadOfSpace + +// Comments that include `@`, but are not recognized as annotations by this sniff. +$a = 1; +// @ = add tag. +$b = 2; +// Some comment. // @username diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/PostStatementCommentUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/PostStatementCommentUnitTest.php index b9751f614..ba3b1c722 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/PostStatementCommentUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/PostStatementCommentUnitTest.php @@ -40,6 +40,12 @@ public function getErrorList($testFile='') 18 => 1, 35 => 1, 53 => 1, + 57 => 1, + 58 => 1, + 59 => 1, + 60 => 1, + 63 => 1, + 64 => 1, ]; case 'PostStatementCommentUnitTest.1.js': diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/VariableCommentUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/VariableCommentUnitTest.inc index 54ef5d2d3..bddb2d178 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/VariableCommentUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/VariableCommentUnitTest.inc @@ -454,3 +454,35 @@ class MoreMissingButSupportedTypes */ private namespace\SomeClass $variableName; } + +class DNFTypes +{ + /** + * @var mixed + */ + private (\Iterator&namespace\Countable)|false|null $variableName; +} + +class PHP84FinalProperties { + /** + * @var integer + */ + final int $hasDocblock; +} + +class AsymVisibility { + /** + * @var integer + */ + public(set) int $hasDocblockA; + + /** + * @var integer + */ + public protected(set) int $hasDocblockB; + + /** + * @var integer + */ + private(set) protected int $hasDocblockC; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/VariableCommentUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/VariableCommentUnitTest.inc.fixed index a292b6de1..2a40e3a07 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/VariableCommentUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Commenting/VariableCommentUnitTest.inc.fixed @@ -454,3 +454,35 @@ class MoreMissingButSupportedTypes */ private namespace\SomeClass $variableName; } + +class DNFTypes +{ + /** + * @var mixed + */ + private (\Iterator&namespace\Countable)|false|null $variableName; +} + +class PHP84FinalProperties { + /** + * @var integer + */ + final int $hasDocblock; +} + +class AsymVisibility { + /** + * @var integer + */ + public(set) int $hasDocblockA; + + /** + * @var integer + */ + public protected(set) int $hasDocblockB; + + /** + * @var integer + */ + private(set) protected int $hasDocblockC; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ControlSignatureUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ControlSignatureUnitTest.1.inc similarity index 97% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ControlSignatureUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ControlSignatureUnitTest.1.inc index 6496f7fb3..de0235cdd 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ControlSignatureUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ControlSignatureUnitTest.1.inc @@ -318,7 +318,3 @@ endif; // Reset property. // phpcs:set Squiz.ControlStructures.ControlSignature requiredSpacesBeforeColon 1 - -// Intentional parse error. This should be the last test in the file. -foreach - // Some unrelated comment. diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ControlSignatureUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ControlSignatureUnitTest.1.inc.fixed similarity index 97% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ControlSignatureUnitTest.inc.fixed rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ControlSignatureUnitTest.1.inc.fixed index c8834a3dd..03e6bf2c6 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ControlSignatureUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ControlSignatureUnitTest.1.inc.fixed @@ -322,7 +322,3 @@ endif; // Reset property. // phpcs:set Squiz.ControlStructures.ControlSignature requiredSpacesBeforeColon 1 - -// Intentional parse error. This should be the last test in the file. -foreach - // Some unrelated comment. diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ControlSignatureUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ControlSignatureUnitTest.2.inc new file mode 100644 index 000000000..ef99b1a22 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ControlSignatureUnitTest.2.inc @@ -0,0 +1,5 @@ + 1, ]; - if ($testFile === 'ControlSignatureUnitTest.inc') { + switch ($testFile) { + case 'ControlSignatureUnitTest.1.inc': $errors[122] = 1; $errors[130] = 2; $errors[134] = 1; @@ -84,9 +85,14 @@ public function getErrorList($testFile='') $errors[306] = 3; $errors[309] = 1; $errors[315] = 1; - }//end if + return $errors; - return $errors; + case 'ControlSignatureUnitTest.js': + return $errors; + + default: + return []; + }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.1.inc similarity index 95% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.1.inc index 5022e74c9..d10bd9800 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.1.inc @@ -111,7 +111,7 @@ for ( // phpcs:set Squiz.ControlStructures.ForLoopDeclaration requiredSpacesAfterOpen 0 // phpcs:set Squiz.ControlStructures.ForLoopDeclaration requiredSpacesBeforeClose 0 -// Test with semi-colon not belonging to for. +// Test with semicolon not belonging to for. for ($i = function() { return $this->i ; }; $i < function() { return $this->max; }; $i++) {} for ($i = function() { return $this->i; }; $i < function() { return $this->max; } ; $i++) {} @@ -124,6 +124,3 @@ for ( // body here } // phpcs:set Squiz.ControlStructures.ForLoopDeclaration ignoreNewlines false - -// This test has to be the last one in the file! Intentional parse error check. -for diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.1.inc.fixed similarity index 95% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.inc.fixed rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.1.inc.fixed index 6a1e7634b..85214c03e 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.1.inc.fixed @@ -77,7 +77,7 @@ for ( $i = 0; $i < 10; $i++ ) {} // phpcs:set Squiz.ControlStructures.ForLoopDeclaration requiredSpacesAfterOpen 0 // phpcs:set Squiz.ControlStructures.ForLoopDeclaration requiredSpacesBeforeClose 0 -// Test with semi-colon not belonging to for. +// Test with semicolon not belonging to for. for ($i = function() { return $this->i ; }; $i < function() { return $this->max; }; $i++) {} for ($i = function() { return $this->i; }; $i < function() { return $this->max; }; $i++) {} @@ -90,6 +90,3 @@ for ( // body here } // phpcs:set Squiz.ControlStructures.ForLoopDeclaration ignoreNewlines false - -// This test has to be the last one in the file! Intentional parse error check. -for diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.js b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.1.js similarity index 95% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.js rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.1.js index cfda6c12f..94e1f7484 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.js +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.1.js @@ -117,9 +117,6 @@ for ( // phpcs:set Squiz.ControlStructures.ForLoopDeclaration requiredSpacesAfterOpen 0 // phpcs:set Squiz.ControlStructures.ForLoopDeclaration requiredSpacesBeforeClose 0 -// Test with semi-colon not belonging to for. +// Test with semicolon not belonging to for. for (i = function() {self.widgetLoaded(widget.id) ; }; i < function() {self.widgetLoaded(widget.id);}; i++) {} for (i = function() {self.widgetLoaded(widget.id);}; i < function() {self.widgetLoaded(widget.id);} ; i++) {} - -// This test has to be the last one in the file! Intentional parse error check. -for diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.js.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.1.js.fixed similarity index 95% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.js.fixed rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.1.js.fixed index 00ced6437..fbf9b6098 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.js.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.1.js.fixed @@ -83,9 +83,6 @@ for ( i = 0; i < 10; i++ ) {} // phpcs:set Squiz.ControlStructures.ForLoopDeclaration requiredSpacesAfterOpen 0 // phpcs:set Squiz.ControlStructures.ForLoopDeclaration requiredSpacesBeforeClose 0 -// Test with semi-colon not belonging to for. +// Test with semicolon not belonging to for. for (i = function() {self.widgetLoaded(widget.id) ; }; i < function() {self.widgetLoaded(widget.id);}; i++) {} for (i = function() {self.widgetLoaded(widget.id);}; i < function() {self.widgetLoaded(widget.id);}; i++) {} - -// This test has to be the last one in the file! Intentional parse error check. -for diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.2.inc new file mode 100644 index 000000000..a327ccedd --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/ForLoopDeclarationUnitTest.2.inc @@ -0,0 +1,6 @@ + 2, 11 => 2, @@ -67,7 +67,7 @@ public function getErrorList($testFile='') 116 => 2, ]; - case 'ForLoopDeclarationUnitTest.js': + case 'ForLoopDeclarationUnitTest.1.js': return [ 6 => 2, 9 => 2, @@ -121,11 +121,12 @@ public function getErrorList($testFile='') public function getWarningList($testFile='') { switch ($testFile) { - case 'ForLoopDeclarationUnitTest.inc': - return [129 => 1]; + case 'ForLoopDeclarationUnitTest.2.inc': + case 'ForLoopDeclarationUnitTest.3.inc': + return [6 => 1]; - case 'ForLoopDeclarationUnitTest.js': - return [125 => 1]; + case 'ForLoopDeclarationUnitTest.2.js': + return [2 => 1]; default: return []; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/SwitchDeclarationUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/SwitchDeclarationUnitTest.inc index cf397607b..8f48451f0 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/SwitchDeclarationUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/SwitchDeclarationUnitTest.inc @@ -331,3 +331,16 @@ $foo = $foo ? } } : null; + +// Fix: goto should be recognized as terminating statement. +switch ( $a ) { + case 1: + doSomething(); + goto jumpOut; + default: + $other = $code; + goto jumpOut; +} + +jumpOut: +doSomething(); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/SwitchDeclarationUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/SwitchDeclarationUnitTest.inc.fixed index fd8ad1e68..5e44a7a92 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/SwitchDeclarationUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/SwitchDeclarationUnitTest.inc.fixed @@ -340,3 +340,17 @@ $foo = $foo ? } } : null; + +// Fix: goto should be recognized as terminating statement. +switch ( $a ) { + case 1: + doSomething(); + goto jumpOut; + + default: + $other = $code; + goto jumpOut; +} + +jumpOut: +doSomething(); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/SwitchDeclarationUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/SwitchDeclarationUnitTest.php index a7f0e3afa..310024dce 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/SwitchDeclarationUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/ControlStructures/SwitchDeclarationUnitTest.php @@ -80,6 +80,8 @@ public function getErrorList($testFile='') 327 => 1, 329 => 1, 330 => 1, + 339 => 2, + 342 => 1, ]; case 'SwitchDeclarationUnitTest.js': diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Formatting/OperatorBracketUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Formatting/OperatorBracketUnitTest.1.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Formatting/OperatorBracketUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Formatting/OperatorBracketUnitTest.1.inc diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Formatting/OperatorBracketUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Formatting/OperatorBracketUnitTest.1.inc.fixed similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Formatting/OperatorBracketUnitTest.inc.fixed rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Formatting/OperatorBracketUnitTest.1.inc.fixed diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Formatting/OperatorBracketUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Formatting/OperatorBracketUnitTest.2.inc new file mode 100644 index 000000000..1284f121f --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Formatting/OperatorBracketUnitTest.2.inc @@ -0,0 +1,7 @@ + 1, 6 => 1, diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationArgumentSpacingUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationArgumentSpacingUnitTest.1.inc similarity index 55% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationArgumentSpacingUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationArgumentSpacingUnitTest.1.inc index 33564e2e0..af872e73d 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationArgumentSpacingUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationArgumentSpacingUnitTest.1.inc @@ -100,7 +100,7 @@ function functionName( ?string $arg1 = 'foo' , ?int & $arg2 , $arg3 ) {} function functionName(string $arg1, ... $arg2) {} function functionName(string $arg1, int ... $arg2) {} function functionName(string $arg1, & ... $arg2) {} - +function functionName(string $arg1,int $arg2) {} $a = function ($var1, $var2=false) use ( $longVar1, & $longerVar1, @@ -109,3 +109,119 @@ $a = function ($var1, $var2=false) use ( ) {}; fn ($a,$b = null) => $a($b); + +function multipleWhitespaceTokensAfterType(int + + $number) {} + +function spacingBetweenParenthesesShouldBeFixedInOneGo( + + + ) {} + +function newlineAfterReferenceShouldBeFlaggedAndFixed( + & + + $param +) {} + +function newlineAfterReferenceFixerRespectsComment( + & + // comment + $param +) {} + +function newlineAfterVariadicShouldBeFlaggedAndFixed( + ... + + $param +) {} + +function newlineAfterVariadicFixerRespectsComment( + ... + //comment + $param +) {} + +function newlineBeforeAndAfterEqualsSignShouldBeFixedForSpacing0( + $param + + = + + true +) {} + +function commentBeforeOrAfterEqualsSignShouldBeFlaggedNotFixed( + $param /*comment*/ = /*comment*/ true +) {} + +function newlineAndCommentBeforeAndAfterEqualsSignShouldBeFlaggedNotFixed( + $param + + //comment + + = + + //comment + + true +) {} + +// phpcs:set Squiz.Functions.FunctionDeclarationArgumentSpacing equalsSpacing 1 +function newlineBeforeAndAfterEqualsSignShouldBeFixedForSpacing1( + $param + + = + + true +) {} +// phpcs:set Squiz.Functions.FunctionDeclarationArgumentSpacing equalsSpacing 0 + +function newlineBeforeCommaShouldBeFixedInOneGo( + $paramA +, + $paramB + + , + $paramC +) {} + +function newlineBeforeCommaFixerRespectsComments( + $paramA // comment + , + $paramB=10 /* comment */ +, + $paramC=20 # comment + , $paramC=30 + , string $paramC='foo' +) {} + +class PropertyPromotionSpacingAfterComma { + public function __construct(private string|int $propA, protected bool $correctSpace, public MyClass $tooMuchSpace,readonly string $noSpace) {} +} + +class PropertyPromotionSpacingAfterModifier { + public function __construct( + private$noSpace, + public MyClass $tooMuchSpace, + protected readonly string $tooMuchSpaceX2, + readonly + public + string $tooMuchSpaceNewLines, + ) {} +} + +class AsymVisibilityPropertyPromotionSpacingAfterComma { + public function __construct(private(set) string|int $propA, protected(set) bool $correctSpace, public(set) MyClass $tooMuchSpace,public(set) string $noSpace) {} +} + +class AsymVisibilityPropertyPromotionSpacingAfterModifier { + public function __construct( + private(set)$noSpace, + public(set) MyClass $tooMuchSpace, + protected(set) public string $tooMuchSpaceX2, + private + public(set) + string $tooMuchSpaceNewLines, + ) {} +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationArgumentSpacingUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationArgumentSpacingUnitTest.1.inc.fixed similarity index 56% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationArgumentSpacingUnitTest.inc.fixed rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationArgumentSpacingUnitTest.1.inc.fixed index 68fb1c1c3..356b37421 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationArgumentSpacingUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationArgumentSpacingUnitTest.1.inc.fixed @@ -100,7 +100,7 @@ function functionName(?string $arg1='foo', ?int &$arg2, $arg3) {} function functionName(string $arg1, ...$arg2) {} function functionName(string $arg1, int ...$arg2) {} function functionName(string $arg1, &...$arg2) {} - +function functionName(string $arg1, int $arg2) {} $a = function ($var1, $var2=false) use ( $longVar1, &$longerVar1, @@ -109,3 +109,91 @@ $a = function ($var1, $var2=false) use ( ) {}; fn ($a, $b=null) => $a($b); + +function multipleWhitespaceTokensAfterType(int $number) {} + +function spacingBetweenParenthesesShouldBeFixedInOneGo() {} + +function newlineAfterReferenceShouldBeFlaggedAndFixed( + &$param +) {} + +function newlineAfterReferenceFixerRespectsComment( + &// comment + $param +) {} + +function newlineAfterVariadicShouldBeFlaggedAndFixed( + ...$param +) {} + +function newlineAfterVariadicFixerRespectsComment( + ...//comment + $param +) {} + +function newlineBeforeAndAfterEqualsSignShouldBeFixedForSpacing0( + $param=true +) {} + +function commentBeforeOrAfterEqualsSignShouldBeFlaggedNotFixed( + $param /*comment*/ = /*comment*/ true +) {} + +function newlineAndCommentBeforeAndAfterEqualsSignShouldBeFlaggedNotFixed( + $param + + //comment + + = + + //comment + + true +) {} + +// phpcs:set Squiz.Functions.FunctionDeclarationArgumentSpacing equalsSpacing 1 +function newlineBeforeAndAfterEqualsSignShouldBeFixedForSpacing1( + $param = true +) {} +// phpcs:set Squiz.Functions.FunctionDeclarationArgumentSpacing equalsSpacing 0 + +function newlineBeforeCommaShouldBeFixedInOneGo( + $paramA, + $paramB, + $paramC +) {} + +function newlineBeforeCommaFixerRespectsComments( + $paramA, // comment + $paramB=10, /* comment */ + $paramC=20, # comment + $paramC=30, + string $paramC='foo' +) {} + +class PropertyPromotionSpacingAfterComma { + public function __construct(private string|int $propA, protected bool $correctSpace, public MyClass $tooMuchSpace, readonly string $noSpace) {} +} + +class PropertyPromotionSpacingAfterModifier { + public function __construct( + private $noSpace, + public MyClass $tooMuchSpace, + protected readonly string $tooMuchSpaceX2, + readonly public string $tooMuchSpaceNewLines, + ) {} +} + +class AsymVisibilityPropertyPromotionSpacingAfterComma { + public function __construct(private(set) string|int $propA, protected(set) bool $correctSpace, public(set) MyClass $tooMuchSpace, public(set) string $noSpace) {} +} + +class AsymVisibilityPropertyPromotionSpacingAfterModifier { + public function __construct( + private(set) $noSpace, + public(set) MyClass $tooMuchSpace, + protected(set) public string $tooMuchSpaceX2, + private public(set) string $tooMuchSpaceNewLines, + ) {} +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationArgumentSpacingUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationArgumentSpacingUnitTest.2.inc new file mode 100644 index 000000000..1b572336b --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationArgumentSpacingUnitTest.2.inc @@ -0,0 +1,6 @@ + */ - public function getErrorList() + public function getErrorList($testFile='') { - return [ - 3 => 1, - 5 => 2, - 7 => 2, - 8 => 2, - 9 => 2, - 11 => 2, - 13 => 7, - 14 => 2, - 15 => 2, - 16 => 4, - 18 => 2, - 35 => 2, - 36 => 2, - 44 => 2, - 45 => 1, - 46 => 1, - 51 => 2, - 53 => 2, - 55 => 1, - 56 => 1, - 58 => 1, - 73 => 7, - 76 => 1, - 77 => 1, - 81 => 1, - 89 => 2, - 92 => 1, - 93 => 1, - 94 => 1, - 95 => 1, - 99 => 11, - 100 => 2, - 101 => 2, - 102 => 2, - 106 => 1, - 107 => 2, - 111 => 3, - ]; + switch ($testFile) { + case 'FunctionDeclarationArgumentSpacingUnitTest.1.inc': + return [ + 3 => 1, + 5 => 2, + 7 => 2, + 8 => 2, + 9 => 2, + 11 => 2, + 13 => 7, + 14 => 2, + 15 => 2, + 16 => 4, + 18 => 2, + 35 => 2, + 36 => 2, + 44 => 2, + 45 => 1, + 46 => 1, + 51 => 2, + 53 => 2, + 55 => 1, + 56 => 1, + 58 => 1, + 73 => 7, + 76 => 1, + 77 => 1, + 81 => 1, + 89 => 2, + 92 => 1, + 93 => 1, + 94 => 1, + 95 => 1, + 99 => 11, + 100 => 2, + 101 => 2, + 102 => 2, + 103 => 1, + 106 => 1, + 107 => 2, + 111 => 3, + 113 => 1, + 117 => 1, + 123 => 1, + 129 => 1, + 135 => 1, + 141 => 1, + 149 => 2, + 155 => 2, + 163 => 2, + 174 => 2, + 182 => 1, + 185 => 1, + 191 => 1, + 193 => 1, + 195 => 1, + 196 => 1, + 200 => 2, + 205 => 1, + 206 => 1, + 207 => 2, + 208 => 1, + 209 => 1, + 215 => 2, + 220 => 1, + 221 => 1, + 222 => 2, + 223 => 1, + 224 => 1, + ]; + + default: + return []; + }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationUnitTest.1.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationUnitTest.1.inc diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationUnitTest.2.inc new file mode 100644 index 000000000..51a55e92a --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/FunctionDeclarationUnitTest.2.inc @@ -0,0 +1,5 @@ + */ - public function getErrorList() + public function getErrorList($testFile='') { - return [ - 55 => 1, - 68 => 1, - ]; + switch ($testFile) { + case 'FunctionDeclarationUnitTest.1.inc': + return [ + 55 => 1, + 68 => 1, + ]; + + default: + return []; + }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/MultiLineFunctionDeclarationUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/MultiLineFunctionDeclarationUnitTest.inc index 811c56ec1..e9f019eb5 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/MultiLineFunctionDeclarationUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/MultiLineFunctionDeclarationUnitTest.inc @@ -302,3 +302,55 @@ new ExceptionMessage(), ) { } } + +// Issue #608 - multi-attributes are not handled correctly. +function ParamWithMultiAttributeOnSameLine( + #[AttributeA, AttributeB] string $param, +) { +} + +function ParamWithMultiAttributeOnSameLineWithParamsShouldNotBeSeenAsMultipleFnParams( + #[AttributeA(10, 'test'), AttributeB([1, 2, 3,])] string $param, +) { +} + +function ParamWithMultiAttributeOnSameLine( + #[AttributeA, AttributeB] string $paramA, int $paramB +) { +} + +function ParamWithMultiAttributeOnSameLineWithParamsShouldNotBeSeenAsMultipleFnParams( + #[AttributeA(10, 'test'), AttributeB([1, 2, 3,])] string $param, int $paramB +) { +} + +function ParamWithAttributeOnOwnLineShouldNotBeSeenAsMultipleFnParams( + #[Attribute] + string $param, +) { +} + +function ParamWithMultipleAttributesOnOwnLineShouldNotBeSeenAsMultipleFnParams( + #[AttributeA] + #[AttributeB] + string $param, +) { +} + +function ParamWithAttributeOnOwnLineWithParamsShouldNotBeSeenAsMultipleFnParamse( + #[Attribute(10, 20)] + string $param, +) { +} + +function ParamWithMultiAttributeOnOwnLineShouldNotBeSeenAsMultipleFnParams( + #[AttributeA, AttributeB] + string $param, +) { +} + +function ParamWithMultiAttributeOnOwnLineWithParamsShouldNotBeSeenAsMultipleFnParams( + #[AttributeA(10, 'test'), AttributeB([1, 2, 3,])] + string $param, +) { +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/MultiLineFunctionDeclarationUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/MultiLineFunctionDeclarationUnitTest.inc.fixed index c38e3ecc0..bb6acd6aa 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/MultiLineFunctionDeclarationUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/MultiLineFunctionDeclarationUnitTest.inc.fixed @@ -314,3 +314,57 @@ new ExceptionMessage(), ) { } } + +// Issue #608 - multi-attributes are not handled correctly. +function ParamWithMultiAttributeOnSameLine( + #[AttributeA, AttributeB] string $param, +) { +} + +function ParamWithMultiAttributeOnSameLineWithParamsShouldNotBeSeenAsMultipleFnParams( + #[AttributeA(10, 'test'), AttributeB([1, 2, 3,])] string $param, +) { +} + +function ParamWithMultiAttributeOnSameLine( + #[AttributeA, AttributeB] string $paramA, + int $paramB +) { +} + +function ParamWithMultiAttributeOnSameLineWithParamsShouldNotBeSeenAsMultipleFnParams( + #[AttributeA(10, 'test'), AttributeB([1, 2, 3,])] string $param, + int $paramB +) { +} + +function ParamWithAttributeOnOwnLineShouldNotBeSeenAsMultipleFnParams( + #[Attribute] + string $param, +) { +} + +function ParamWithMultipleAttributesOnOwnLineShouldNotBeSeenAsMultipleFnParams( + #[AttributeA] + #[AttributeB] + string $param, +) { +} + +function ParamWithAttributeOnOwnLineWithParamsShouldNotBeSeenAsMultipleFnParamse( + #[Attribute(10, 20)] + string $param, +) { +} + +function ParamWithMultiAttributeOnOwnLineShouldNotBeSeenAsMultipleFnParams( + #[AttributeA, AttributeB] + string $param, +) { +} + +function ParamWithMultiAttributeOnOwnLineWithParamsShouldNotBeSeenAsMultipleFnParams( + #[AttributeA(10, 'test'), AttributeB([1, 2, 3,])] + string $param, +) { +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/MultiLineFunctionDeclarationUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/MultiLineFunctionDeclarationUnitTest.php index 30490345d..cc1dc35ed 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/MultiLineFunctionDeclarationUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Functions/MultiLineFunctionDeclarationUnitTest.php @@ -75,6 +75,8 @@ public function getErrorList($testFile='') 252 => 1, 253 => 1, 254 => 1, + 318 => 1, + 323 => 1, ]; } else { $errors = [ diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/NamingConventions/ValidVariableNameUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/NamingConventions/ValidVariableNameUnitTest.inc index 87c3bdf2e..361cc91bf 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/NamingConventions/ValidVariableNameUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/NamingConventions/ValidVariableNameUnitTest.inc @@ -155,3 +155,17 @@ enum SomeEnum $bar_foo = 3; } } + +class AsymVisibility { + // The read scope is public, but not specified. Enforce the naming conventions anyway. + private(set) $asymPublicImplied = 'hello'; + private(set) $_asymPublicImplied = 'hello'; + + // The read scope is private, so these properties should be handled as private properties. + private private(set) $asymPrivate = 'hello'; + private(set) private $_asymPrivate = 'hello'; + + // The read scope is public/protected, so these properties should be handled as public properties. + public private(set) $asymPublicPrivate = 'hello'; + private(set) protected $_asymPrivateProtected = 'hello'; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/NamingConventions/ValidVariableNameUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/NamingConventions/ValidVariableNameUnitTest.php index d8d8695c6..96ae98a0a 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/NamingConventions/ValidVariableNameUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/NamingConventions/ValidVariableNameUnitTest.php @@ -68,6 +68,9 @@ public function getErrorList() 146 => 1, 152 => 1, 155 => 1, + 162 => 1, + 165 => 1, + 170 => 1, ]; return $errors; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Objects/ObjectInstantiationUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Objects/ObjectInstantiationUnitTest.inc index 725c60ed6..b6df38c9d 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Objects/ObjectInstantiationUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Objects/ObjectInstantiationUnitTest.inc @@ -47,7 +47,3 @@ $a = $b !== null default => 5, } : new Foo; - -// Intentional parse error. This must be the last test in the file. -function new -?> diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/DisallowMultipleAssignmentsUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/DisallowMultipleAssignmentsUnitTest.1.inc similarity index 69% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/DisallowMultipleAssignmentsUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/DisallowMultipleAssignmentsUnitTest.1.inc index f657fb4a4..960f907de 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/DisallowMultipleAssignmentsUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/DisallowMultipleAssignmentsUnitTest.1.inc @@ -108,3 +108,43 @@ function () { $b = getB(); }; +?> + + +// Issue PHPCSStandards/PHP_CodeSniffer#537. + + + + + + + + + + + + +field = $result; +$filtered_results->$field = $result; +$filtered_results->$row->field = $result; +$filtered_results->$row->$field = $result; + +$filtered_results[ $i ]->field = $result; +$filtered_results[ $i ]->$field = $result; +$filtered_results[ $i ]->$row->field = $result; +$filtered_results[ $i ]->$row->$field = $result; +$filtered_results[ $i ]->$row[0]->field = $result; +$filtered_results[ $i ]->$row[$j]->$field = $result; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/DisallowMultipleAssignmentsUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/DisallowMultipleAssignmentsUnitTest.2.inc new file mode 100644 index 000000000..3befd507a --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/DisallowMultipleAssignmentsUnitTest.2.inc @@ -0,0 +1,7 @@ + */ - public function getErrorList() + public function getErrorList($testFile='') { - return [ - 4 => 1, - 5 => 2, - 7 => 1, - 9 => 1, - 12 => 1, - 14 => 1, - 15 => 1, - 79 => 1, - 85 => 1, - ]; + switch ($testFile) { + case 'DisallowMultipleAssignmentsUnitTest.1.inc': + return [ + 4 => 1, + 5 => 2, + 7 => 1, + 9 => 1, + 12 => 1, + 14 => 1, + 15 => 1, + 79 => 1, + 85 => 1, + ]; + + default: + return []; + } }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.1.inc index f28c55989..b4f481d4e 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.1.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/PHP/EmbeddedPhpUnitTest.1.inc @@ -265,6 +265,31 @@ echo 'the PHP tag is correctly indented as an indent less than the previous code echo 'the PHP tag is incorrectly indented as the indent is more than 4 different from the indent of the previous code'; ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1, 175 => 1, 176 => 2, - 178 => 1, + 178 => 2, 179 => 1, 180 => 2, 181 => 1, @@ -100,6 +100,11 @@ public function getErrorList($testFile='') 258 => 1, 263 => 1, 264 => 1, + 270 => 1, + 272 => 1, + 276 => 1, + 279 => 2, + 282 => 2, ]; case 'EmbeddedPhpUnitTest.2.inc': @@ -147,7 +152,7 @@ public function getErrorList($testFile='') 105 => 1, 111 => 1, 112 => 2, - 114 => 1, + 114 => 2, 115 => 1, 116 => 2, 117 => 1, @@ -187,9 +192,30 @@ public function getErrorList($testFile='') case 'EmbeddedPhpUnitTest.22.inc': return [ 14 => 1, - 22 => 2, + 22 => 1, ]; + case 'EmbeddedPhpUnitTest.24.inc': + $shortOpenTagDirective = (bool) ini_get('short_open_tag'); + if ($shortOpenTagDirective === true) { + return [ + 18 => 1, + 20 => 1, + ]; + } + return []; + + case 'EmbeddedPhpUnitTest.25.inc': + if (PHP_VERSION_ID >= 70300) { + return [ + 12 => 2, + 14 => 2, + ]; + } + + // PHP 7.2 or lower: PHP version which doesn't support flexible heredocs/nowdocs yet. + return []; + default: return []; }//end switch diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MemberVarScopeUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MemberVarScopeUnitTest.inc index 6df12cca4..163b65eec 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MemberVarScopeUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MemberVarScopeUnitTest.inc @@ -70,3 +70,18 @@ class MyClass { interface Base { protected $anonymous; } + +class PHP84FinalProperties { + final int $final; +} + +class AsymVisibility { + // The read scope is public, but not specified. Error should use different error code. + public(set) $asymPublic = 'hello'; + protected(set) $asymProtected = 'hello'; + private(set) $asymPrivate = 'hello'; + + public public(set) $asymPublicPublic = 'hello'; + protected(set) public $asymPublicProtected = 'hello'; + protected private(set) $asymProtectedPrivate = 'hello'; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MemberVarScopeUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MemberVarScopeUnitTest.php index e17f9ae7b..1d83126a2 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MemberVarScopeUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/Scope/MemberVarScopeUnitTest.php @@ -39,6 +39,10 @@ public function getErrorList() 41 => 1, 66 => 2, 67 => 1, + 75 => 1, + 80 => 1, + 81 => 1, + 82 => 1, ]; }//end getErrorList() @@ -54,6 +58,7 @@ public function getErrorList() */ public function getWarningList() { + // Warning from getMemberProperties() about parse error. return [71 => 1]; }//end getWarningList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.inc index e831e257d..8c8daf1f4 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.inc @@ -37,3 +37,54 @@ function foo() } + +// Nested functions - okay. +function hasNestedOkay() { + function nestedFunction() { + echo 'hello'; + } + +} + +$cl = function() { + function nestedFunction() { + echo 'hello'; + } + +}; + +mycallback( + 'name', + function() { + echo 'hello'; + } + +); + +// Nested functions - not okay. +function hasNestedNotOkay() { + function nestedFunction() {} + +} + +$cl = function() { + function nestedFunction() { + echo 'hello'; } + +}; + +mycallback('name', function() { + echo 'hello'; + + + + } + +); + +mycallback('name', function() { + // Comment + + } + +); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.inc.fixed index c567dbb2d..1166366f4 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.inc.fixed @@ -43,3 +43,52 @@ function foo() }//end for } + +// Nested functions - okay. +function hasNestedOkay() { + function nestedFunction() { + echo 'hello'; + } + +} + +$cl = function() { + function nestedFunction() { + echo 'hello'; + } + +}; + +mycallback( + 'name', + function() { + echo 'hello'; + } + +); + +// Nested functions - not okay. +function hasNestedNotOkay() { + function nestedFunction() { +} + +} + +$cl = function() { + function nestedFunction() { + echo 'hello'; +} + +}; + +mycallback('name', function() { + echo 'hello'; + } + +); + +mycallback('name', function() { + // Comment + } + +); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.php index cb5cf061d..7361cf499 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionClosingBraceSpaceUnitTest.php @@ -41,6 +41,10 @@ public function getErrorList($testFile='') 29 => 1, 31 => 1, 39 => 1, + 66 => 1, + 72 => 1, + 81 => 1, + 88 => 1, ]; case 'FunctionClosingBraceSpaceUnitTest.js': diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.1.inc index b03a0ed82..83600e873 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.1.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.1.inc @@ -582,3 +582,171 @@ echo 'this line belongs with the #3904 test'; function Foo() {} function bar($name){} echo 'this line belongs with the #3904 test'; + + +/** + * foo. + */ +function a() { +}/** + * foo. + */ +function b() { +} + + +// phpcs:set Squiz.WhiteSpace.FunctionSpacing spacingBeforeFirst 1 +// phpcs:set Squiz.WhiteSpace.FunctionSpacing spacingAfterLast 0 + +class DocblockFollowedByAttributesCorrectSpacing { + + /** + * No error. + */ + #[AttributesShouldBeJumpedOver] + #[ + ASecondAttributeShouldBeJumpedOverToo + ]#[AndAThirdAsWell] + function FirstFunction() + { + // Code + } +} + +class DocblockFollowedByAttributesTooMuchSpacing { + + + + /** + * Docblock. + */ + #[AttributesShouldBeJumpedOver] + #[ + ASecondAttributeShouldBeJumpedOverToo + ]#[AndAThirdAsWell] + function FirstFunction() + { + // Code + } +} + +class DocblockFollowedByAttributesTooLittleSpacing { + /** + * Docblock. + */ + #[AttributesShouldBeJumpedOver] + #[ + ASecondAttributeShouldBeJumpedOverToo + ]#[AndAThirdAsWell] + function FirstFunction() + { + // Code + } +} + +class DocblockPrecededByAttributesCorrectSpacing { + + #[AttributesShouldBeJumpedOver] + #[ + ASecondAttributeShouldBeJumpedOverToo + ]#[AndAThirdAsWell] + /** + * No error. + */ + function FirstFunction() + { + // Code + } +} + +class DocblockPrecededByAttributesTooMuchSpacing { + + + #[AttributesShouldBeJumpedOver] + #[ + ASecondAttributeShouldBeJumpedOverToo + ]#[AndAThirdAsWell] + /** + * Docblock. + */ + function FirstFunction() + { + // Code + } +} + +class DocblockPrecededByAttributesTooLittleSpacing { + #[AttributesShouldBeJumpedOver] + #[ + ASecondAttributeShouldBeJumpedOverToo + ]#[AndAThirdAsWell] + /** + * Docblock. + */ + function FirstFunction() + { + // Code + } +} + +// Reset properties to their default value. +// phpcs:set Squiz.WhiteSpace.FunctionSpacing spacingBeforeFirst 2 +// phpcs:set Squiz.WhiteSpace.FunctionSpacing spacingAfterLast 2 + +class SilenceBeforeErrorIfPreviousThingWasAFunctionBug +{ + /** + * Docblock. + */ + + #[ReturnTypeWillChange] + + + + + + #[ + + AnotherAttribute + + ]#[AndAThirdAsWell] + + public function blankLineDetectionA() + { + + }//end blankLineDetectionA() + + /** + * Docblock. + */ + #[ReturnTypeWillChange] + + public function blankLineDetectionB() + { + + }//end blankLineDetectionB() +}//end class + +// Issue #945. +class OnlyAcceptFirstDocblockAsBelongingWithFunction { + /** + * Superfluous docblock + */ + + + /** + * Function docblock + */ + function correctSpacing($x) {} + + + /** + * Superfluous docblock + */ + /** + * Function docblock + */ + function incorrectSpacing($x) {} + + +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.1.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.1.inc.fixed index 443824ca1..91444e7ca 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.1.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.1.inc.fixed @@ -671,3 +671,180 @@ function Foo() {} function bar($name){} echo 'this line belongs with the #3904 test'; + + +/** + * foo. + */ +function a() { +} + + +/** + * foo. + */ +function b() { +} + + +// phpcs:set Squiz.WhiteSpace.FunctionSpacing spacingBeforeFirst 1 +// phpcs:set Squiz.WhiteSpace.FunctionSpacing spacingAfterLast 0 + +class DocblockFollowedByAttributesCorrectSpacing { + + /** + * No error. + */ + #[AttributesShouldBeJumpedOver] + #[ + ASecondAttributeShouldBeJumpedOverToo + ]#[AndAThirdAsWell] + function FirstFunction() + { + // Code + } +} + +class DocblockFollowedByAttributesTooMuchSpacing { + + /** + * Docblock. + */ + #[AttributesShouldBeJumpedOver] + #[ + ASecondAttributeShouldBeJumpedOverToo + ]#[AndAThirdAsWell] + function FirstFunction() + { + // Code + } +} + +class DocblockFollowedByAttributesTooLittleSpacing { + + /** + * Docblock. + */ + #[AttributesShouldBeJumpedOver] + #[ + ASecondAttributeShouldBeJumpedOverToo + ]#[AndAThirdAsWell] + function FirstFunction() + { + // Code + } +} + +class DocblockPrecededByAttributesCorrectSpacing { + + #[AttributesShouldBeJumpedOver] + #[ + ASecondAttributeShouldBeJumpedOverToo + ]#[AndAThirdAsWell] + /** + * No error. + */ + function FirstFunction() + { + // Code + } +} + +class DocblockPrecededByAttributesTooMuchSpacing { + + #[AttributesShouldBeJumpedOver] + #[ + ASecondAttributeShouldBeJumpedOverToo + ]#[AndAThirdAsWell] + /** + * Docblock. + */ + function FirstFunction() + { + // Code + } +} + +class DocblockPrecededByAttributesTooLittleSpacing { + + #[AttributesShouldBeJumpedOver] + #[ + ASecondAttributeShouldBeJumpedOverToo + ]#[AndAThirdAsWell] + /** + * Docblock. + */ + function FirstFunction() + { + // Code + } +} + +// Reset properties to their default value. +// phpcs:set Squiz.WhiteSpace.FunctionSpacing spacingBeforeFirst 2 +// phpcs:set Squiz.WhiteSpace.FunctionSpacing spacingAfterLast 2 + +class SilenceBeforeErrorIfPreviousThingWasAFunctionBug +{ + + + /** + * Docblock. + */ + + #[ReturnTypeWillChange] + + + + + + #[ + + AnotherAttribute + + ]#[AndAThirdAsWell] + + public function blankLineDetectionA() + { + + }//end blankLineDetectionA() + + + /** + * Docblock. + */ + #[ReturnTypeWillChange] + + public function blankLineDetectionB() + { + + }//end blankLineDetectionB() + + +}//end class + +// Issue #945. +class OnlyAcceptFirstDocblockAsBelongingWithFunction { + /** + * Superfluous docblock + */ + + + /** + * Function docblock + */ + function correctSpacing($x) {} + + + /** + * Superfluous docblock + */ + + + /** + * Function docblock + */ + function incorrectSpacing($x) {} + + +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.php index cc6d96d25..a963a9a4b 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/FunctionSpacingUnitTest.php @@ -101,7 +101,16 @@ public function getErrorList($testFile='') 560 => 1, 566 => 1, 580 => 2, - 583 => 3, + 583 => 4, + 591 => 1, + 627 => 1, + 641 => 1, + 672 => 1, + 686 => 1, + 714 => 1, + 717 => 1, + 727 => 1, + 749 => 1, ]; case 'FunctionSpacingUnitTest.2.inc': diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.1.inc similarity index 77% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.inc.fixed rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.1.inc index d683eaadf..75d576d29 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.1.inc @@ -1,9 +1,9 @@ 'a', 'b' => 'b' ), @@ -259,9 +270,9 @@ class ClassUsingSimpleTraits { use HelloWorld; + /* comment */ public $firstVar = array( 'a', 'b' ); - protected $secondVar = true; } @@ -272,8 +283,11 @@ class ClassUsingComplexTraits A::bigTalk insteadof B; } + + public $firstVar = array( 'a', 'b' ); + /* comment */ protected $secondVar = true; } @@ -311,7 +325,6 @@ class CommentedOutCodeAtStartOfClass { class CommentedOutCodeAtStartOfClassNoBlankLine { // phpcs:disable Stnd.Cat.Sniff -- For reasons. - /** * Description. * @@ -322,21 +335,24 @@ class CommentedOutCodeAtStartOfClassNoBlankLine { class HasAttributes { - /** * Short description of the member variable. * * @var array */ + #[ORM\Id]#[ORM\Column("integer")] + private $id; + /** * Short description of the member variable. * * @var array */ #[ORM\GeneratedValue] + #[ORM\Column(ORM\Column::T_INTEGER)] protected $height; @@ -346,7 +362,6 @@ class HasAttributes #[FirstAttribute] #[SecondAttribute] protected $propertyDouble; - #[ThirdAttribute] protected $propertyWithoutSpacing; } @@ -357,3 +372,90 @@ enum SomeEnum case ONE = 'one'; } + +class SupportReadonlyProperties { + readonly int $readonlyA; + public readonly string $publicReadonly; + readonly bool $readonlyB; + readonly private bool $readonlyPrivate; +} + +class NoPreambleMultilineDeclaration { + public + static + int $prop = 1; +} + +class MultipleBlankLinesInPreAmble { + + /** + * Docblock. + */ + + #[MyAttribute] + + + #[ + + BlankLinesWithinAnAttributeShouldBeLeftAlone + + ] + + public $prop; +} + +final class BlankLinesBetweenVsAttributesWithoutCommentIssueSquiz3594 +{ + + // PHPCS can fix blank lines for the first property, but not for the second. (fixed now) + #[SingleAttribute] + + public $property1; + #[SingleAttribute] + + public $property2; +} + +class PHP84FinalProperties { + final int $finalA; + + /** + * Docblock + */ + public final string $publicfinal; + #[AnAttribute] + final bool $finalB; + + final private bool $finalPrivate; +} + +class MultilineCommentShouldNotBeSplitUp { + // This is the first line + // of a multi-line comment + // which should be recognized as belonging + // with the property. + public $prop; + + + /* This is the first line + of a multi-line comment + which should be recognized as belonging + with the property. + */ + public $prop; +} + +class AsymVisibility { + protected private(set) int $asymProtectedPrivate; + + /** + * Docblock + */ + protected(set) final string $asymProtected; + #[AnAttribute] + + public(set) string|bool $asymPublic; + + + private(set) private bool $asymPrivate; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.1.inc.fixed similarity index 77% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.1.inc.fixed index 12b55176c..d87c8b74a 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.1.inc.fixed @@ -1,8 +1,8 @@ 'a', 'b' => 'b' ), @@ -270,9 +259,9 @@ class ClassUsingSimpleTraits { use HelloWorld; - /* comment */ public $firstVar = array( 'a', 'b' ); + protected $secondVar = true; } @@ -283,11 +272,8 @@ class ClassUsingComplexTraits A::bigTalk insteadof B; } - - public $firstVar = array( 'a', 'b' ); - /* comment */ protected $secondVar = true; } @@ -325,6 +311,7 @@ class CommentedOutCodeAtStartOfClass { class CommentedOutCodeAtStartOfClassNoBlankLine { // phpcs:disable Stnd.Cat.Sniff -- For reasons. + /** * Description. * @@ -335,24 +322,21 @@ class CommentedOutCodeAtStartOfClassNoBlankLine { class HasAttributes { + /** * Short description of the member variable. * * @var array */ - #[ORM\Id]#[ORM\Column("integer")] - private $id; - /** * Short description of the member variable. * * @var array */ #[ORM\GeneratedValue] - #[ORM\Column(ORM\Column::T_INTEGER)] protected $height; @@ -362,6 +346,7 @@ class HasAttributes #[FirstAttribute] #[SecondAttribute] protected $propertyDouble; + #[ThirdAttribute] protected $propertyWithoutSpacing; } @@ -372,3 +357,92 @@ enum SomeEnum case ONE = 'one'; } + +class SupportReadonlyProperties { + + readonly int $readonlyA; + + public readonly string $publicReadonly; + + readonly bool $readonlyB; + + readonly private bool $readonlyPrivate; +} + +class NoPreambleMultilineDeclaration { + + public + static + int $prop = 1; +} + +class MultipleBlankLinesInPreAmble { + + /** + * Docblock. + */ + #[MyAttribute] + #[ + + BlankLinesWithinAnAttributeShouldBeLeftAlone + + ] + public $prop; +} + +final class BlankLinesBetweenVsAttributesWithoutCommentIssueSquiz3594 +{ + + // PHPCS can fix blank lines for the first property, but not for the second. (fixed now) + #[SingleAttribute] + public $property1; + + #[SingleAttribute] + public $property2; +} + +class PHP84FinalProperties { + + final int $finalA; + + /** + * Docblock + */ + public final string $publicfinal; + + #[AnAttribute] + final bool $finalB; + + final private bool $finalPrivate; +} + +class MultilineCommentShouldNotBeSplitUp { + + // This is the first line + // of a multi-line comment + // which should be recognized as belonging + // with the property. + public $prop; + + /* This is the first line + of a multi-line comment + which should be recognized as belonging + with the property. + */ + public $prop; +} + +class AsymVisibility { + + protected private(set) int $asymProtectedPrivate; + + /** + * Docblock + */ + protected(set) final string $asymProtected; + + #[AnAttribute] + public(set) string|bool $asymPublic; + + private(set) private bool $asymPrivate; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.2.inc new file mode 100644 index 000000000..2aab7c059 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/MemberVarSpacingUnitTest.2.inc @@ -0,0 +1,10 @@ + */ - public function getErrorList() + public function getErrorList($testFile='') { - return [ - 4 => 1, - 7 => 1, - 20 => 1, - 30 => 1, - 35 => 1, - 44 => 1, - 50 => 1, - 73 => 1, - 86 => 1, - 106 => 1, - 115 => 1, - 150 => 1, - 160 => 1, - 165 => 1, - 177 => 1, - 186 => 1, - 200 => 1, - 209 => 1, - 211 => 1, - 224 => 1, - 229 => 1, - 241 => 1, - 246 => 1, - 252 => 1, - 254 => 1, - 261 => 1, - 275 => 1, - 276 => 1, - 288 => 1, - 292 => 1, - 333 => 1, - 342 => 1, - 346 => 1, - 353 => 1, - 357 => 1, - 366 => 1, - ]; + switch ($testFile) { + case 'MemberVarSpacingUnitTest.1.inc': + return [ + 4 => 1, + 7 => 1, + 20 => 1, + 30 => 1, + 35 => 1, + 44 => 1, + 50 => 1, + 73 => 1, + 86 => 1, + 107 => 1, + 115 => 1, + 151 => 1, + 160 => 1, + 165 => 1, + 177 => 1, + 186 => 1, + 200 => 1, + 209 => 1, + 211 => 1, + 224 => 1, + 229 => 1, + 241 => 1, + 246 => 1, + 252 => 1, + 254 => 1, + 261 => 1, + 275 => 1, + 276 => 1, + 288 => 1, + 292 => 1, + 333 => 1, + 343 => 1, + 345 => 1, + 346 => 1, + 355 => 1, + 357 => 1, + 366 => 1, + 377 => 1, + 378 => 1, + 379 => 1, + 380 => 1, + 384 => 1, + 394 => 1, + 396 => 1, + 403 => 1, + 412 => 1, + 415 => 1, + 416 => 1, + 420 => 1, + 427 => 1, + 437 => 1, + 445 => 1, + 449 => 1, + 456 => 1, + 457 => 1, + 460 => 1, + ]; + + default: + return []; + }//end switch }//end getErrorList() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc similarity index 91% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc index 765e7ab71..29acf308a 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc @@ -483,5 +483,28 @@ match ($a) { default => -3, }; -/* Intentional parse error. This has to be the last test in the file. */ -$a = 10 + +$foo = $var + ? 10 + : true; + +// Safeguard that a non-fixable error is thrown when there is a new line before the operator, +// but the last non-whitespace token before the operator is a comment token. +$foo = $var // Comment + ? false /* Comment */ + : true; + +$foo = $var // phpcs: ignore Stnd.Cat.Sniff -- for reasons. + + + ? $something /** + * Don't ask, but someone might have a docblock between the lines. It's valid PHP after all. + */ + + + : true; + +// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreNewlines true +$foo = $var // Comment + ? false // Comment + : true; +// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreNewlines false diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc.fixed similarity index 91% rename from app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc.fixed rename to app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc.fixed index ada77fa85..5c94e3658 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc.fixed @@ -477,5 +477,26 @@ match ($a) { default => -3, }; -/* Intentional parse error. This has to be the last test in the file. */ -$a = 10 + +$foo = $var ? 10 : true; + +// Safeguard that a non-fixable error is thrown when there is a new line before the operator, +// but the last non-whitespace token before the operator is a comment token. +$foo = $var // Comment + ? false /* Comment */ + : true; + +$foo = $var // phpcs: ignore Stnd.Cat.Sniff -- for reasons. + + + ? $something /** + * Don't ask, but someone might have a docblock between the lines. It's valid PHP after all. + */ + + + : true; + +// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreNewlines true +$foo = $var // Comment + ? false // Comment + : true; +// phpcs:set Squiz.WhiteSpace.OperatorSpacing ignoreNewlines false diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.2.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.2.inc new file mode 100644 index 000000000..3a0dbac3e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.2.inc @@ -0,0 +1,3 @@ + 1, 5 => 2, @@ -104,6 +104,12 @@ public function getErrorList($testFile='') 265 => 2, 266 => 2, 271 => 2, + 487 => 1, + 488 => 1, + 493 => 1, + 494 => 1, + 499 => 1, + 504 => 1, ]; case 'OperatorSpacingUnitTest.js': diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.1.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.1.inc index 49eaa2b63..e53511f8f 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.1.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.1.inc @@ -77,27 +77,27 @@ class MyOtherClass $varQ = 'string', $varR = 123; - // Intentionally missing a semi-colon for testing. public $varS, - $varT -} + $varT, + $varU; -// Issue #3188 - static as return type. -public static function fCreate($attributes = []): static -{ - return static::factory()->create($attributes); -} + // Issue #3188 - static as return type. + public static function staticAsReturnType($attributes = []): static + { + return static::factory()->create($attributes); + } -public static function fCreate($attributes = []): ?static -{ - return static::factory()->create($attributes); -} + public static function nullableStaticReturnType($attributes = []): ?static + { + return static::factory()->create($attributes); + } -// Also account for static used within union types. -public function staticLast($attributes = []): object|static {} -public function staticMiddle(): string|static|object {} -public function staticFirst(): static|object {} + // Also account for static used within union types. + public function staticLast($attributes = []): object|static {} + public function staticMiddle(): string|static|object {} + public function staticFirst(): static|object {} +} // Ensure that static as a scope keyword when preceeded by a colon which is not for a type declaration is still handled. $callback = $cond ? get_fn_name() : static function ($a) { return $a * 10; }; @@ -147,3 +147,58 @@ readonly class ReadonlyClassTest {} // PHP 8.3 readonly anonymous classes. $anon = new readonly class {}; $anon = new readonly class {}; + +class FinalTest { + final public static function create(ContainerInterface $container) {} +} + +final class FinalTest2 { +} + +final + readonly class FinalTest3 {} + +class FinalTest4 { + final const X = "foo"; + final public const Y = "bar"; +} + +abstract class AbstractTest { + abstract public function foo(); +} + +final class FinalSpacingCorrect { + public final const SPACING_CORRECT = true; +} + +abstract class AbstractSpacingCorrect { + public abstract function spacingCorrect() {} +} + +$closure = static function() { return 'spacing correct'; }; +$closure = static function() { return 'spacing incorrect'; }; + +class ConstantVisibility { + public const PUBLIC_SPACING_CORRECT = true; + protected const PROTECTED_SPACING_CORRECT = true; + private const PRIVATE_SPACING_CORRECT = true; + + public const PUBLIC_SPACING_INCORRECT = true; + protected const PROTECTED_SPACING_INCORRECT = true; + private const PRIVATE_SPACING_INCORRECT = true; +} + +class FinalProperties { + final readonly public ?MyType $spacing_correct; + protected final $spacing_incorrect = 'foo'; +} + +class AsymVisibility { + public(set) string $asymPublic = 'hello'; + public protected(set) final $asymProtected = 'hello'; + private(set) public string|false $asymPrivate = 'hello'; + + public public(set) $asymPublicPublic = 'hello'; + protected(set) public $asymPublicProtected = 'hello'; + protected private(set) $asymProtectedPrivate = 'hello'; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.1.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.1.inc.fixed index 4c116c76a..8376b5604 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.1.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.1.inc.fixed @@ -72,27 +72,27 @@ class MyOtherClass $varQ = 'string', $varR = 123; - // Intentionally missing a semi-colon for testing. public $varS, - $varT -} + $varT, + $varU; -// Issue #3188 - static as return type. -public static function fCreate($attributes = []): static -{ - return static::factory()->create($attributes); -} + // Issue #3188 - static as return type. + public static function staticAsReturnType($attributes = []): static + { + return static::factory()->create($attributes); + } -public static function fCreate($attributes = []): ?static -{ - return static::factory()->create($attributes); -} + public static function nullableStaticReturnType($attributes = []): ?static + { + return static::factory()->create($attributes); + } -// Also account for static used within union types. -public function staticLast($attributes = []): object|static {} -public function staticMiddle(): string|static|object {} -public function staticFirst(): static|object {} + // Also account for static used within union types. + public function staticLast($attributes = []): object|static {} + public function staticMiddle(): string|static|object {} + public function staticFirst(): static|object {} +} // Ensure that static as a scope keyword when preceeded by a colon which is not for a type declaration is still handled. $callback = $cond ? get_fn_name() : static function ($a) { return $a * 10; }; @@ -141,3 +141,57 @@ readonly class ReadonlyClassTest {} // PHP 8.3 readonly anonymous classes. $anon = new readonly class {}; $anon = new readonly class {}; + +class FinalTest { + final public static function create(ContainerInterface $container) {} +} + +final class FinalTest2 { +} + +final readonly class FinalTest3 {} + +class FinalTest4 { + final const X = "foo"; + final public const Y = "bar"; +} + +abstract class AbstractTest { + abstract public function foo(); +} + +final class FinalSpacingCorrect { + public final const SPACING_CORRECT = true; +} + +abstract class AbstractSpacingCorrect { + public abstract function spacingCorrect() {} +} + +$closure = static function() { return 'spacing correct'; }; +$closure = static function() { return 'spacing incorrect'; }; + +class ConstantVisibility { + public const PUBLIC_SPACING_CORRECT = true; + protected const PROTECTED_SPACING_CORRECT = true; + private const PRIVATE_SPACING_CORRECT = true; + + public const PUBLIC_SPACING_INCORRECT = true; + protected const PROTECTED_SPACING_INCORRECT = true; + private const PRIVATE_SPACING_INCORRECT = true; +} + +class FinalProperties { + final readonly public ?MyType $spacing_correct; + protected final $spacing_incorrect = 'foo'; +} + +class AsymVisibility { + public(set) string $asymPublic = 'hello'; + public protected(set) final $asymProtected = 'hello'; + private(set) public string|false $asymPrivate = 'hello'; + + public public(set) $asymPublicPublic = 'hello'; + protected(set) public $asymPublicProtected = 'hello'; + protected private(set) $asymProtectedPrivate = 'hello'; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.4.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.4.inc new file mode 100644 index 000000000..045943354 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/ScopeKeywordSpacingUnitTest.4.inc @@ -0,0 +1,11 @@ + 3, 145 => 1, 149 => 1, + 152 => 1, + 155 => 1, + 158 => 1, + 162 => 1, + 163 => 1, + 166 => 1, + 167 => 1, + 179 => 1, + 186 => 1, + 187 => 1, + 188 => 1, + 193 => 2, + 197 => 1, + 198 => 3, + 199 => 2, ]; case 'ScopeKeywordSpacingUnitTest.3.inc': diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SemicolonSpacingUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SemicolonSpacingUnitTest.inc index 393f48454..60f87e5bc 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SemicolonSpacingUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SemicolonSpacingUnitTest.inc @@ -18,14 +18,14 @@ $sum = $a /* + $b + $c */ ; /* - * Test that the sniff does *not* throw incorrect errors for semi-colons in + * Test that the sniff does *not* throw incorrect errors for semicolons in * "empty" parts of a `for` control structure. */ for ($i = 1; ; $i++) {} for ( ; $ptr >= 0; $ptr-- ) {} for ( ; ; ) {} -// But it should when the semi-colon in a `for` follows a comment (but shouldn't move the semi-colon). +// But it should when the semicolon in a `for` follows a comment (but shouldn't move the semicolon). for ( /* Deliberately left empty. */ ; $ptr >= 0; $ptr-- ) {} for ( $i = 1 ; /* Deliberately left empty. */ ; $i++ ) {} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SemicolonSpacingUnitTest.inc.fixed b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SemicolonSpacingUnitTest.inc.fixed index 0d06324de..b4dc0f13e 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SemicolonSpacingUnitTest.inc.fixed +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/Tests/WhiteSpace/SemicolonSpacingUnitTest.inc.fixed @@ -18,14 +18,14 @@ $sum = $a; /* + $b + $c */ /* - * Test that the sniff does *not* throw incorrect errors for semi-colons in + * Test that the sniff does *not* throw incorrect errors for semicolons in * "empty" parts of a `for` control structure. */ for ($i = 1; ; $i++) {} for ( ; $ptr >= 0; $ptr-- ) {} for ( ; ; ) {} -// But it should when the semi-colon in a `for` follows a comment (but shouldn't move the semi-colon). +// But it should when the semicolon in a `for` follows a comment (but shouldn't move the semicolon). for ( /* Deliberately left empty. */; $ptr >= 0; $ptr-- ) {} for ( $i = 1; /* Deliberately left empty. */; $i++ ) {} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/ruleset.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/ruleset.xml index 87ab4c3e8..82f5270ad 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/ruleset.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Squiz/ruleset.xml @@ -74,8 +74,14 @@ - - + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Docs/Files/ClosingTagStandard.xml b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Docs/Files/ClosingTagStandard.xml index aa60b8ab9..f1dca3c67 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Docs/Files/ClosingTagStandard.xml +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Docs/Files/ClosingTagStandard.xml @@ -1,7 +1,7 @@ @@ -11,7 +11,7 @@ $var = 1; ]]> - + numTokens + 1); + return $phpcsFile->numTokens; } $fileName = $phpcsFile->getFilename(); @@ -69,7 +70,7 @@ public function process(File $phpcsFile, $stackPtr) // provide useful error reporting. if (is_numeric($exitCode) === true && $exitCode > 0) { if (is_array($output) === true) { - $msg = join('\n', $output); + $msg = implode('\n', $output); } throw new RuntimeException("Failed invoking ZendCodeAnalyzer, exitcode was [$exitCode], retval was [$retval], output was [$msg]"); @@ -92,9 +93,45 @@ public function process(File $phpcsFile, $stackPtr) } // Ignore the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; }//end process() + /** + * Provide the version number in which the sniff was deprecated. + * + * @return string + */ + public function getDeprecationVersion() + { + return 'v3.9.0'; + + }//end getDeprecationVersion() + + + /** + * Provide the version number in which the sniff will be removed. + * + * @return string + */ + public function getRemovalVersion() + { + return 'v4.0.0'; + + }//end getRemovalVersion() + + + /** + * Provide a custom message to display with the deprecation. + * + * @return string + */ + public function getDeprecationMessage() + { + return ''; + + }//end getDeprecationMessage() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/Files/ClosingTagSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/Files/ClosingTagSniff.php index 5ae72362d..7b547bfd8 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/Files/ClosingTagSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/Files/ClosingTagSniff.php @@ -9,8 +9,8 @@ namespace PHP_CodeSniffer\Standards\Zend\Sniffs\Files; -use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Tokens; class ClosingTagSniff implements Sniff @@ -71,7 +71,7 @@ public function process(File $phpcsFile, $stackPtr) }//end if // Ignore the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; }//end process() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php index 2dfeb39aa..41b194810 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Sniffs/NamingConventions/ValidVariableNameSniff.php @@ -9,9 +9,9 @@ namespace PHP_CodeSniffer\Standards\Zend\Sniffs\NamingConventions; +use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\AbstractVariableSniff; use PHP_CodeSniffer\Util\Common; -use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Util\Tokens; class ValidVariableNameSniff extends AbstractVariableSniff diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/NamingConventions/ValidVariableNameUnitTest.inc b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/NamingConventions/ValidVariableNameUnitTest.inc index 3325e1152..f3ea469de 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/NamingConventions/ValidVariableNameUnitTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/NamingConventions/ValidVariableNameUnitTest.inc @@ -129,3 +129,17 @@ enum SomeEnum $bar_foo = 3; } } + +class AsymVisibility { + // The read scope is public, but not specified. Enforce the naming conventions anyway. + private(set) $asymPublicImplied = 'hello'; + private(set) $_asymPublicImplied = 'hello'; + + // The read scope is private, so these properties should be handled as private properties. + private private(set) $asymPrivate = 'hello'; + private(set) private $_asymPrivate = 'hello'; + + // The read scope is public/protected, so these properties should be handled as public properties. + protected private(set) $asymProtectedPrivate = 'hello'; + private(set) public $_asymPrivatePublic = 'hello'; +} diff --git a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/NamingConventions/ValidVariableNameUnitTest.php b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/NamingConventions/ValidVariableNameUnitTest.php index 94316dad1..7e6202715 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/NamingConventions/ValidVariableNameUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Standards/Zend/Tests/NamingConventions/ValidVariableNameUnitTest.php @@ -61,6 +61,10 @@ public function getErrorList() 121 => 1, 126 => 1, 129 => 1, + 136 => 1, + 139 => 1, + 143 => 1, + 144 => 1, ]; }//end getErrorList() @@ -92,6 +96,7 @@ public function getWarningList() 79 => 1, 82 => 1, 94 => 1, + // Warning from getMemberProperties() about parse error. 107 => 1, ]; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/CSS.php b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/CSS.php index d3f71b379..36631ddc3 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/CSS.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/CSS.php @@ -22,7 +22,7 @@ class CSS extends PHP * * Pre-checks the content to see if it looks minified. * - * @param string $content The content to tokenize, + * @param string $content The content to tokenize. * @param \PHP_CodeSniffer\Config $config The config data for the run. * @param string $eolChar The EOL char used in the content. * diff --git a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/Comment.php b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/Comment.php index 9ca2ddf26..e779c84a2 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/Comment.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/Comment.php @@ -9,23 +9,20 @@ namespace PHP_CodeSniffer\Tokenizers; -use PHP_CodeSniffer\Util; +use PHP_CodeSniffer\Util\Common; class Comment { /** - * Creates an array of tokens when given some PHP code. + * Splits a single doc block comment token up into something that can be easily iterated over. * - * Starts by using token_get_all() but does a lot of extra processing - * to insert information about the context of the token. - * - * @param string $string The string to tokenize. + * @param string $string The doc block comment string to parse. * @param string $eolChar The EOL character to use for splitting strings. - * @param int $stackPtr The position of the first token in the file. + * @param int $stackPtr The position of the token in the "new"/final token stream. * - * @return array + * @return array>> */ public function tokenizeString($string, $eolChar, $stackPtr) { @@ -41,9 +38,16 @@ public function tokenizeString($string, $eolChar, $stackPtr) extra star when they are used for function and class comments. */ - $char = ($numChars - strlen(ltrim($string, '/*'))); - $openTag = substr($string, 0, $char); - $string = ltrim($string, '/*'); + $char = ($numChars - strlen(ltrim($string, '/*'))); + $lastChars = substr($string, -2); + if ($char === $numChars && $lastChars === '*/') { + // Edge case: docblock without whitespace or contents. + $openTag = substr($string, 0, -2); + $string = $lastChars; + } else { + $openTag = substr($string, 0, $char); + $string = ltrim($string, '/*'); + } $tokens[$stackPtr] = [ 'content' => $openTag, @@ -56,7 +60,7 @@ public function tokenizeString($string, $eolChar, $stackPtr) $stackPtr++; if (PHP_CODESNIFFER_VERBOSITY > 1) { - $content = Util\Common::prepareForOutput($openTag); + $content = Common::prepareForOutput($openTag); echo "\t\tCreate comment token: T_DOC_COMMENT_OPEN_TAG => $content".PHP_EOL; } @@ -74,6 +78,7 @@ public function tokenizeString($string, $eolChar, $stackPtr) ]; if ($closeTag['content'] === false) { + // In PHP < 8.0 substr() can return `false` instead of always returning a string. $closeTag['content'] = ''; } @@ -99,7 +104,7 @@ public function tokenizeString($string, $eolChar, $stackPtr) $tokens[$stackPtr] = $space; $stackPtr++; if (PHP_CODESNIFFER_VERBOSITY > 1) { - $content = Util\Common::prepareForOutput($space['content']); + $content = Common::prepareForOutput($space['content']); echo "\t\tCreate comment token: T_DOC_COMMENT_WHITESPACE => $content".PHP_EOL; } @@ -134,7 +139,7 @@ public function tokenizeString($string, $eolChar, $stackPtr) foreach ($lineTokens as $lineToken) { $tokens[$stackPtr] = $lineToken; if (PHP_CODESNIFFER_VERBOSITY > 1) { - $content = Util\Common::prepareForOutput($lineToken['content']); + $content = Common::prepareForOutput($lineToken['content']); $type = $lineToken['type']; echo "\t\tCreate comment token: $type => $content".PHP_EOL; } @@ -150,7 +155,7 @@ public function tokenizeString($string, $eolChar, $stackPtr) $tokens[$stackPtr] = $closeTag; $tokens[$openPtr]['comment_closer'] = $stackPtr; if (PHP_CODESNIFFER_VERBOSITY > 1) { - $content = Util\Common::prepareForOutput($closeTag['content']); + $content = Common::prepareForOutput($closeTag['content']); echo "\t\tCreate comment token: T_DOC_COMMENT_CLOSE_TAG => $content".PHP_EOL; } @@ -171,7 +176,7 @@ public function tokenizeString($string, $eolChar, $stackPtr) * @param int $start The position in the string to start processing. * @param int $end The position in the string to end processing. * - * @return array + * @return array> */ private function processLine($string, $eolChar, $start, $end) { @@ -246,7 +251,7 @@ private function processLine($string, $eolChar, $start, $end) * @param int $start The position in the string to start processing. * @param int $end The position in the string to end processing. * - * @return array|null + * @return array|null */ private function collectWhitespace($string, $start, $end) { @@ -263,14 +268,12 @@ private function collectWhitespace($string, $start, $end) return null; } - $token = [ + return [ 'content' => $space, 'code' => T_DOC_COMMENT_WHITESPACE, 'type' => 'T_DOC_COMMENT_WHITESPACE', ]; - return $token; - }//end collectWhitespace() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/JS.php b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/JS.php index cb7bd3c19..c7249fcd9 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/JS.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/JS.php @@ -251,7 +251,7 @@ class JS extends Tokenizer * * Pre-checks the content to see if it looks minified. * - * @param string $content The content to tokenize, + * @param string $content The content to tokenize. * @param \PHP_CodeSniffer\Config $config The config data for the run. * @param string $eolChar The EOL char used in the content. * @@ -1188,7 +1188,7 @@ public function processAdditional() } } } else if ($this->tokens[$i]['code'] === T_CLOSE_OBJECT) { - $opener = array_pop($classStack); + array_pop($classStack); } else if ($this->tokens[$i]['code'] === T_COLON) { // If it is a scope opener, it belongs to a // DEFAULT or CASE statement. diff --git a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/PHP.php b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/PHP.php index 4be5400a0..32877a0ef 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/PHP.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/PHP.php @@ -9,7 +9,8 @@ namespace PHP_CodeSniffer\Tokenizers; -use PHP_CodeSniffer\Util; +use PHP_CodeSniffer\Util\Common; +use PHP_CodeSniffer\Util\Tokens; class PHP extends Tokenizer { @@ -230,6 +231,7 @@ class PHP extends Tokenizer T_CONTINUE => T_CONTINUE, T_THROW => T_THROW, T_EXIT => T_EXIT, + T_GOTO => T_GOTO, ], 'strict' => true, 'shared' => true, @@ -250,6 +252,7 @@ class PHP extends Tokenizer T_CONTINUE => T_CONTINUE, T_THROW => T_THROW, T_EXIT => T_EXIT, + T_GOTO => T_GOTO, ], 'strict' => true, 'shared' => true, @@ -288,7 +291,7 @@ class PHP extends Tokenizer * from the scopeOpeners array. The data is duplicated here to * save time during parsing of the file. * - * @var array + * @var array */ public $endScopeTokens = [ T_CLOSE_CURLY_BRACKET => T_CLOSE_CURLY_BRACKET, @@ -400,8 +403,11 @@ class PHP extends Tokenizer T_PLUS_EQUAL => 2, T_PRINT => 5, T_PRIVATE => 7, + T_PRIVATE_SET => 12, T_PUBLIC => 6, + T_PUBLIC_SET => 11, T_PROTECTED => 9, + T_PROTECTED_SET => 14, T_READONLY => 8, T_REQUIRE => 7, T_REQUIRE_ONCE => 12, @@ -463,6 +469,8 @@ class PHP extends Tokenizer T_CLOSE_SHORT_ARRAY => 1, T_TYPE_UNION => 1, T_TYPE_INTERSECTION => 1, + T_TYPE_OPEN_PARENTHESIS => 1, + T_TYPE_CLOSE_PARENTHESIS => 1, ]; /** @@ -543,12 +551,12 @@ protected function tokenize($string) if (PHP_CODESNIFFER_VERBOSITY > 1) { if ($tokenIsArray === true) { - $type = Util\Tokens::tokenName($token[0]); - $content = Util\Common::prepareForOutput($token[1]); + $type = Tokens::tokenName($token[0]); + $content = Common::prepareForOutput($token[1]); } else { $newToken = self::resolveSimpleToken($token[0]); $type = $newToken['type']; - $content = Util\Common::prepareForOutput($token[0]); + $content = Common::prepareForOutput($token[0]); } echo "\tProcess token "; @@ -562,7 +570,7 @@ protected function tokenize($string) }//end if if ($newStackPtr > 0 - && isset(Util\Tokens::$emptyTokens[$finalTokens[($newStackPtr - 1)]['code']]) === false + && isset(Tokens::$emptyTokens[$finalTokens[($newStackPtr - 1)]['code']]) === false ) { $lastNotEmptyToken = ($newStackPtr - 1); } @@ -602,12 +610,33 @@ protected function tokenize($string) echo PHP_EOL; } + /* + Before PHP 5.5, the yield keyword was tokenized as + T_STRING. So look for and change this token in + earlier versions. + */ + + if (PHP_VERSION_ID < 50500 + && $tokenIsArray === true + && $token[0] === T_STRING + && strtolower($token[1]) === 'yield' + && isset($this->tstringContexts[$finalTokens[$lastNotEmptyToken]['code']]) === false + ) { + // Could still be a context sensitive keyword or "yield from" and potentially multi-line, + // so adjust the token stack in place. + $token[0] = T_YIELD; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t\t* token $stackPtr changed from T_STRING to T_YIELD".PHP_EOL; + } + } + /* Tokenize context sensitive keyword as string when it should be string. */ if ($tokenIsArray === true - && isset(Util\Tokens::$contextSensitiveKeywords[$token[0]]) === true + && isset(Tokens::$contextSensitiveKeywords[$token[0]]) === true && (isset($this->tstringContexts[$finalTokens[$lastNotEmptyToken]['code']]) === true || $finalTokens[$lastNotEmptyToken]['content'] === '&' || $insideConstDeclaration === true) @@ -629,7 +658,7 @@ protected function tokenize($string) ) { for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { if (is_array($tokens[$i]) === false - || isset(Util\Tokens::$emptyTokens[$tokens[$i][0]]) === false + || isset(Tokens::$emptyTokens[$tokens[$i][0]]) === false ) { break; } @@ -654,7 +683,7 @@ protected function tokenize($string) break; } - if (isset(Util\Tokens::$emptyTokens[$tokens[$i][0]]) === true) { + if (isset(Tokens::$emptyTokens[$tokens[$i][0]]) === true) { continue; } @@ -677,7 +706,7 @@ protected function tokenize($string) // Find the next non-empty token. for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { if (is_array($tokens[$i]) === true - && isset(Util\Tokens::$emptyTokens[$tokens[$i][0]]) === true + && isset(Tokens::$emptyTokens[$tokens[$i][0]]) === true ) { continue; } @@ -695,7 +724,7 @@ protected function tokenize($string) $preserveKeyword = true; for ($i = ($lastNotEmptyToken - 1); $i >= 0; $i--) { - if (isset(Util\Tokens::$emptyTokens[$finalTokens[$i]['code']]) === true) { + if (isset(Tokens::$emptyTokens[$finalTokens[$i]['code']]) === true) { continue; } @@ -709,7 +738,7 @@ protected function tokenize($string) if ($preserveKeyword === false) { if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = Util\Tokens::tokenName($token[0]); + $type = Tokens::tokenName($token[0]); echo "\t\t* token $stackPtr changed from $type to T_STRING".PHP_EOL; } @@ -734,7 +763,7 @@ protected function tokenize($string) } /* - Close an open "inside constant declaration" marker when no keyword convertion was needed. + Close an open "inside constant declaration" marker when no keyword conversion was needed. */ if ($insideConstDeclaration === true @@ -746,6 +775,9 @@ protected function tokenize($string) /* Special case for `static` used as a function name, i.e. `static()`. + + Note: this may incorrectly change the static keyword directly before a DNF property type. + If so, this will be caught and corrected for in the additional processing. */ if ($tokenIsArray === true @@ -754,7 +786,7 @@ protected function tokenize($string) ) { for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { if (is_array($tokens[$i]) === true - && isset(Util\Tokens::$emptyTokens[$tokens[$i][0]]) === true + && isset(Tokens::$emptyTokens[$tokens[$i][0]]) === true ) { continue; } @@ -774,13 +806,53 @@ protected function tokenize($string) } }//end if + /* + Prior to PHP 7.4, PHP didn't support stand-alone PHP open tags at the end of a file + (without a new line), so we need to make sure that the tokenization in PHPCS is consistent + cross-version PHP by retokenizing to T_OPEN_TAG. + */ + + if (PHP_VERSION_ID < 70400 + && $tokenIsArray === true + // PHP < 7.4 with short open tags off. + && (($stackPtr === ($numTokens - 1) + && $token[0] === T_INLINE_HTML + && stripos($token[1], ' T_OPEN_TAG, + 'type' => 'T_OPEN_TAG', + 'content' => $token[1], + ]; + } else { + $finalTokens[$newStackPtr] = [ + 'code' => T_OPEN_TAG, + 'type' => 'T_OPEN_TAG', + 'content' => $token[1].$tokens[($stackPtr + 1)][1], + ]; + + $stackPtr++; + } + + $newStackPtr++; + continue; + }//end if + /* Parse doc blocks into something that can be easily iterated over. */ if ($tokenIsArray === true && ($token[0] === T_DOC_COMMENT - || ($token[0] === T_COMMENT && strpos($token[1], '/**') === 0)) + || ($token[0] === T_COMMENT && strpos($token[1], '/**') === 0 && $token[1] !== '/**/')) ) { $commentTokens = $commentTokenizer->tokenizeString($token[1], $this->eolChar, $newStackPtr); foreach ($commentTokens as $commentToken) { @@ -1109,7 +1181,7 @@ protected function tokenize($string) // Get the next non-empty token. for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { if (is_array($tokens[$i]) === false - || isset(Util\Tokens::$emptyTokens[$tokens[$i][0]]) === false + || isset(Tokens::$emptyTokens[$tokens[$i][0]]) === false ) { break; } @@ -1196,6 +1268,49 @@ protected function tokenize($string) } }//end if + /* + Asymmetric visibility for PHP < 8.4 + */ + + if ($tokenIsArray === true + && in_array($token[0], [T_PUBLIC, T_PROTECTED, T_PRIVATE], true) === true + && ($stackPtr + 3) < $numTokens + && $tokens[($stackPtr + 1)] === '(' + && is_array($tokens[($stackPtr + 2)]) === true + && $tokens[($stackPtr + 2)][0] === T_STRING + && strtolower($tokens[($stackPtr + 2)][1]) === 'set' + && $tokens[($stackPtr + 3)] === ')' + ) { + $newToken = []; + if ($token[0] === T_PUBLIC) { + $oldCode = 'T_PUBLIC'; + $newToken['code'] = T_PUBLIC_SET; + $newToken['type'] = 'T_PUBLIC_SET'; + } else if ($token[0] === T_PROTECTED) { + $oldCode = 'T_PROTECTED'; + $newToken['code'] = T_PROTECTED_SET; + $newToken['type'] = 'T_PROTECTED_SET'; + } else { + $oldCode = 'T_PRIVATE'; + $newToken['code'] = T_PRIVATE_SET; + $newToken['type'] = 'T_PRIVATE_SET'; + } + + $newToken['content'] = $token[1].'('.$tokens[($stackPtr + 2)][1].')'; + $finalTokens[$newStackPtr] = $newToken; + $newStackPtr++; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $newCode = $newToken['type']; + echo "\t\t* tokens from $stackPtr changed from $oldCode to $newCode".PHP_EOL; + } + + // We processed an extra 3 tokens, for `(`, `set`, and `)`. + $stackPtr += 3; + + continue; + }//end if + /* As of PHP 8.0 fully qualified, partially qualified and namespace relative identifier names are tokenized differently. @@ -1263,8 +1378,8 @@ protected function tokenize($string) } if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = Util\Tokens::tokenName($token[0]); - $content = Util\Common::prepareForOutput($token[1]); + $type = Tokens::tokenName($token[0]); + $content = Common::prepareForOutput($token[1]); echo "\t\t* token $stackPtr split into individual tokens; was: $type => $content".PHP_EOL; } @@ -1327,7 +1442,7 @@ protected function tokenize($string) // Get the next non-empty token. for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { if (is_array($tokens[$i]) === false - || isset(Util\Tokens::$emptyTokens[$tokens[$i][0]]) === false + || isset(Tokens::$emptyTokens[$tokens[$i][0]]) === false ) { break; } @@ -1340,7 +1455,7 @@ protected function tokenize($string) // Get the previous non-empty token. for ($j = ($stackPtr - 1); $j > 0; $j--) { if (is_array($tokens[$j]) === false - || isset(Util\Tokens::$emptyTokens[$tokens[$j][0]]) === false + || isset(Tokens::$emptyTokens[$tokens[$j][0]]) === false ) { break; } @@ -1363,7 +1478,7 @@ protected function tokenize($string) $tokens[$stackPtr][0] = T_PARAM_NAME; if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = Util\Tokens::tokenName($token[0]); + $type = Tokens::tokenName($token[0]); echo "\t\t* token $stackPtr changed from $type to T_PARAM_NAME".PHP_EOL; } @@ -1384,7 +1499,7 @@ protected function tokenize($string) // Get the next non-whitespace token. for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { if (is_array($tokens[$i]) === false - || isset(Util\Tokens::$emptyTokens[$tokens[$i][0]]) === false + || isset(Tokens::$emptyTokens[$tokens[$i][0]]) === false ) { break; } @@ -1414,7 +1529,7 @@ protected function tokenize($string) $tokenType = $tokens[$i]; } - if (isset(Util\Tokens::$emptyTokens[$tokenType]) === true) { + if (isset(Tokens::$emptyTokens[$tokenType]) === true) { continue; } @@ -1467,6 +1582,12 @@ protected function tokenize($string) ]; $newStackPtr++; + // Also modify the original token stack so that + // future checks (like looking for T_NULLABLE) can + // detect the T_READONLY token more easily. + $tokens[$stackPtr][0] = T_READONLY; + $token[0] = T_READONLY; + if (PHP_CODESNIFFER_VERBOSITY > 1 && $type !== T_READONLY) { echo "\t\t* token $stackPtr changed from $type to T_READONLY".PHP_EOL; } @@ -1487,80 +1608,160 @@ protected function tokenize($string) }//end if /* - Before PHP 7.0, the "yield from" was tokenized as + Before PHP 7.0, "yield from" was tokenized as T_YIELD, T_WHITESPACE and T_STRING. So look for and change this token in earlier versions. */ if (PHP_VERSION_ID < 70000 - && PHP_VERSION_ID >= 50500 && $tokenIsArray === true && $token[0] === T_YIELD && isset($tokens[($stackPtr + 1)]) === true && isset($tokens[($stackPtr + 2)]) === true && $tokens[($stackPtr + 1)][0] === T_WHITESPACE + && strpos($tokens[($stackPtr + 1)][1], $this->eolChar) === false && $tokens[($stackPtr + 2)][0] === T_STRING && strtolower($tokens[($stackPtr + 2)][1]) === 'from' ) { - // Could be multi-line, so adjust the token stack. - $token[0] = T_YIELD_FROM; - $token[1] .= $tokens[($stackPtr + 1)][1].$tokens[($stackPtr + 2)][1]; + // Single-line "yield from" with only whitespace between. + $finalTokens[$newStackPtr] = [ + 'code' => T_YIELD_FROM, + 'type' => 'T_YIELD_FROM', + 'content' => $token[1].$tokens[($stackPtr + 1)][1].$tokens[($stackPtr + 2)][1], + ]; if (PHP_CODESNIFFER_VERBOSITY > 1) { for ($i = ($stackPtr + 1); $i <= ($stackPtr + 2); $i++) { - $type = Util\Tokens::tokenName($tokens[$i][0]); - $content = Util\Common::prepareForOutput($tokens[$i][1]); + $type = Tokens::tokenName($tokens[$i][0]); + $content = Common::prepareForOutput($tokens[$i][1]); echo "\t\t* token $i merged into T_YIELD_FROM; was: $type => $content".PHP_EOL; } } - $tokens[($stackPtr + 1)] = null; - $tokens[($stackPtr + 2)] = null; - } - - /* - Before PHP 5.5, the yield keyword was tokenized as - T_STRING. So look for and change this token in - earlier versions. - Checks also if it is just "yield" or "yield from". - */ + $newStackPtr++; + $stackPtr += 2; - if (PHP_VERSION_ID < 50500 + continue; + } else if (PHP_VERSION_ID < 80300 && $tokenIsArray === true && $token[0] === T_STRING - && strtolower($token[1]) === 'yield' - && isset($this->tstringContexts[$finalTokens[$lastNotEmptyToken]['code']]) === false + && strtolower($token[1]) === 'from' + && $finalTokens[$lastNotEmptyToken]['code'] === T_YIELD ) { - if (isset($tokens[($stackPtr + 1)]) === true - && isset($tokens[($stackPtr + 2)]) === true - && $tokens[($stackPtr + 1)][0] === T_WHITESPACE - && $tokens[($stackPtr + 2)][0] === T_STRING - && strtolower($tokens[($stackPtr + 2)][1]) === 'from' - ) { - // Could be multi-line, so just just the token stack. - $token[0] = T_YIELD_FROM; - $token[1] .= $tokens[($stackPtr + 1)][1].$tokens[($stackPtr + 2)][1]; + /* + Before PHP 8.3, if there was a comment between the "yield" and "from" keywords, + it was tokenized as T_YIELD, T_WHITESPACE, T_COMMENT... and T_STRING. + We want to keep the tokenization of the tokens between, but need to change the + `T_YIELD` and `T_STRING` (from) keywords to `T_YIELD_FROM. + */ - if (PHP_CODESNIFFER_VERBOSITY > 1) { - for ($i = ($stackPtr + 1); $i <= ($stackPtr + 2); $i++) { - $type = Util\Tokens::tokenName($tokens[$i][0]); - $content = Util\Common::prepareForOutput($tokens[$i][1]); - echo "\t\t* token $i merged into T_YIELD_FROM; was: $type => $content".PHP_EOL; + $finalTokens[$lastNotEmptyToken]['code'] = T_YIELD_FROM; + $finalTokens[$lastNotEmptyToken]['type'] = 'T_YIELD_FROM'; + + $finalTokens[$newStackPtr] = [ + 'code' => T_YIELD_FROM, + 'type' => 'T_YIELD_FROM', + 'content' => $token[1], + ]; + $newStackPtr++; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t\t* token $lastNotEmptyToken (new stack) changed into T_YIELD_FROM; was: T_YIELD".PHP_EOL; + echo "\t\t* token $stackPtr changed into T_YIELD_FROM; was: T_STRING".PHP_EOL; + } + + continue; + } else if (PHP_VERSION_ID >= 70000 + && $tokenIsArray === true + && $token[0] === T_YIELD_FROM + && strpos($token[1], $this->eolChar) !== false + && preg_match('`^yield\s+from$`i', $token[1]) === 1 + ) { + /* + In PHP 7.0+, a multi-line "yield from" (without comment) tokenizes as a single + T_YIELD_FROM token, but we want to split it and tokenize the whitespace + separately for consistency. + */ + + $finalTokens[$newStackPtr] = [ + 'code' => T_YIELD_FROM, + 'type' => 'T_YIELD_FROM', + 'content' => substr($token[1], 0, 5), + ]; + $newStackPtr++; + + $tokenLines = explode($this->eolChar, substr($token[1], 5, -4)); + $numLines = count($tokenLines); + $newToken = [ + 'type' => 'T_WHITESPACE', + 'code' => T_WHITESPACE, + 'content' => '', + ]; + + foreach ($tokenLines as $i => $line) { + $newToken['content'] = $line; + if ($i === ($numLines - 1)) { + if ($line === '') { + break; } + } else { + $newToken['content'] .= $this->eolChar; } - $tokens[($stackPtr + 1)] = null; - $tokens[($stackPtr + 2)] = null; - } else { - $newToken = []; - $newToken['code'] = T_YIELD; - $newToken['type'] = 'T_YIELD'; - $newToken['content'] = $token[1]; $finalTokens[$newStackPtr] = $newToken; - $newStackPtr++; - continue; - }//end if + } + + $finalTokens[$newStackPtr] = [ + 'code' => T_YIELD_FROM, + 'type' => 'T_YIELD_FROM', + 'content' => substr($token[1], -4), + ]; + $newStackPtr++; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t\t* token $stackPtr split into 'yield', one or more whitespace tokens and 'from'".PHP_EOL; + } + + continue; + } else if (PHP_VERSION_ID >= 80300 + && $tokenIsArray === true + && $token[0] === T_YIELD_FROM + && preg_match('`^yield[ \t]+from$`i', $token[1]) !== 1 + && stripos($token[1], 'yield') === 0 + ) { + /* + Since PHP 8.3, "yield from" allows for comments and will + swallow the comment in the `T_YIELD_FROM` token. + We need to split this up to allow for sniffs handling comments. + */ + + $finalTokens[$newStackPtr] = [ + 'code' => T_YIELD_FROM, + 'type' => 'T_YIELD_FROM', + 'content' => substr($token[1], 0, 5), + ]; + $newStackPtr++; + + $yieldFromSubtokens = @token_get_all(" T_YIELD_FROM, + 1 => substr($token[1], -4), + ]; + + // Inject the new tokens into the token stack. + array_splice($tokens, ($stackPtr + 1), 0, $yieldFromSubtokens); + $numTokens = count($tokens); + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + echo "\t\t* token $stackPtr split into parts (yield from with comment)".PHP_EOL; + } + + unset($yieldFromSubtokens); + continue; }//end if /* @@ -1783,7 +1984,7 @@ protected function tokenize($string) $newToken = []; $newToken['code'] = $newType; - $newToken['type'] = Util\Tokens::tokenName($newType); + $newToken['type'] = Tokens::tokenName($newType); $newToken['content'] = $newContent; $finalTokens[$newStackPtr] = $newToken; @@ -1807,7 +2008,7 @@ protected function tokenize($string) ) { $isMatch = false; for ($x = ($stackPtr + 1); $x < $numTokens; $x++) { - if (isset($tokens[$x][0], Util\Tokens::$emptyTokens[$tokens[$x][0]]) === true) { + if (isset($tokens[$x][0], Tokens::$emptyTokens[$tokens[$x][0]]) === true) { continue; } @@ -1872,7 +2073,7 @@ protected function tokenize($string) } if (is_array($tokens[$x]) === false - || isset(Util\Tokens::$emptyTokens[$tokens[$x][0]]) === false + || isset(Tokens::$emptyTokens[$tokens[$x][0]]) === false ) { // Non-empty, non-comma content. break; @@ -1945,7 +2146,7 @@ protected function tokenize($string) $tokenType = $tokens[$i]; } - if (isset(Util\Tokens::$emptyTokens[$tokenType]) === true) { + if (isset(Tokens::$emptyTokens[$tokenType]) === true) { continue; } @@ -2014,7 +2215,7 @@ protected function tokenize($string) } if ($prevNonEmpty === null - && isset(Util\Tokens::$emptyTokens[$tokenType]) === false + && isset(Tokens::$emptyTokens[$tokenType]) === false ) { // Found the previous non-empty token. if ($tokenType === ':' || $tokenType === ',' || $tokenType === T_ATTRIBUTE_END) { @@ -2033,8 +2234,10 @@ protected function tokenize($string) if ($tokenType === T_FUNCTION || $tokenType === T_FN - || isset(Util\Tokens::$methodPrefixes[$tokenType]) === true + || isset(Tokens::$methodPrefixes[$tokenType]) === true + || isset(Tokens::$scopeModifiers[$tokenType]) === true || $tokenType === T_VAR + || $tokenType === T_READONLY ) { if (PHP_CODESNIFFER_VERBOSITY > 1) { echo "\t\t* token $stackPtr changed from ? to T_NULLABLE".PHP_EOL; @@ -2055,7 +2258,7 @@ protected function tokenize($string) break; } - if (isset(Util\Tokens::$emptyTokens[$tokenType]) === false) { + if (isset(Tokens::$emptyTokens[$tokenType]) === false) { $lastSeenNonEmpty = $tokenType; } }//end for @@ -2078,7 +2281,7 @@ protected function tokenize($string) && $token[0] !== T_STRING && $token[0] !== T_VARIABLE && $token[0] !== T_DOLLAR - && isset(Util\Tokens::$emptyTokens[$token[0]]) === false + && isset(Tokens::$emptyTokens[$token[0]]) === false ) { $newToken = []; $newToken['code'] = T_STRING; @@ -2138,11 +2341,11 @@ function return types. We want to keep the parenthesis map clean, if ($parenthesisCloser !== false) { for ($x = ($parenthesisCloser + 1); $x < $numTokens; $x++) { if (is_array($tokens[$x]) === false - || isset(Util\Tokens::$emptyTokens[$tokens[$x][0]]) === false + || isset(Tokens::$emptyTokens[$tokens[$x][0]]) === false ) { // Non-empty content. if (is_array($tokens[$x]) === true && $tokens[$x][0] === T_USE) { - // Found a use statements, so search ahead for the closing parenthesis. + // Found a use statement, so search ahead for the closing parenthesis. for ($x += 1; $x < $numTokens; $x++) { if (is_array($tokens[$x]) === false && $tokens[$x] === ')') { continue(2); @@ -2161,7 +2364,7 @@ function return types. We want to keep the parenthesis map clean, // Find the start of the return type. for ($x += 1; $x < $numTokens; $x++) { if (is_array($tokens[$x]) === true - && isset(Util\Tokens::$emptyTokens[$tokens[$x][0]]) === true + && isset(Tokens::$emptyTokens[$tokens[$x][0]]) === true ) { // Whitespace or comments before the return type. continue; @@ -2273,7 +2476,7 @@ function return types. We want to keep the parenthesis map clean, $tokenLines = explode($this->eolChar, $token[1]); $numLines = count($tokenLines); $newToken = [ - 'type' => Util\Tokens::tokenName($token[0]), + 'type' => Tokens::tokenName($token[0]), 'code' => $token[0], 'content' => '', ]; @@ -2305,7 +2508,7 @@ function return types. We want to keep the parenthesis map clean, // Find the next non-empty token. for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { if (is_array($tokens[$i]) === true - && isset(Util\Tokens::$emptyTokens[$tokens[$i][0]]) === true + && isset(Tokens::$emptyTokens[$tokens[$i][0]]) === true ) { continue; } @@ -2333,7 +2536,7 @@ function return types. We want to keep the parenthesis map clean, } else if ($finalTokens[$lastNotEmptyToken]['content'] === '&') { // Function names for functions declared to return by reference. for ($i = ($lastNotEmptyToken - 1); $i >= 0; $i--) { - if (isset(Util\Tokens::$emptyTokens[$finalTokens[$i]['code']]) === true) { + if (isset(Tokens::$emptyTokens[$finalTokens[$i]['code']]) === true) { continue; } @@ -2347,7 +2550,7 @@ function return types. We want to keep the parenthesis map clean, // Keywords with special PHPCS token when used as a function call. for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { if (is_array($tokens[$i]) === true - && isset(Util\Tokens::$emptyTokens[$tokens[$i][0]]) === true + && isset(Tokens::$emptyTokens[$tokens[$i][0]]) === true ) { continue; } @@ -2404,7 +2607,7 @@ function return types. We want to keep the parenthesis map clean, // Get the previous non-empty token. for ($i = ($stackPtr - 1); $i > 0; $i--) { if (is_array($tokens[$i]) === false - || isset(Util\Tokens::$emptyTokens[$tokens[$i][0]]) === false + || isset(Tokens::$emptyTokens[$tokens[$i][0]]) === false ) { break; } @@ -2511,7 +2714,7 @@ function return types. We want to keep the parenthesis map clean, if ($newToken['code'] === T_ARRAY) { for ($i = ($stackPtr + 1); $i < $numTokens; $i++) { if (is_array($tokens[$i]) === false - || isset(Util\Tokens::$emptyTokens[$tokens[$i][0]]) === false + || isset(Tokens::$emptyTokens[$tokens[$i][0]]) === false ) { // Non-empty content. break; @@ -2596,7 +2799,9 @@ protected function processAdditional() $this->createAttributesNestingMap(); - $numTokens = count($this->tokens); + $numTokens = count($this->tokens); + $lastSeenTypeToken = $numTokens; + for ($i = ($numTokens - 1); $i >= 0; $i--) { // Check for any unset scope conditions due to alternate IF/ENDIF syntax. if (isset($this->tokens[$i]['scope_opener']) === true @@ -2613,7 +2818,7 @@ protected function processAdditional() if (isset($this->tokens[$i]['scope_opener']) === true) { for ($x = ($i + 1); $x < $numTokens; $x++) { - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false + if (isset(Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false && $this->tokens[$x]['code'] !== T_BITWISE_AND ) { break; @@ -2649,7 +2854,7 @@ protected function processAdditional() */ for ($x = ($i + 1); $x < $numTokens; $x++) { - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) { + if (isset(Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) { break; } } @@ -2700,7 +2905,7 @@ protected function processAdditional() } else if ($this->tokens[$i]['code'] === T_FN && isset($this->tokens[($i + 1)]) === true) { // Possible arrow function. for ($x = ($i + 1); $x < $numTokens; $x++) { - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false + if (isset(Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false && $this->tokens[$x]['code'] !== T_BITWISE_AND ) { // Non-whitespace content. @@ -2708,22 +2913,29 @@ protected function processAdditional() } } - if (isset($this->tokens[$x]) === true && $this->tokens[$x]['code'] === T_OPEN_PARENTHESIS) { - $ignore = Util\Tokens::$emptyTokens; + if (isset($this->tokens[$x]) === true + && $this->tokens[$x]['code'] === T_OPEN_PARENTHESIS + && isset($this->tokens[$x]['parenthesis_closer']) === true + ) { + $ignore = Tokens::$emptyTokens; $ignore += [ - T_ARRAY => T_ARRAY, - T_CALLABLE => T_CALLABLE, - T_COLON => T_COLON, - T_NAMESPACE => T_NAMESPACE, - T_NS_SEPARATOR => T_NS_SEPARATOR, - T_NULL => T_NULL, - T_NULLABLE => T_NULLABLE, - T_PARENT => T_PARENT, - T_SELF => T_SELF, - T_STATIC => T_STATIC, - T_STRING => T_STRING, - T_TYPE_UNION => T_TYPE_UNION, - T_TYPE_INTERSECTION => T_TYPE_INTERSECTION, + T_ARRAY => T_ARRAY, + T_CALLABLE => T_CALLABLE, + T_COLON => T_COLON, + T_NAMESPACE => T_NAMESPACE, + T_NS_SEPARATOR => T_NS_SEPARATOR, + T_NULL => T_NULL, + T_TRUE => T_TRUE, + T_FALSE => T_FALSE, + T_NULLABLE => T_NULLABLE, + T_PARENT => T_PARENT, + T_SELF => T_SELF, + T_STATIC => T_STATIC, + T_STRING => T_STRING, + T_TYPE_UNION => T_TYPE_UNION, + T_TYPE_INTERSECTION => T_TYPE_INTERSECTION, + T_TYPE_OPEN_PARENTHESIS => T_TYPE_OPEN_PARENTHESIS, + T_TYPE_CLOSE_PARENTHESIS => T_TYPE_CLOSE_PARENTHESIS, ]; $closer = $this->tokens[$x]['parenthesis_closer']; @@ -2768,7 +2980,7 @@ protected function processAdditional() } for ($lastNonEmpty = ($scopeCloser - 1); $lastNonEmpty > $arrow; $lastNonEmpty--) { - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$lastNonEmpty]['code']]) === false) { + if (isset(Tokens::$emptyTokens[$this->tokens[$lastNonEmpty]['code']]) === false) { $scopeCloser = $lastNonEmpty; break 2; } @@ -2783,7 +2995,7 @@ protected function processAdditional() && $this->tokens[$scopeCloser]['bracket_opener'] < $arrow)) ) { for ($lastNonEmpty = ($scopeCloser - 1); $lastNonEmpty > $arrow; $lastNonEmpty--) { - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$lastNonEmpty]['code']]) === false) { + if (isset(Tokens::$emptyTokens[$this->tokens[$lastNonEmpty]['code']]) === false) { $scopeCloser = $lastNonEmpty; break; } @@ -2882,7 +3094,7 @@ protected function processAdditional() }//end if }//end if - // If after all that, the extra tokens are not set, this is not an arrow function. + // If after all that, the extra tokens are not set, this is not a (valid) arrow function. if (isset($this->tokens[$i]['scope_closer']) === false) { if (PHP_CODESNIFFER_VERBOSITY > 1) { $line = $this->tokens[$i]['line']; @@ -2912,7 +3124,7 @@ protected function processAdditional() T_CONSTANT_ENCAPSED_STRING => T_CONSTANT_ENCAPSED_STRING, T_DOUBLE_QUOTED_STRING => T_DOUBLE_QUOTED_STRING, ]; - $allowed += Util\Tokens::$magicConstants; + $allowed += Tokens::$magicConstants; for ($x = ($i - 1); $x >= 0; $x--) { // If we hit a scope opener, the statement has ended @@ -2923,11 +3135,11 @@ protected function processAdditional() break; } - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) { + if (isset(Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) { // Allow for control structures without braces. if (($this->tokens[$x]['code'] === T_CLOSE_PARENTHESIS && isset($this->tokens[$x]['parenthesis_owner']) === true - && isset(Util\Tokens::$scopeOpeners[$this->tokens[$this->tokens[$x]['parenthesis_owner']]['code']]) === true) + && isset(Tokens::$scopeOpeners[$this->tokens[$this->tokens[$x]['parenthesis_owner']]['code']]) === true) || isset($allowed[$this->tokens[$x]['code']]) === false ) { $isShortArray = true; @@ -2989,7 +3201,7 @@ protected function processAdditional() T_OPEN_SHORT_ARRAY => T_OPEN_SHORT_ARRAY, T_DOUBLE_ARROW => T_DOUBLE_ARROW, ]; - $searchFor += Util\Tokens::$scopeOpeners; + $searchFor += Tokens::$scopeOpeners; for ($x = ($this->tokens[$i]['scope_opener'] + 1); $x < $this->tokens[$i]['scope_closer']; $x++) { if (isset($searchFor[$this->tokens[$x]['code']]) === false) { @@ -3026,10 +3238,20 @@ protected function processAdditional() continue; } else if ($this->tokens[$i]['code'] === T_BITWISE_OR || $this->tokens[$i]['code'] === T_BITWISE_AND + || $this->tokens[$i]['code'] === T_CLOSE_PARENTHESIS ) { + if ($lastSeenTypeToken < $i) { + // We've already examined this code to check if it is a type declaration and concluded it wasn't. + // No need to do it again. + continue; + } + /* Convert "|" to T_TYPE_UNION or leave as T_BITWISE_OR. Convert "&" to T_TYPE_INTERSECTION or leave as T_BITWISE_AND. + Convert "(" and ")" to T_TYPE_(OPEN|CLOSE)_PARENTHESIS or leave as T_(OPEN|CLOSE)_PARENTHESIS. + + All type related tokens will be converted in one go as soon as this section is hit. */ $allowed = [ @@ -3045,20 +3267,22 @@ protected function processAdditional() T_NS_SEPARATOR => T_NS_SEPARATOR, ]; - $suspectedType = null; - $typeTokenCount = 0; + $suspectedType = null; + $typeTokenCountAfter = 0; for ($x = ($i + 1); $x < $numTokens; $x++) { - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === true) { + if (isset(Tokens::$emptyTokens[$this->tokens[$x]['code']]) === true) { continue; } if (isset($allowed[$this->tokens[$x]['code']]) === true) { - ++$typeTokenCount; + ++$typeTokenCountAfter; continue; } - if ($typeTokenCount > 0 + if (($typeTokenCountAfter > 0 + || ($this->tokens[$i]['code'] === T_CLOSE_PARENTHESIS + && isset($this->tokens[$i]['parenthesis_owner']) === false)) && ($this->tokens[$x]['code'] === T_BITWISE_AND || $this->tokens[$x]['code'] === T_ELLIPSIS) ) { @@ -3089,6 +3313,7 @@ protected function processAdditional() && $this->tokens[$this->tokens[$x]['scope_condition']]['code'] === T_FUNCTION ) { $suspectedType = 'return'; + break; } if ($this->tokens[$x]['code'] === T_EQUAL) { @@ -3100,8 +3325,12 @@ protected function processAdditional() break; }//end for - if ($typeTokenCount === 0 || isset($suspectedType) === false) { - // Definitely not a union or intersection type, move on. + if (($typeTokenCountAfter === 0 + && ($this->tokens[$i]['code'] !== T_CLOSE_PARENTHESIS + || isset($this->tokens[$i]['parenthesis_owner']) === true)) + || isset($suspectedType) === false + ) { + // Definitely not a union, intersection or DNF type, move on. continue; } @@ -3109,22 +3338,79 @@ protected function processAdditional() unset($allowed[T_STATIC]); } - $typeTokenCount = 0; - $typeOperators = [$i]; - $confirmed = false; + $typeTokenCountBefore = 0; + $typeOperators = [$i]; + $parenthesesCount = 0; + $confirmed = false; + $maybeNullable = null; + + if ($this->tokens[$i]['code'] === T_OPEN_PARENTHESIS || $this->tokens[$i]['code'] === T_CLOSE_PARENTHESIS) { + ++$parenthesesCount; + } for ($x = ($i - 1); $x >= 0; $x--) { - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === true) { + if (isset(Tokens::$emptyTokens[$this->tokens[$x]['code']]) === true) { continue; } + if ($suspectedType === 'property or parameter' + && $this->tokens[$x]['code'] === T_STRING + && strtolower($this->tokens[$x]['content']) === 'static' + ) { + // Static keyword followed directly by an open parenthesis for a DNF type. + // This token should be T_STATIC and was incorrectly identified as a function call before. + $this->tokens[$x]['code'] = T_STATIC; + $this->tokens[$x]['type'] = 'T_STATIC'; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $line = $this->tokens[$x]['line']; + echo "\t* token $x on line $line changed back from T_STRING to T_STATIC".PHP_EOL; + } + } + + if ($suspectedType === 'property or parameter' + && $this->tokens[$x]['code'] === T_OPEN_PARENTHESIS + ) { + // We need to prevent the open parenthesis for a function/fn declaration from being retokenized + // to T_TYPE_OPEN_PARENTHESIS if this is the first parameter in the declaration. + if (isset($this->tokens[$x]['parenthesis_owner']) === true + && $this->tokens[$this->tokens[$x]['parenthesis_owner']]['code'] === T_FUNCTION + ) { + $confirmed = true; + break; + } else { + // This may still be an arrow function which hasn't been handled yet. + for ($y = ($x - 1); $y > 0; $y--) { + if (isset(Tokens::$emptyTokens[$this->tokens[$y]['code']]) === false + && $this->tokens[$y]['code'] !== T_BITWISE_AND + ) { + // Non-whitespace content. + break; + } + } + + if ($this->tokens[$y]['code'] === T_FN) { + $confirmed = true; + break; + } + } + }//end if + if (isset($allowed[$this->tokens[$x]['code']]) === true) { - ++$typeTokenCount; + ++$typeTokenCountBefore; continue; } - // Union and intersection types can't use the nullable operator, but be tolerant to parse errors. - if ($typeTokenCount > 0 && $this->tokens[$x]['code'] === T_NULLABLE) { + // Union, intersection and DNF types can't use the nullable operator, but be tolerant to parse errors. + if (($typeTokenCountBefore > 0 + || ($this->tokens[$x]['code'] === T_OPEN_PARENTHESIS && isset($this->tokens[$x]['parenthesis_owner']) === false)) + && ($this->tokens[$x]['code'] === T_NULLABLE + || $this->tokens[$x]['code'] === T_INLINE_THEN) + ) { + if ($this->tokens[$x]['code'] === T_INLINE_THEN) { + $maybeNullable = $x; + } + continue; } @@ -3133,10 +3419,52 @@ protected function processAdditional() continue; } + if ($this->tokens[$x]['code'] === T_OPEN_PARENTHESIS || $this->tokens[$x]['code'] === T_CLOSE_PARENTHESIS) { + ++$parenthesesCount; + $typeOperators[] = $x; + continue; + } + if ($suspectedType === 'return' && $this->tokens[$x]['code'] === T_COLON) { - $confirmed = true; + // Make sure this is the colon for a return type. + for ($y = ($x - 1); $y > 0; $y--) { + if (isset(Tokens::$emptyTokens[$this->tokens[$y]['code']]) === false) { + break; + } + } + + if ($this->tokens[$y]['code'] !== T_CLOSE_PARENTHESIS) { + // Definitely not a union, intersection or DNF return type, move on. + continue 2; + } + + if (isset($this->tokens[$y]['parenthesis_owner']) === true) { + if ($this->tokens[$this->tokens[$y]['parenthesis_owner']]['code'] === T_FUNCTION + || $this->tokens[$this->tokens[$y]['parenthesis_owner']]['code'] === T_CLOSURE + || $this->tokens[$this->tokens[$y]['parenthesis_owner']]['code'] === T_FN + ) { + $confirmed = true; + } + + break; + } + + // Arrow functions may not have the parenthesis_owner set correctly yet. + // Closure use tokens won't be parentheses owners until PHPCS 4.0. + if (isset($this->tokens[$y]['parenthesis_opener']) === true) { + for ($z = ($this->tokens[$y]['parenthesis_opener'] - 1); $z > 0; $z--) { + if (isset(Tokens::$emptyTokens[$this->tokens[$z]['code']]) === false) { + break; + } + } + + if ($this->tokens[$z]['code'] === T_FN || $this->tokens[$z]['code'] === T_USE) { + $confirmed = true; + } + } + break; - } + }//end if if ($suspectedType === 'constant' && $this->tokens[$x]['code'] === T_CONST) { $confirmed = true; @@ -3144,10 +3472,11 @@ protected function processAdditional() } if ($suspectedType === 'property or parameter' - && (isset(Util\Tokens::$scopeModifiers[$this->tokens[$x]['code']]) === true + && (isset(Tokens::$scopeModifiers[$this->tokens[$x]['code']]) === true || $this->tokens[$x]['code'] === T_VAR || $this->tokens[$x]['code'] === T_STATIC - || $this->tokens[$x]['code'] === T_READONLY) + || $this->tokens[$x]['code'] === T_READONLY + || $this->tokens[$x]['code'] === T_FINAL) ) { // This will also confirm constructor property promotion parameters, but that's fine. $confirmed = true; @@ -3156,6 +3485,9 @@ protected function processAdditional() break; }//end for + // Remember the last token we examined as part of the (non-)"type declaration". + $lastSeenTypeToken = $x; + if ($confirmed === false && $suspectedType === 'property or parameter' && isset($this->tokens[$i]['nested_parenthesis']) === true @@ -3172,7 +3504,7 @@ protected function processAdditional() // had additional processing done. if (isset($this->tokens[$last]['parenthesis_opener']) === true) { for ($x = ($this->tokens[$last]['parenthesis_opener'] - 1); $x >= 0; $x--) { - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === true) { + if (isset(Tokens::$emptyTokens[$this->tokens[$x]['code']]) === true) { continue; } @@ -3181,7 +3513,7 @@ protected function processAdditional() if ($this->tokens[$x]['code'] === T_FN) { for (--$x; $x >= 0; $x--) { - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === true + if (isset(Tokens::$emptyTokens[$this->tokens[$x]['code']]) === true || $this->tokens[$x]['code'] === T_BITWISE_AND ) { continue; @@ -3200,8 +3532,8 @@ protected function processAdditional() unset($parens, $last); }//end if - if ($confirmed === false) { - // Not a union or intersection type after all, move on. + if ($confirmed === false || ($parenthesesCount % 2) !== 0) { + // Not a (valid) union, intersection or DNF type after all, move on. continue; } @@ -3214,7 +3546,7 @@ protected function processAdditional() $line = $this->tokens[$x]['line']; echo "\t* token $x on line $line changed from T_BITWISE_OR to T_TYPE_UNION".PHP_EOL; } - } else { + } else if ($this->tokens[$x]['code'] === T_BITWISE_AND) { $this->tokens[$x]['code'] = T_TYPE_INTERSECTION; $this->tokens[$x]['type'] = 'T_TYPE_INTERSECTION'; @@ -3222,13 +3554,39 @@ protected function processAdditional() $line = $this->tokens[$x]['line']; echo "\t* token $x on line $line changed from T_BITWISE_AND to T_TYPE_INTERSECTION".PHP_EOL; } + } else if ($this->tokens[$x]['code'] === T_OPEN_PARENTHESIS) { + $this->tokens[$x]['code'] = T_TYPE_OPEN_PARENTHESIS; + $this->tokens[$x]['type'] = 'T_TYPE_OPEN_PARENTHESIS'; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $line = $this->tokens[$x]['line']; + echo "\t* token $x on line $line changed from T_OPEN_PARENTHESIS to T_TYPE_OPEN_PARENTHESIS".PHP_EOL; + } + } else if ($this->tokens[$x]['code'] === T_CLOSE_PARENTHESIS) { + $this->tokens[$x]['code'] = T_TYPE_CLOSE_PARENTHESIS; + $this->tokens[$x]['type'] = 'T_TYPE_CLOSE_PARENTHESIS'; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $line = $this->tokens[$x]['line']; + echo "\t* token $x on line $line changed from T_CLOSE_PARENTHESIS to T_TYPE_CLOSE_PARENTHESIS".PHP_EOL; + } + }//end if + }//end foreach + + if (isset($maybeNullable) === true) { + $this->tokens[$maybeNullable]['code'] = T_NULLABLE; + $this->tokens[$maybeNullable]['type'] = 'T_NULLABLE'; + + if (PHP_CODESNIFFER_VERBOSITY > 1) { + $line = $this->tokens[$maybeNullable]['line']; + echo "\t* token $maybeNullable on line $line changed from T_INLINE_THEN to T_NULLABLE".PHP_EOL; } } continue; } else if ($this->tokens[$i]['code'] === T_STATIC) { for ($x = ($i - 1); $x > 0; $x--) { - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) { + if (isset(Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) { break; } } @@ -3249,7 +3607,7 @@ protected function processAdditional() || $this->tokens[$i]['code'] === T_NULL ) { for ($x = ($i + 1); $x < $numTokens; $x++) { - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) { + if (isset(Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) { // Non-whitespace content. break; } @@ -3285,7 +3643,7 @@ protected function processAdditional() // opening this case statement and the opener and closer are // probably set incorrectly. for ($x = ($scopeOpener + 1); $x < $numTokens; $x++) { - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) { + if (isset(Tokens::$emptyTokens[$this->tokens[$x]['code']]) === false) { // Non-whitespace content. break; } @@ -3389,14 +3747,14 @@ protected function processAdditional() $type = $this->tokens[$x]['type']; $oldConds = ''; foreach ($oldConditions as $condition) { - $oldConds .= Util\Tokens::tokenName($condition).','; + $oldConds .= Tokens::tokenName($condition).','; } $oldConds = rtrim($oldConds, ','); $newConds = ''; foreach ($this->tokens[$x]['conditions'] as $condition) { - $newConds .= Util\Tokens::tokenName($condition).','; + $newConds .= Tokens::tokenName($condition).','; } $newConds = rtrim($newConds, ','); @@ -3484,7 +3842,7 @@ public static function standardiseToken($token) } else { $newToken = [ 'code' => $token[0], - 'type' => Util\Tokens::tokenName($token[0]), + 'type' => Tokens::tokenName($token[0]), ]; self::$resolveTokenCache[$token[0]] = $newToken; @@ -3608,10 +3966,10 @@ public static function resolveSimpleToken($token) * Finds a "closer" token (closing parenthesis or square bracket for example) * Handle parenthesis balancing while searching for closing token * - * @param array $tokens The list of tokens to iterate searching the closing token (as returned by token_get_all) - * @param int $start The starting position - * @param string|string[] $openerTokens The opening character - * @param string $closerChar The closing character + * @param array $tokens The list of tokens to iterate searching the closing token (as returned by token_get_all). + * @param int $start The starting position. + * @param string|string[] $openerTokens The opening character. + * @param string $closerChar The closing character. * * @return int|null The position of the closing token, if found. NULL otherwise. */ @@ -3645,8 +4003,8 @@ private function findCloser(array &$tokens, $start, $openerTokens, $closerChar) * PHP 8 attributes parser for PHP < 8 * Handles single-line and multiline attributes. * - * @param array $tokens The original array of tokens (as returned by token_get_all) - * @param int $stackPtr The current position in token array + * @param array $tokens The original array of tokens (as returned by token_get_all). + * @param int $stackPtr The current position in token array. * * @return array|null The array of parsed attribute tokens */ diff --git a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/Tokenizer.php b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/Tokenizer.php index bfe8c7a14..fe3d05e83 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/Tokenizer.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Tokenizers/Tokenizer.php @@ -10,7 +10,8 @@ namespace PHP_CodeSniffer\Tokenizers; use PHP_CodeSniffer\Exceptions\TokenizerException; -use PHP_CodeSniffer\Util; +use PHP_CodeSniffer\Util\Common; +use PHP_CodeSniffer\Util\Tokens; abstract class Tokenizer { @@ -53,7 +54,7 @@ abstract class Tokenizer /** * A list of tokens that end the scope. * - * @var array + * @var array */ public $endScopeTokens = []; @@ -75,9 +76,9 @@ abstract class Tokenizer /** * Initialise and run the tokenizer. * - * @param string $content The content to tokenize, - * @param \PHP_CodeSniffer\Config | null $config The config data for the run. - * @param string $eolChar The EOL char used in the content. + * @param string $content The content to tokenize. + * @param \PHP_CodeSniffer\Config|null $config The config data for the run. + * @param string $eolChar The EOL char used in the content. * * @return void * @throws \PHP_CodeSniffer\Exceptions\TokenizerException If the file appears to be minified. @@ -192,11 +193,14 @@ private function createPositionMap() T_DOC_COMMENT_STRING => true, T_CONSTANT_ENCAPSED_STRING => true, T_DOUBLE_QUOTED_STRING => true, + T_START_HEREDOC => true, + T_START_NOWDOC => true, T_HEREDOC => true, T_NOWDOC => true, T_END_HEREDOC => true, T_END_NOWDOC => true, T_INLINE_HTML => true, + T_YIELD_FROM => true, ]; $this->numTokens = count($this->tokens); @@ -617,7 +621,7 @@ public function replaceTabsInToken(&$token, $prefix=' ', $padding=' ', $tabWidth if ($content !== '') { $newContent .= $content; if ($checkEncoding === true) { - // Not using the default encoding, so take a bit more care. + // Not using ASCII encoding, so take a bit more care. $oldLevel = error_reporting(); error_reporting(0); $contentLength = iconv_strlen($content, $this->config->encoding); @@ -680,7 +684,7 @@ private function createTokenMap() Parenthesis mapping. */ - if (isset(Util\Tokens::$parenthesisOpeners[$this->tokens[$i]['code']]) === true) { + if (isset(Tokens::$parenthesisOpeners[$this->tokens[$i]['code']]) === true) { $this->tokens[$i]['parenthesis_opener'] = null; $this->tokens[$i]['parenthesis_closer'] = null; $this->tokens[$i]['parenthesis_owner'] = $i; @@ -896,7 +900,7 @@ private function createScopeMap() if (isset($this->scopeOpeners[$this->tokens[$i]['code']]) === true) { if (PHP_CODESNIFFER_VERBOSITY > 1) { $type = $this->tokens[$i]['type']; - $content = Util\Common::prepareForOutput($this->tokens[$i]['content']); + $content = Common::prepareForOutput($this->tokens[$i]['content']); echo "\tStart scope map at $i:$type => $content".PHP_EOL; } @@ -958,7 +962,7 @@ private function recurseScopeMap($stackPtr, $depth=1, &$ignore=0) if (PHP_CODESNIFFER_VERBOSITY > 1) { $type = $this->tokens[$i]['type']; $line = $this->tokens[$i]['line']; - $content = Util\Common::prepareForOutput($this->tokens[$i]['content']); + $content = Common::prepareForOutput($this->tokens[$i]['content']); echo str_repeat("\t", $depth); echo "Process token $i on line $line ["; @@ -1314,13 +1318,13 @@ private function recurseScopeMap($stackPtr, $depth=1, &$ignore=0) // Make sure this is actually an opener and not a // string offset (e.g., $var{0}). for ($x = ($i - 1); $x > 0; $x--) { - if (isset(Util\Tokens::$emptyTokens[$this->tokens[$x]['code']]) === true) { + if (isset(Tokens::$emptyTokens[$this->tokens[$x]['code']]) === true) { continue; } else { // If the first non-whitespace/comment token looks like this // brace is a string offset, or this brace is mid-way through // a new statement, it isn't a scope opener. - $disallowed = Util\Tokens::$assignmentTokens; + $disallowed = Tokens::$assignmentTokens; $disallowed += [ T_DOLLAR => true, T_VARIABLE => true, @@ -1388,7 +1392,7 @@ private function recurseScopeMap($stackPtr, $depth=1, &$ignore=0) } else if ($tokenType === T_OPEN_PARENTHESIS) { if (isset($this->tokens[$i]['parenthesis_owner']) === true) { $owner = $this->tokens[$i]['parenthesis_owner']; - if (isset(Util\Tokens::$scopeOpeners[$this->tokens[$owner]['code']]) === true + if (isset(Tokens::$scopeOpeners[$this->tokens[$owner]['code']]) === true && isset($this->tokens[$i]['parenthesis_closer']) === true ) { // If we get into here, then we opened a parenthesis for @@ -1427,7 +1431,7 @@ private function recurseScopeMap($stackPtr, $depth=1, &$ignore=0) // token was empty (in which case we'll just confirm there is // more code in this file and not just a big comment). if ($this->tokens[$i]['line'] >= ($startLine + 30) - && isset(Util\Tokens::$emptyTokens[$this->tokens[($i - 1)]['code']]) === false + && isset(Tokens::$emptyTokens[$this->tokens[($i - 1)]['code']]) === false ) { if ($this->scopeOpeners[$currType]['strict'] === true) { if (PHP_CODESNIFFER_VERBOSITY > 1) { @@ -1516,14 +1520,14 @@ private function createLevelMap() $len = $this->tokens[$i]['length']; $col = $this->tokens[$i]['column']; - $content = Util\Common::prepareForOutput($this->tokens[$i]['content']); + $content = Common::prepareForOutput($this->tokens[$i]['content']); echo str_repeat("\t", ($level + 1)); echo "Process token $i on line $line [col:$col;len:$len;lvl:$level;"; if (empty($conditions) !== true) { $conditionString = 'conds;'; foreach ($conditions as $condition) { - $conditionString .= Util\Tokens::tokenName($condition).','; + $conditionString .= Tokens::tokenName($condition).','; } echo rtrim($conditionString, ',').';'; @@ -1584,14 +1588,14 @@ private function createLevelMap() $type = $this->tokens[$x]['type']; $oldConds = ''; foreach ($oldConditions as $condition) { - $oldConds .= Util\Tokens::tokenName($condition).','; + $oldConds .= Tokens::tokenName($condition).','; } $oldConds = rtrim($oldConds, ','); $newConds = ''; foreach ($this->tokens[$x]['conditions'] as $condition) { - $newConds .= Util\Tokens::tokenName($condition).','; + $newConds .= Tokens::tokenName($condition).','; } $newConds = rtrim($newConds, ','); @@ -1660,7 +1664,7 @@ private function createLevelMap() $oldCondition = array_pop($conditions); if (PHP_CODESNIFFER_VERBOSITY > 1) { echo str_repeat("\t", ($level + 1)); - echo '* token '.Util\Tokens::tokenName($oldCondition).' removed from conditions array *'.PHP_EOL; + echo '* token '.Tokens::tokenName($oldCondition).' removed from conditions array *'.PHP_EOL; } // Make sure this closer actually belongs to us. @@ -1672,7 +1676,7 @@ private function createLevelMap() $badToken = $this->tokens[$oldOpener]['scope_condition']; if (PHP_CODESNIFFER_VERBOSITY > 1) { - $type = Util\Tokens::tokenName($oldCondition); + $type = Tokens::tokenName($oldCondition); echo str_repeat("\t", ($level + 1)); echo "* scope closer was bad, cleaning up $badToken:$type *".PHP_EOL; } @@ -1686,14 +1690,14 @@ private function createLevelMap() $type = $this->tokens[$x]['type']; $oldConds = ''; foreach ($oldConditions as $condition) { - $oldConds .= Util\Tokens::tokenName($condition).','; + $oldConds .= Tokens::tokenName($condition).','; } $oldConds = rtrim($oldConds, ','); $newConds = ''; foreach ($this->tokens[$x]['conditions'] as $condition) { - $newConds .= Util\Tokens::tokenName($condition).','; + $newConds .= Tokens::tokenName($condition).','; } $newConds = rtrim($newConds, ','); diff --git a/app/vendor/squizlabs/php_codesniffer/src/Util/Cache.php b/app/vendor/squizlabs/php_codesniffer/src/Util/Cache.php index 932952e4b..408de96e7 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Util/Cache.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Util/Cache.php @@ -9,9 +9,13 @@ namespace PHP_CodeSniffer\Util; +use FilesystemIterator; use PHP_CodeSniffer\Autoload; use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Ruleset; +use RecursiveCallbackFilterIterator; +use RecursiveDirectoryIterator; +use RecursiveIteratorIterator; class Cache { @@ -95,11 +99,11 @@ public static function load(Ruleset $ruleset, Config $config) // hash. This ensures that core PHPCS changes will also invalidate the cache. // Note that we ignore sniffs here, and any files that don't affect // the outcome of the run. - $di = new \RecursiveDirectoryIterator( + $di = new RecursiveDirectoryIterator( $installDir, - (\FilesystemIterator::KEY_AS_PATHNAME | \FilesystemIterator::CURRENT_AS_FILEINFO | \FilesystemIterator::SKIP_DOTS) + (FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::SKIP_DOTS) ); - $filter = new \RecursiveCallbackFilterIterator( + $filter = new RecursiveCallbackFilterIterator( $di, function ($file, $key, $iterator) { // Skip non-php files. @@ -126,7 +130,7 @@ function ($file, $key, $iterator) { } ); - $iterator = new \RecursiveIteratorIterator($filter); + $iterator = new RecursiveIteratorIterator($filter); foreach ($iterator as $file) { if (PHP_CODESNIFFER_VERBOSITY > 1) { echo "\t\t=> core file: $file".PHP_EOL; diff --git a/app/vendor/squizlabs/php_codesniffer/src/Util/Common.php b/app/vendor/squizlabs/php_codesniffer/src/Util/Common.php index afed49e70..cb6965f62 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Util/Common.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Util/Common.php @@ -9,6 +9,9 @@ namespace PHP_CodeSniffer\Util; +use InvalidArgumentException; +use Phar; + class Common { @@ -112,7 +115,7 @@ public static function realpath($path) return $path; } - $phar = \Phar::running(false); + $phar = Phar::running(false); $extra = str_replace('phar://'.$phar, '', $path); $path = realpath($phar); if ($path === false) { @@ -310,6 +313,20 @@ public static function prepareForOutput($content, $exclude=[]) }//end prepareForOutput() + /** + * Strip colors from a text for output to screen. + * + * @param string $text The text to process. + * + * @return string + */ + public static function stripColors($text) + { + return preg_replace('`\033\[[0-9;]+m`', '', $text); + + }//end stripColors() + + /** * Returns true if the specified string is in the camel caps format. * @@ -404,7 +421,7 @@ public static function isCamelCaps( */ public static function isUnderscoreName($string) { - // If there are space in the name, it can't be valid. + // If there is whitespace in the name, it can't be valid. if (strpos($string, ' ') !== false) { return false; } @@ -513,25 +530,43 @@ public static function suggestType($varType) * @param string $sniffClass The fully qualified sniff class name. * * @return string + * + * @throws \InvalidArgumentException When $sniffClass is not a non-empty string. + * @throws \InvalidArgumentException When $sniffClass is not a FQN for a sniff(test) class. */ public static function getSniffCode($sniffClass) { - $parts = explode('\\', $sniffClass); - $sniff = array_pop($parts); + if (is_string($sniffClass) === false || $sniffClass === '') { + throw new InvalidArgumentException('The $sniffClass parameter must be a non-empty string'); + } + + $parts = explode('\\', $sniffClass); + $partsCount = count($parts); + $sniff = $parts[($partsCount - 1)]; if (substr($sniff, -5) === 'Sniff') { // Sniff class name. $sniff = substr($sniff, 0, -5); - } else { + } else if (substr($sniff, -8) === 'UnitTest') { // Unit test class name. $sniff = substr($sniff, 0, -8); + } else { + throw new InvalidArgumentException( + 'The $sniffClass parameter was not passed a fully qualified sniff(test) class name. Received: '.$sniffClass + ); + } + + $standard = ''; + if (isset($parts[($partsCount - 4)]) === true) { + $standard = $parts[($partsCount - 4)]; + } + + $category = ''; + if (isset($parts[($partsCount - 2)]) === true) { + $category = $parts[($partsCount - 2)]; } - $category = array_pop($parts); - $sniffDir = array_pop($parts); - $standard = array_pop($parts); - $code = $standard.'.'.$category.'.'.$sniff; - return $code; + return $standard.'.'.$category.'.'.$sniff; }//end getSniffCode() diff --git a/app/vendor/squizlabs/php_codesniffer/src/Util/Help.php b/app/vendor/squizlabs/php_codesniffer/src/Util/Help.php new file mode 100644 index 000000000..e125d3aaa --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Util/Help.php @@ -0,0 +1,626 @@ + + * @copyright 2024 Juliette Reinders Folmer. All rights reserved. + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Util; + +use InvalidArgumentException; +use PHP_CodeSniffer\Config; +use PHP_CodeSniffer\Util\Common; + +final class Help +{ + + + /** + * Short options which are available for both the `phpcs` as well as the `phpcbf` command. + * + * @var string + */ + const DEFAULT_SHORT_OPTIONS = '-hilnpqvw'; + + /** + * Long options which are available for both the `phpcs` as well as the `phpcbf` command. + * + * {@internal This should be a constant array, but those aren't supported until PHP 5.6.} + * + * @var string Comma-separated list of the option names. + */ + const DEFAULT_LONG_OPTIONS = 'basepath,bootstrap,colors,encoding,error-severity,exclude,extensions,file,file-list,filter,ignore,ignore-annotations,no-colors,parallel,php-ini,report-width,runtime-set,severity,sniffs,standard,stdin-path,tab-width,version,vv,vvv,warning-severity'; + + /** + * Minimum screen width. + * + * The help info needs room to display, so this is the minimum acceptable width. + * + * @var integer + */ + const MIN_WIDTH = 60; + + /** + * Indent option lines. + * + * @var string + */ + const INDENT = ' '; + + /** + * Gutter spacing for between the option argument info and the option description. + * + * @var string + */ + const GUTTER = ' '; + + /** + * The current PHPCS Configuration. + * + * @var \PHP_CodeSniffer\Config + */ + private $config; + + /** + * The options which should be shown for this help screen. + * + * @var array + */ + private $requestedOptions = []; + + /** + * Active options per category (after filtering). + * + * @var array>> + */ + private $activeOptions = []; + + /** + * Width of the indent for option lines. + * + * @var integer + */ + private $indentWidth = 0; + + /** + * Width of the gutter spacing. + * + * @var integer + */ + private $gutterWidth = 0; + + /** + * Width of longest option argument info entry. + * + * @var integer + */ + private $maxOptionNameLength = 0; + + + /** + * Constructor. + * + * @param \PHP_CodeSniffer\Config $config Configuration object. + * @param array $longOptions The long options which should be shown. + * @param string $shortOptions The short options which should be shown. + * + * @throws \InvalidArgumentException When $shortOptions is not a string. + */ + public function __construct(Config $config, array $longOptions, $shortOptions='') + { + if (is_string($shortOptions) === false) { + throw new InvalidArgumentException('The $shortOptions parameter must be a string'); + } + + $this->config = $config; + $this->requestedOptions = array_merge($longOptions, str_split($shortOptions)); + + $this->filterOptions(); + + $this->indentWidth = strlen(self::INDENT); + $this->gutterWidth = strlen(self::GUTTER); + + $this->setMaxOptionNameLength(); + + }//end __construct() + + + /** + * Display the help info. + * + * @return void + */ + public function display() + { + $this->printUsage(); + $this->printCategories(); + + }//end display() + + + /** + * Filter the available options based on the requested options. + * + * @return void + */ + private function filterOptions() + { + $filteredOptions = $this->getAllOptions(); + + foreach ($filteredOptions as $category => $options) { + // Initial state set to "true" to prevent a spacer at the start of an array. + $lastWasSpacer = true; + $spacerCount = 0; + + foreach ($options as $name => $option) { + if ($lastWasSpacer !== true && strpos($name, 'blank-line') === 0) { + ++$spacerCount; + $lastWasSpacer = true; + continue; + } + + if (in_array($name, $this->requestedOptions, true) === false) { + unset($filteredOptions[$category][$name]); + continue; + } + + $lastWasSpacer = false; + } + + // Make sure the final array doesn't contain a spacer at the end. + if (empty($filteredOptions[$category]) === false) { + end($filteredOptions[$category]); + $key = key($filteredOptions[$category]); + if (strpos($key, 'blank-line') === 0) { + unset($filteredOptions[$category][$key]); + --$spacerCount; + } + } + + // Remove categories now left empty. + if (empty($filteredOptions[$category]) === true || count($filteredOptions[$category]) === $spacerCount) { + unset($filteredOptions[$category]); + } + }//end foreach + + $this->activeOptions = $filteredOptions; + + }//end filterOptions() + + + /** + * Determine the length of the longest option argument and store it. + * + * @return void + */ + private function setMaxOptionNameLength() + { + $lengths = []; + foreach ($this->activeOptions as $category => $options) { + foreach ($options as $option) { + if (isset($option['argument']) === false) { + continue; + } + + $lengths[] = strlen($option['argument']); + } + } + + if (empty($lengths) === false) { + $this->maxOptionNameLength = max($lengths); + } + + }//end setMaxOptionNameLength() + + + /** + * Get the maximum width which can be used to display the help info. + * + * Independently of user preference/auto-determined width of the current screen, + * a minimum width is needed to display information, so don't allow this to get too low. + * + * @return int + */ + private function getMaxWidth() + { + return max(self::MIN_WIDTH, $this->config->reportWidth); + + }//end getMaxWidth() + + + /** + * Get the maximum width for the text in the option description column. + * + * @return int + */ + private function getDescriptionColumnWidth() + { + return ($this->getMaxWidth() - $this->maxOptionNameLength - $this->indentWidth - $this->gutterWidth); + + }//end getDescriptionColumnWidth() + + + /** + * Get the length of the indentation needed for follow up lines when the description does not fit on one line. + * + * @return int + */ + private function getDescriptionFollowupLineIndentLength() + { + return ($this->maxOptionNameLength + $this->indentWidth + $this->gutterWidth); + + }//end getDescriptionFollowupLineIndentLength() + + + /** + * Print basic usage information to the screen. + * + * @return void + */ + private function printUsage() + { + $command = 'phpcs'; + if (defined('PHP_CODESNIFFER_CBF') === true && PHP_CODESNIFFER_CBF === true) { + $command = 'phpcbf'; + } + + $this->printCategoryHeader('Usage'); + + echo self::INDENT.$command.' [options] '.PHP_EOL; + + }//end printUsage() + + + /** + * Print details of all the requested options to the screen, sorted by category. + * + * @return void + */ + private function printCategories() + { + foreach ($this->activeOptions as $category => $options) { + $this->printCategoryHeader($category); + $this->printCategoryOptions($options); + } + + }//end printCategories() + + + /** + * Print a category header. + * + * @param string $header The header text. + * + * @return void + */ + private function printCategoryHeader($header) + { + $header .= ':'; + if ($this->config->colors === true) { + $header = "\033[33m{$header}\033[0m"; + } + + echo PHP_EOL.$header.PHP_EOL; + + }//end printCategoryHeader() + + + /** + * Print the options for a category. + * + * @param array> $options The options to display. + * + * @return void + */ + private function printCategoryOptions(array $options) + { + $maxDescriptionWidth = $this->getDescriptionColumnWidth(); + $maxTextWidth = ($this->getMaxWidth() - $this->indentWidth); + $secondLineIndent = str_repeat(' ', $this->getDescriptionFollowupLineIndentLength()); + + $output = ''; + foreach ($options as $option) { + if (isset($option['spacer']) === true) { + $output .= PHP_EOL; + } + + if (isset($option['text']) === true) { + $text = wordwrap($option['text'], $maxTextWidth, "\n"); + $output .= self::INDENT.implode(PHP_EOL.self::INDENT, explode("\n", $text)).PHP_EOL; + } + + if (isset($option['argument'], $option['description']) === true) { + $argument = str_pad($option['argument'], $this->maxOptionNameLength); + $argument = $this->colorizeVariableInput($argument); + $output .= self::INDENT."\033[32m{$argument}\033[0m"; + $output .= self::GUTTER; + + $description = wordwrap($option['description'], $maxDescriptionWidth, "\n"); + $output .= implode(PHP_EOL.$secondLineIndent, explode("\n", $description)).PHP_EOL; + } + } + + if ($this->config->colors === false) { + $output = Common::stripColors($output); + } + + echo $output; + + }//end printCategoryOptions() + + + /** + * Colorize "variable" input in the option argument info. + * + * For the purposes of this method, "variable" input is text between <> brackets. + * The regex allows for multiple tags and nested tags. + * + * @param string $text The text to process. + * + * @return string + */ + private function colorizeVariableInput($text) + { + return preg_replace('`(<(?:(?>[^<>]+)|(?R))*>)`', "\033[36m".'$1'."\033[32m", $text); + + }//end colorizeVariableInput() + + + /** + * Retrieve the help details for all supported CLI arguments per category. + * + * @return array>> + */ + private function getAllOptions() + { + $options = []; + + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Readability is more important. + $options['Scan targets'] = [ + 'file' => [ + 'argument' => '', + 'description' => 'One or more files and/or directories to check, space separated.', + ], + '-' => [ + 'argument' => '-', + 'description' => 'Check STDIN instead of local files and directories.', + ], + 'stdin-path' => [ + 'argument' => '--stdin-path=', + 'description' => 'If processing STDIN, the file path that STDIN will be processed as.', + ], + 'file-list' => [ + 'argument' => '--file-list=', + 'description' => 'Check the files and/or directories which are defined in the file to which the path is provided (one per line).', + ], + 'filter' => [ + 'argument' => '--filter=', + 'description' => 'Check based on a predefined file filter. Use either the "GitModified" or "GitStaged" filter, or specify the path to a custom filter class.', + ], + 'ignore' => [ + 'argument' => '--ignore=', + 'description' => 'Ignore files based on a comma-separated list of patterns matching files and/or directories.', + ], + 'extensions' => [ + 'argument' => '--extensions=', + 'description' => 'Check files with the specified file extensions (comma-separated list). Defaults to php,inc/php,js,css.'."\n" + .'The type of the file can be specified using: ext/type; e.g. module/php,es/js.', + ], + 'l' => [ + 'argument' => '-l', + 'description' => 'Check local directory only, no recursion.', + ], + ]; + + $options['Rule Selection Options'] = [ + 'standard' => [ + 'argument' => '--standard=', + 'description' => 'The name of, or the path to, the coding standard to use. Can be a comma-separated list specifying multiple standards. If no standard is specified, PHP_CodeSniffer will look for a [.]phpcs.xml[.dist] custom ruleset file in the current directory and those above it.', + ], + 'sniffs' => [ + 'argument' => '--sniffs=', + 'description' => 'A comma-separated list of sniff codes to limit the scan to. All sniffs must be part of the standard in use.', + ], + 'exclude' => [ + 'argument' => '--exclude=', + 'description' => 'A comma-separated list of sniff codes to exclude from the scan. All sniffs must be part of the standard in use.', + ], + 'blank-line' => ['spacer' => ''], + + 'i' => [ + 'argument' => '-i', + 'description' => 'Show a list of installed coding standards.', + ], + 'e' => [ + 'argument' => '-e', + 'description' => 'Explain a standard by showing the names of all the sniffs it includes.', + ], + 'generator' => [ + 'argument' => '--generator=', + 'description' => 'Show documentation for a standard. Use either the "HTML", "Markdown" or "Text" generator.', + ], + ]; + + $options['Run Options'] = [ + 'a' => [ + 'argument' => '-a', + 'description' => 'Run in interactive mode, pausing after each file.', + ], + 'bootstrap' => [ + 'argument' => '--bootstrap=', + 'description' => 'Run the specified file(s) before processing begins. A list of files can be provided, separated by commas.', + ], + 'cache' => [ + 'argument' => '--cache[=]', + 'description' => 'Cache results between runs. Optionally, can be provided to use a specific file for caching. Otherwise, a temporary file is used.', + ], + 'no-cache' => [ + 'argument' => '--no-cache', + 'description' => 'Do not cache results between runs (default).', + ], + 'parallel' => [ + 'argument' => '--parallel=', + 'description' => 'The number of files to be checked simultaneously. Defaults to 1 (no parallel processing).'."\n" + .'If enabled, this option only takes effect if the PHP PCNTL (Process Control) extension is available.', + ], + 'suffix' => [ + 'argument' => '--suffix=', + 'description' => 'Write modified files to a filename using this suffix ("diff" and "patch" are not used in this mode).', + ], + 'blank-line' => ['spacer' => ''], + + 'php-ini' => [ + 'argument' => '-d ', + 'description' => 'Set the [key] php.ini value to [value] or set to [true] if value is omitted.'."\n" + .'Note: only php.ini settings which can be changed at runtime are supported.', + ], + ]; + + $options['Reporting Options'] = [ + 'report' => [ + 'argument' => '--report=', + 'description' => 'A comma-separated list of reports to print. Available reports: "full", "xml", "checkstyle", "csv", "json", "junit", "emacs", "source", "summary", "diff", "svnblame", "gitblame", "hgblame", "notifysend" or "performance".'."\n" + .'Or specify the path to a custom report class. By default, the "full" report is displayed.', + ], + 'report-file' => [ + 'argument' => '--report-file=', + 'description' => 'Write the report to the specified file path.', + ], + 'report-report' => [ + 'argument' => '--report-=', + 'description' => 'Write the report specified in to the specified file path.', + ], + 'report-width' => [ + 'argument' => '--report-width=', + 'description' => 'How many columns wide screen reports should be. Set to "auto" to use current screen width, where supported.', + ], + 'basepath' => [ + 'argument' => '--basepath=', + 'description' => 'Strip a path from the front of file paths inside reports.', + ], + 'blank-line-1' => ['spacer' => ''], + + 'w' => [ + 'argument' => '-w', + 'description' => 'Include both warnings and errors (default).', + ], + 'n' => [ + 'argument' => '-n', + 'description' => 'Do not include warnings. Shortcut for "--warning-severity=0".', + ], + 'severity' => [ + 'argument' => '--severity=', + 'description' => 'The minimum severity required to display an error or warning. Defaults to 5.', + ], + 'error-severity' => [ + 'argument' => '--error-severity=', + 'description' => 'The minimum severity required to display an error. Defaults to 5.', + ], + 'warning-severity' => [ + 'argument' => '--warning-severity=', + 'description' => 'The minimum severity required to display a warning. Defaults to 5.', + ], + 'blank-line-2' => ['spacer' => ''], + + 's' => [ + 'argument' => '-s', + 'description' => 'Show sniff error codes in all reports.', + ], + 'ignore-annotations' => [ + 'argument' => '--ignore-annotations', + 'description' => 'Ignore all "phpcs:..." annotations in code comments.', + ], + 'colors' => [ + 'argument' => '--colors', + 'description' => 'Use colors in screen output.', + ], + 'no-colors' => [ + 'argument' => '--no-colors', + 'description' => 'Do not use colors in screen output (default).', + ], + 'p' => [ + 'argument' => '-p', + 'description' => 'Show progress of the run.', + ], + 'q' => [ + 'argument' => '-q', + 'description' => 'Quiet mode; disables progress and verbose output.', + ], + 'm' => [ + 'argument' => '-m', + 'description' => 'Stop error messages from being recorded. This saves a lot of memory but stops many reports from being used.', + ], + ]; + + $options['Configuration Options'] = [ + 'encoding' => [ + 'argument' => '--encoding=', + 'description' => 'The encoding of the files being checked. Defaults to "utf-8".', + ], + 'tab-width' => [ + 'argument' => '--tab-width=', + 'description' => 'The number of spaces each tab represents.', + ], + 'blank-line' => ['spacer' => ''], + + 'config-explain' => [ + 'text' => 'Default values for a selection of options can be stored in a user-specific CodeSniffer.conf configuration file.'."\n" + .'This applies to the following options: "default_standard", "report_format", "tab_width", "encoding", "severity", "error_severity", "warning_severity", "show_warnings", "report_width", "show_progress", "quiet", "colors", "cache", "parallel", "installed_paths", "php_version", "ignore_errors_on_exit", "ignore_warnings_on_exit".', + ], + 'config-show' => [ + 'argument' => '--config-show', + 'description' => 'Show the configuration options which are currently stored in the applicable CodeSniffer.conf file.', + ], + 'config-set' => [ + 'argument' => '--config-set ', + 'description' => 'Save a configuration option to the CodeSniffer.conf file.', + ], + 'config-delete' => [ + 'argument' => '--config-delete ', + 'description' => 'Delete a configuration option from the CodeSniffer.conf file.', + ], + 'runtime-set' => [ + 'argument' => '--runtime-set ', + 'description' => 'Set a configuration option to be applied to the current scan run only.', + ], + ]; + + $options['Miscellaneous Options'] = [ + 'h' => [ + 'argument' => '-h, -?, --help', + 'description' => 'Print this help message.', + ], + 'version' => [ + 'argument' => '--version', + 'description' => 'Print version information.', + ], + 'v' => [ + 'argument' => '-v', + 'description' => 'Verbose output: Print processed files.', + ], + 'vv' => [ + 'argument' => '-vv', + 'description' => 'Verbose output: Print ruleset and token output.', + ], + 'vvv' => [ + 'argument' => '-vvv', + 'description' => 'Verbose output: Print sniff processing information.', + ], + ]; + // phpcs:enable + + return $options; + + }//end getAllOptions() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Util/MessageCollector.php b/app/vendor/squizlabs/php_codesniffer/src/Util/MessageCollector.php new file mode 100644 index 000000000..6db9414c1 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/src/Util/MessageCollector.php @@ -0,0 +1,310 @@ + + * @copyright 2025 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Util; + +use InvalidArgumentException; +use PHP_CodeSniffer\Exceptions\RuntimeException; + +final class MessageCollector +{ + + /** + * Indicator for a (blocking) error. + * + * @var int + */ + const ERROR = 1; + + /** + * Indicator for a warning. + * + * @var int + */ + const WARNING = 2; + + /** + * Indicator for a notice. + * + * @var int + */ + const NOTICE = 4; + + /** + * Indicator for a deprecation notice. + * + * @var int + */ + const DEPRECATED = 8; + + /** + * Indicator for ordering the messages based on severity first, order received second. + * + * @var string + */ + const ORDERBY_SEVERITY = 'severity'; + + /** + * Indicator for ordering the messages based on the order in which they were received. + * + * @var string + */ + const ORDERBY_RECEIVED = 'received'; + + /** + * Collected messages. + * + * @var array> The value for each array entry is an associative array + * which holds two keys: + * - 'message' string The message text. + * - 'type' int The type of the message based on the + * above declared error level constants. + */ + private $cache = []; + + + /** + * Add a new message. + * + * @param string $message The message text. + * @param int $type The type of message. Should be one of the following constants: + * MessageCollector::ERROR, MessageCollector::WARNING, MessageCollector::NOTICE + * or MessageCollector::DEPRECATED. + * Defaults to MessageCollector::NOTICE. + * + * @return void + * + * @throws \InvalidArgumentException If the message text is not a string. + * @throws \InvalidArgumentException If the message type is not one of the accepted types. + */ + public function add($message, $type=self::NOTICE) + { + if (is_string($message) === false) { + throw new InvalidArgumentException('The $message should be of type string. Received: '.gettype($message).'.'); + } + + if ($type !== self::ERROR + && $type !== self::WARNING + && $type !== self::NOTICE + && $type !== self::DEPRECATED + ) { + throw new InvalidArgumentException('The message $type should be one of the predefined MessageCollector constants. Received: '.$type.'.'); + } + + $this->cache[] = [ + 'message' => $message, + 'type' => $type, + ]; + + }//end add() + + + /** + * Determine whether or not the currently cached errors include blocking errors. + * + * @return bool + */ + public function containsBlockingErrors() + { + $seenTypes = $this->arrayColumn($this->cache, 'type'); + $typeFrequency = array_count_values($seenTypes); + return isset($typeFrequency[self::ERROR]); + + }//end containsBlockingErrors() + + + /** + * Display the cached messages. + * + * Displaying the messages will also clear the message cache. + * + * @param string $order Optional. The order in which to display the messages. + * Should be one of the following constants: MessageCollector::ORDERBY_SEVERITY, + * MessageCollector::ORDERBY_RECEIVED. + * Defaults to MessageCollector::ORDERBY_SEVERITY. + * + * @return void + * + * @throws \PHP_CodeSniffer\Exceptions\RuntimeException When there are blocking errors. + */ + public function display($order=self::ORDERBY_SEVERITY) + { + if ($this->cache === []) { + return; + } + + $blocking = $this->containsBlockingErrors(); + $messageInfo = $this->prefixAll($this->cache); + $this->clearCache(); + + if ($order === self::ORDERBY_RECEIVED) { + $messages = $this->arrayColumn($messageInfo, 'message'); + } else { + $messages = $this->sortBySeverity($messageInfo); + } + + $allMessages = implode(PHP_EOL, $messages).PHP_EOL.PHP_EOL; + + if ($blocking === true) { + throw new RuntimeException($allMessages); + } else { + echo $allMessages; + } + + }//end display() + + + /** + * Label all messages based on their type. + * + * @param array> $messages A multi-dimensional array of messages with their severity. + * + * @return array> + */ + private function prefixAll(array $messages) + { + foreach ($messages as $i => $details) { + $messages[$i]['message'] = $this->prefix($details['message'], $details['type']); + } + + return $messages; + + }//end prefixAll() + + + /** + * Add a message type prefix to a message. + * + * @param string $message The message text. + * @param int $type The type of message. + * + * @return string + */ + private function prefix($message, $type) + { + switch ($type) { + case self::ERROR: + $message = 'ERROR: '.$message; + break; + + case self::WARNING: + $message = 'WARNING: '.$message; + break; + + case self::DEPRECATED: + $message = 'DEPRECATED: '.$message; + break; + + default: + $message = 'NOTICE: '.$message; + break; + } + + return $message; + + }//end prefix() + + + /** + * Sort an array of messages by severity. + * + * @param array> $messages A multi-dimensional array of messages with their severity. + * + * @return array A single dimensional array of only messages, sorted by severity. + */ + private function sortBySeverity(array $messages) + { + if (count($messages) === 1) { + return [$messages[0]['message']]; + } + + $errors = []; + $warnings = []; + $notices = []; + $deprecations = []; + + foreach ($messages as $details) { + switch ($details['type']) { + case self::ERROR: + $errors[] = $details['message']; + break; + + case self::WARNING: + $warnings[] = $details['message']; + break; + + case self::DEPRECATED: + $deprecations[] = $details['message']; + break; + + default: + $notices[] = $details['message']; + break; + } + } + + return array_merge($errors, $warnings, $notices, $deprecations); + + }//end sortBySeverity() + + + /** + * Clear the message cache. + * + * @return void + */ + private function clearCache() + { + $this->cache = []; + + }//end clearCache() + + + /** + * Return the values from a single column in the input array. + * + * Polyfill for the PHP 5.5+ native array_column() function (for the functionality needed here). + * + * @param array> $input A multi-dimensional array from which to pull a column of values. + * @param string $columnKey The name of the column of values to return. + * + * @link https://www.php.net/function.array-column + * + * @return array + */ + private function arrayColumn(array $input, $columnKey) + { + if (function_exists('array_column') === true) { + // PHP 5.5+. + return array_column($input, $columnKey); + } + + // PHP 5.4. + $callback = function ($row) use ($columnKey) { + return $row[$columnKey]; + }; + + return array_map($callback, $input); + + }//end arrayColumn() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/src/Util/Standards.php b/app/vendor/squizlabs/php_codesniffer/src/Util/Standards.php index ca1060bc9..527f5b792 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Util/Standards.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Util/Standards.php @@ -9,6 +9,7 @@ namespace PHP_CodeSniffer\Util; +use DirectoryIterator; use PHP_CodeSniffer\Config; class Standards @@ -35,7 +36,7 @@ public static function getInstalledStandardPaths() $resolvedInstalledPaths = []; foreach ($installedPaths as $installedPath) { if (substr($installedPath, 0, 1) === '.') { - $installedPath = Common::realPath(__DIR__.$ds.'..'.$ds.'..'.$ds.$installedPath); + $installedPath = Common::realpath(__DIR__.$ds.'..'.$ds.'..'.$ds.$installedPath); if ($installedPath === false) { continue; } @@ -99,7 +100,7 @@ public static function getInstalledStandardDetails( continue; } - $di = new \DirectoryIterator($standardsDir); + $di = new DirectoryIterator($standardsDir); foreach ($di as $file) { if ($file->isDir() === true && $file->isDot() === false) { $filename = $file->getFilename(); @@ -190,7 +191,7 @@ public static function getInstalledStandards( continue; } - $di = new \DirectoryIterator($standardsDir); + $di = new DirectoryIterator($standardsDir); $standardsInDir = []; foreach ($di as $file) { if ($file->isDir() === true && $file->isDot() === false) { @@ -238,7 +239,7 @@ public static function isInstalledStandard($standard) } else { // This could be a custom standard, installed outside our // standards directory. - $standard = Common::realPath($standard); + $standard = Common::realpath($standard); if ($standard === false) { return false; } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Util/Timing.php b/app/vendor/squizlabs/php_codesniffer/src/Util/Timing.php index 57470c77a..95f6810b3 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Util/Timing.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Util/Timing.php @@ -13,7 +13,21 @@ class Timing { /** - * The start time of the run. + * Number of milliseconds in a minute. + * + * @var int + */ + const MINUTE_IN_MS = 60000; + + /** + * Number of milliseconds in a second. + * + * @var int + */ + const SECOND_IN_MS = 1000; + + /** + * The start time of the run in microseconds. * * @var float */ @@ -43,7 +57,7 @@ public static function startTiming() /** * Get the duration of the run up to "now". * - * @return float Duration in microseconds. + * @return float Duration in milliseconds. */ public static function getDuration() { @@ -58,24 +72,24 @@ public static function getDuration() /** - * Convert a duration in microseconds to a human readable duration string. + * Convert a duration in milliseconds to a human readable duration string. * - * @param float $duration Duration in microseconds. + * @param float $duration Duration in milliseconds. * * @return string */ public static function getHumanReadableDuration($duration) { $timeString = ''; - if ($duration > 60000) { - $mins = floor($duration / 60000); - $secs = round((fmod($duration, 60000) / 1000), 2); + if ($duration >= self::MINUTE_IN_MS) { + $mins = floor($duration / self::MINUTE_IN_MS); + $secs = round((fmod($duration, self::MINUTE_IN_MS) / self::SECOND_IN_MS), 2); $timeString = $mins.' mins'; - if ($secs !== 0) { + if ($secs >= 0.01) { $timeString .= ", $secs secs"; } - } else if ($duration > 1000) { - $timeString = round(($duration / 1000), 2).' secs'; + } else if ($duration >= self::SECOND_IN_MS) { + $timeString = round(($duration / self::SECOND_IN_MS), 2).' secs'; } else { $timeString = round($duration).'ms'; } diff --git a/app/vendor/squizlabs/php_codesniffer/src/Util/Tokens.php b/app/vendor/squizlabs/php_codesniffer/src/Util/Tokens.php index ab70e7832..525b5b632 100644 --- a/app/vendor/squizlabs/php_codesniffer/src/Util/Tokens.php +++ b/app/vendor/squizlabs/php_codesniffer/src/Util/Tokens.php @@ -82,6 +82,13 @@ define('T_ATTRIBUTE_END', 'PHPCS_T_ATTRIBUTE_END'); define('T_ENUM_CASE', 'PHPCS_T_ENUM_CASE'); define('T_TYPE_INTERSECTION', 'PHPCS_T_TYPE_INTERSECTION'); +define('T_TYPE_OPEN_PARENTHESIS', 'PHPCS_T_TYPE_OPEN_PARENTHESIS'); +define('T_TYPE_CLOSE_PARENTHESIS', 'PHPCS_T_TYPE_CLOSE_PARENTHESIS'); + +/* + * {@internal IMPORTANT: all PHP native polyfilled tokens MUST be added to the + * `PHP_CodeSniffer\Tests\Core\Util\Tokens\TokenNameTest::dataPolyfilledPHPNativeTokens()` test method!} + */ // Some PHP 5.5 tokens, replicated for lower versions. if (defined('T_FINALLY') === false) { @@ -173,6 +180,19 @@ define('T_ENUM', 'PHPCS_T_ENUM'); } +// Some PHP 8.4 tokens, replicated for lower versions. +if (defined('T_PUBLIC_SET') === false) { + define('T_PUBLIC_SET', 'PHPCS_T_PUBLIC_SET'); +} + +if (defined('T_PROTECTED_SET') === false) { + define('T_PROTECTED_SET', 'PHPCS_T_PROTECTED_SET'); +} + +if (defined('T_PRIVATE_SET') === false) { + define('T_PRIVATE_SET', 'PHPCS_T_PRIVATE_SET'); +} + // Tokens used for parsing doc blocks. define('T_DOC_COMMENT_STAR', 'PHPCS_T_DOC_COMMENT_STAR'); define('T_DOC_COMMENT_WHITESPACE', 'PHPCS_T_DOC_COMMENT_WHITESPACE'); @@ -456,9 +476,12 @@ final class Tokens * @var array */ public static $scopeModifiers = [ - T_PRIVATE => T_PRIVATE, - T_PUBLIC => T_PUBLIC, - T_PROTECTED => T_PROTECTED, + T_PRIVATE => T_PRIVATE, + T_PUBLIC => T_PUBLIC, + T_PROTECTED => T_PROTECTED, + T_PUBLIC_SET => T_PUBLIC_SET, + T_PROTECTED_SET => T_PROTECTED_SET, + T_PRIVATE_SET => T_PRIVATE_SET, ]; /** @@ -745,13 +768,13 @@ final class Tokens /** - * Given a token, returns the name of the token. + * Given a token constant, returns the name of the token. * * If passed an integer, the token name is sourced from PHP's token_name() * function. If passed a string, it is assumed to be a PHPCS-supplied token * that begins with PHPCS_T_, so the name is sourced from the token value itself. * - * @param int|string $token The token to get the name for. + * @param int|string $token The token constant to get the name for. * * @return string */ @@ -775,12 +798,14 @@ public static function tokenName($token) * For example T_CLASS tokens appear very infrequently in a file, and * therefore have a high weighting. * - * Returns false if there are no weightings for any of the specified tokens. + * If there are no weightings for any of the specified tokens, the first token + * seen in the passed array will be returned. * * @param array $tokens The token types to get the highest weighted * type for. * - * @return int|false The highest weighted token. + * @return int The highest weighted token. + * On equal "weight", returns the first token of that particular weight. */ public static function getHighestWeightedToken(array $tokens) { diff --git a/app/vendor/squizlabs/php_codesniffer/tests/ConfigDouble.php b/app/vendor/squizlabs/php_codesniffer/tests/ConfigDouble.php index 190f75ece..8ebce0585 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/ConfigDouble.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/ConfigDouble.php @@ -41,7 +41,7 @@ final class ConfigDouble extends Config * the ruleset auto-discovery. * Note: there is no need to set this to `true` when a standard * is being passed via the `$cliArgs`. Those settings will always - * respected. + * be respected. * Defaults to `false`. Will result in the standard being set * to "PSR1" if not provided via `$cliArgs`. * @param bool $skipSettingReportWidth Whether to skip setting a report-width to prevent @@ -72,6 +72,22 @@ public function __construct(array $cliArgs=[], $skipSettingStandard=false, $skip }//end __construct() + /** + * Ensures the static properties in the Config class are reset to their default values + * when the ConfigDouble is no longer used. + * + * @return void + */ + public function __destruct() + { + $this->setStaticConfigProperty('overriddenDefaults', []); + $this->setStaticConfigProperty('executablePaths', []); + $this->setStaticConfigProperty('configData', null); + $this->setStaticConfigProperty('configDataFile', null); + + }//end __destruct() + + /** * Sets the command line values and optionally prevents a file system search for a custom ruleset. * diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/AbstractMethodUnitTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/AbstractMethodUnitTest.php index b8522bf4b..8a25016f0 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/AbstractMethodUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/AbstractMethodUnitTest.php @@ -9,9 +9,10 @@ namespace PHP_CodeSniffer\Tests\Core; -use PHP_CodeSniffer\Ruleset; +use Exception; use PHP_CodeSniffer\Files\DummyFile; use PHP_CodeSniffer\Files\File; +use PHP_CodeSniffer\Ruleset; use PHP_CodeSniffer\Tests\ConfigDouble; use PHPUnit\Framework\TestCase; @@ -57,7 +58,8 @@ abstract class AbstractMethodUnitTest extends TestCase */ public static function initializeFile() { - $config = new ConfigDouble(); + $_SERVER['argv'] = []; + $config = new ConfigDouble(); // Also set a tab-width to enable testing tab-replaced vs `orig_content`. $config->tabWidth = static::$tabWidth; @@ -73,20 +75,98 @@ public static function initializeFile() $contents .= file_get_contents($pathToTestFile); self::$phpcsFile = new DummyFile($contents, $ruleset, $config); - self::$phpcsFile->process(); + self::$phpcsFile->parse(); }//end initializeFile() + /** + * Clean up after finished test by resetting all static properties on the class to their default values. + * + * Note: This is a PHPUnit cross-version compatible {@see \PHPUnit\Framework\TestCase::tearDownAfterClass()} + * method. + * + * @afterClass + * + * @return void + */ + public static function reset() + { + // Explicitly trigger __destruct() on the ConfigDouble to reset the Config statics. + // The explicit method call prevents potential stray test-local references to the $config object + // preventing the destructor from running the clean up (which without stray references would be + // automagically triggered when `self::$phpcsFile` is reset, but we can't definitively rely on that). + if (isset(self::$phpcsFile) === true) { + self::$phpcsFile->config->__destruct(); + } + + self::$fileExtension = 'inc'; + self::$tabWidth = 4; + self::$phpcsFile = null; + + }//end reset() + + + /** + * Test QA: verify that a test case file does not contain any duplicate test markers. + * + * When a test case file contains a lot of test cases, it is easy to overlook that a test marker name + * is already in use. + * A test wouldn't necessarily fail on this, but would not be testing what is intended to be tested as + * it would be verifying token properties for the wrong token. + * + * This test safeguards against this. + * + * @coversNothing + * + * @return void + */ + public function testTestMarkersAreUnique() + { + $this->assertTestMarkersAreUnique(self::$phpcsFile); + + }//end testTestMarkersAreUnique() + + + /** + * Assertion to verify that a test case file does not contain any duplicate test markers. + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file to validate. + * + * @return void + */ + public static function assertTestMarkersAreUnique(File $phpcsFile) + { + $tokens = $phpcsFile->getTokens(); + + // Collect all marker comments in the file. + $seenComments = []; + for ($i = 0; $i < $phpcsFile->numTokens; $i++) { + if ($tokens[$i]['code'] !== T_COMMENT) { + continue; + } + + if (stripos($tokens[$i]['content'], '/* test') !== 0) { + continue; + } + + $seenComments[] = $tokens[$i]['content']; + } + + self::assertSame(array_unique($seenComments), $seenComments, 'Duplicate test markers found.'); + + }//end assertTestMarkersAreUnique() + + /** * Get the token pointer for a target token based on a specific comment found on the line before. * * Note: the test delimiter comment MUST start with "/* test" to allow this function to * distinguish between comments used *in* a test and test delimiters. * - * @param string $commentString The delimiter comment to look for. - * @param int|string|array $tokenType The type of token(s) to look for. - * @param string $tokenContent Optional. The token content for the target token. + * @param string $commentString The delimiter comment to look for. + * @param int|string|array $tokenType The type of token(s) to look for. + * @param string $tokenContent Optional. The token content for the target token. * * @return int */ @@ -103,12 +183,15 @@ public function getTargetToken($commentString, $tokenType, $tokenContent=null) * Note: the test delimiter comment MUST start with "/* test" to allow this function to * distinguish between comments used *in* a test and test delimiters. * - * @param \PHP_CodeSniffer\Files\File $phpcsFile The file to find the token in. - * @param string $commentString The delimiter comment to look for. - * @param int|string|array $tokenType The type of token(s) to look for. - * @param string $tokenContent Optional. The token content for the target token. + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file to find the token in. + * @param string $commentString The delimiter comment to look for. + * @param int|string|array $tokenType The type of token(s) to look for. + * @param string $tokenContent Optional. The token content for the target token. * * @return int + * + * @throws \Exception When the test delimiter comment is not found. + * @throws \Exception When the test target token is not found. */ public static function getTargetTokenFromFile(File $phpcsFile, $commentString, $tokenType, $tokenContent=null) { @@ -121,6 +204,12 @@ public static function getTargetTokenFromFile(File $phpcsFile, $commentString, $ $commentString ); + if ($comment === false) { + throw new Exception( + sprintf('Failed to find the test marker: %s in test case file %s', $commentString, $phpcsFile->getFilename()) + ); + } + $tokens = $phpcsFile->getTokens(); $end = ($start + 1); @@ -147,10 +236,10 @@ public static function getTargetTokenFromFile(File $phpcsFile, $commentString, $ if ($target === false) { $msg = 'Failed to find test target token for comment string: '.$commentString; if ($tokenContent !== null) { - $msg .= ' With token content: '.$tokenContent; + $msg .= ' with token content: '.$tokenContent; } - self::assertFalse(true, $msg); + throw new Exception($msg); } return $target; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/AllTests.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/AllTests.php index 60547bb36..a5465f987 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/AllTests.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/AllTests.php @@ -11,8 +11,8 @@ namespace PHP_CodeSniffer\Tests\Core; use PHP_CodeSniffer\Tests\FileList; -use PHPUnit\TextUI\TestRunner; use PHPUnit\Framework\TestSuite; +use PHPUnit\TextUI\TestRunner; class AllTests { diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Autoloader/DetermineLoadedClassTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Autoloader/DetermineLoadedClassTest.php index ea40a5402..e719c7eb7 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Autoloader/DetermineLoadedClassTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Autoloader/DetermineLoadedClassTest.php @@ -60,7 +60,7 @@ public function testOrdered() ]; $className = Autoload::determineLoadedClass($classesBeforeLoad, $classesAfterLoad); - $this->assertEquals('PHP_CodeSniffer\Tests\Core\Autoloader\Sub\C', $className); + $this->assertSame('PHP_CodeSniffer\Tests\Core\Autoloader\Sub\C', $className); }//end testOrdered() @@ -90,7 +90,7 @@ public function testUnordered() ]; $className = Autoload::determineLoadedClass($classesBeforeLoad, $classesAfterLoad); - $this->assertEquals('PHP_CodeSniffer\Tests\Core\Autoloader\Sub\C', $className); + $this->assertSame('PHP_CodeSniffer\Tests\Core\Autoloader\Sub\C', $className); $classesAfterLoad = [ 'classes' => [ @@ -104,7 +104,7 @@ public function testUnordered() ]; $className = Autoload::determineLoadedClass($classesBeforeLoad, $classesAfterLoad); - $this->assertEquals('PHP_CodeSniffer\Tests\Core\Autoloader\Sub\C', $className); + $this->assertSame('PHP_CodeSniffer\Tests\Core\Autoloader\Sub\C', $className); $classesAfterLoad = [ 'classes' => [ @@ -118,7 +118,7 @@ public function testUnordered() ]; $className = Autoload::determineLoadedClass($classesBeforeLoad, $classesAfterLoad); - $this->assertEquals('PHP_CodeSniffer\Tests\Core\Autoloader\Sub\C', $className); + $this->assertSame('PHP_CodeSniffer\Tests\Core\Autoloader\Sub\C', $className); }//end testUnordered() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/AbstractRealConfigTestCase.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/AbstractRealConfigTestCase.php new file mode 100644 index 000000000..6f5cd8844 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/AbstractRealConfigTestCase.php @@ -0,0 +1,92 @@ +setAccessible(true); + $property->setValue(null, $value); + $property->setAccessible(false); + + }//end setStaticConfigProperty() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/ExtensionsArgTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/ExtensionsArgTest.php new file mode 100644 index 000000000..e63b1fef9 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/ExtensionsArgTest.php @@ -0,0 +1,128 @@ +assertSame($expected, $config->extensions); + + }//end testValidExtensions() + + + /** + * Data provider. + * + * @see self::testValidExtensions() + * + * @return array>> + */ + public static function dataValidExtensions() + { + return [ + // Passing an empty extensions list is not useful, as it will result in no files being scanned, + // but that's the responsibility of the user. + 'Empty extensions list' => [ + 'passedValue' => '', + 'expected' => [], + ], + 'Single extension passed: php' => [ + 'passedValue' => 'php', + 'expected' => [ + 'php' => 'PHP', + ], + ], + // This would cause PHPCS to scan python files as PHP, which will probably cause very weird scan results, + // but that's the responsibility of the user. + 'Single extension passed: py' => [ + 'passedValue' => 'py', + 'expected' => [ + 'py' => 'PHP', + ], + ], + // This would likely result in a problem when PHPCS can't find a "PY" tokenizer class, + // but that's not our concern at this moment. Support for non-PHP tokenizers is being dropped soon anyway. + 'Single extension passed with language: py/py' => [ + 'passedValue' => 'py/py', + 'expected' => [ + 'py' => 'PY', + ], + ], + 'Multiple extensions passed: php,js,css' => [ + 'passedValue' => 'php,js,css', + 'expected' => [ + 'php' => 'PHP', + 'js' => 'JS', + 'css' => 'CSS', + ], + ], + 'Multiple extensions passed, some with language: php,inc/php,phpt/php,js' => [ + 'passedValue' => 'php,inc/php,phpt/php,js', + 'expected' => [ + 'php' => 'PHP', + 'inc' => 'PHP', + 'phpt' => 'PHP', + 'js' => 'JS', + ], + ], + 'File extensions are set case sensitively (and filtering is case sensitive too)' => [ + 'passedValue' => 'PHP,php', + 'expected' => [ + 'PHP' => 'PHP', + 'php' => 'PHP', + ], + ], + ]; + + }//end dataValidExtensions() + + + /** + * Ensure that only the first argument is processed and others are ignored. + * + * @return void + */ + public function testOnlySetOnce() + { + $config = new ConfigDouble( + [ + '--extensions=php', + '--extensions=inc,module', + ] + ); + + $this->assertSame(['php' => 'PHP'], $config->extensions); + + }//end testOnlySetOnce() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/GeneratorArgTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/GeneratorArgTest.php new file mode 100644 index 000000000..12fe1c66f --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/GeneratorArgTest.php @@ -0,0 +1,163 @@ +markTestSkipped('The `--generator` CLI flag is only supported for the `phpcs` command'); + } + + }//end maybeSkipTests() + + + /** + * Ensure that the generator property is set when the parameter is passed a valid value. + * + * @param string $argumentValue Generator name passed on the command line. + * @param string $expectedPropertyValue Expected value of the generator property. + * + * @dataProvider dataValidGeneratorNames + * + * @return void + */ + public function testValidGenerators($argumentValue, $expectedPropertyValue) + { + $config = new ConfigDouble(["--generator=$argumentValue"]); + + $this->assertSame($expectedPropertyValue, $config->generator); + + }//end testValidGenerators() + + + /** + * Data provider for testValidGenerators(). + * + * @see self::testValidGenerators() + * + * @return array> + */ + public static function dataValidGeneratorNames() + { + return [ + 'Text generator passed' => [ + 'argumentValue' => 'Text', + 'expectedPropertyValue' => 'Text', + ], + 'HTML generator passed' => [ + 'argumentValue' => 'HTML', + 'expectedPropertyValue' => 'HTML', + ], + 'Markdown generator passed' => [ + 'argumentValue' => 'Markdown', + 'expectedPropertyValue' => 'Markdown', + ], + 'Uppercase Text generator passed' => [ + 'argumentValue' => 'TEXT', + 'expectedPropertyValue' => 'Text', + ], + 'Mixed case Text generator passed' => [ + 'argumentValue' => 'tEXt', + 'expectedPropertyValue' => 'Text', + ], + 'Lowercase HTML generator passed' => [ + 'argumentValue' => 'html', + 'expectedPropertyValue' => 'HTML', + ], + ]; + + }//end dataValidGeneratorNames() + + + /** + * Ensure that only the first argument is processed and others are ignored. + * + * @return void + */ + public function testOnlySetOnce() + { + $config = new ConfigDouble( + [ + '--generator=Text', + '--generator=HTML', + '--generator=InvalidGenerator', + ] + ); + + $this->assertSame('Text', $config->generator); + + }//end testOnlySetOnce() + + + /** + * Ensure that an exception is thrown for an invalid generator. + * + * @param string $generatorName Generator name. + * + * @dataProvider dataInvalidGeneratorNames + * + * @return void + */ + public function testInvalidGenerator($generatorName) + { + $exception = 'PHP_CodeSniffer\Exceptions\DeepExitException'; + $message = 'ERROR: "'.$generatorName.'" is not a valid generator. The following generators are supported: Text, HTML and Markdown.'; + + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException($exception); + $this->expectExceptionMessage($message); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $message); + } + + new ConfigDouble(["--generator={$generatorName}"]); + + }//end testInvalidGenerator() + + + /** + * Data provider for testInvalidGenerator(). + * + * @see self::testInvalidGenerator() + * + * @return array> + */ + public static function dataInvalidGeneratorNames() + { + return [ + ['InvalidGenerator'], + ['Text,HTML'], + [''], + ]; + + }//end dataInvalidGeneratorNames() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/ReportArgsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/ReportArgsTest.php new file mode 100644 index 000000000..60b5a7c46 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/ReportArgsTest.php @@ -0,0 +1,64 @@ +markTestSkipped('This test needs CS mode to run'); + } + + $config = new ConfigDouble(['--report-file='.__DIR__.'/report.txt']); + + $this->assertTrue(is_string($config->reportFile)); + $this->assertStringEndsWith('/report.txt', $config->reportFile); + $this->assertSame(['full' => null], $config->reports); + + }//end testReportFileDoesNotSetReportsCs() + + + /** + * [CBF mode] Verify that passing `--report-file` does not influence *which* reports get activated. + * + * @group CBF + * + * @return void + */ + public function testReportFileDoesNotSetReportsCbf() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $config = new ConfigDouble(['--report-file='.__DIR__.'/report.txt']); + + $this->assertNull($config->reportFile); + $this->assertSame(['full' => null], $config->reports); + + }//end testReportFileDoesNotSetReportsCbf() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/ReportWidthTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/ReportWidthTest.php index 2e67fa269..28b996228 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/ReportWidthTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/ReportWidthTest.php @@ -10,74 +10,17 @@ namespace PHP_CodeSniffer\Tests\Core\Config; use PHP_CodeSniffer\Config; -use PHPUnit\Framework\TestCase; -use ReflectionProperty; +use PHP_CodeSniffer\Tests\Core\Config\AbstractRealConfigTestCase; /** * Tests for the \PHP_CodeSniffer\Config reportWidth value. * * @covers \PHP_CodeSniffer\Config::__get */ -final class ReportWidthTest extends TestCase +final class ReportWidthTest extends AbstractRealConfigTestCase { - /** - * Set static properties in the Config class to prevent tests influencing each other. - * - * @before - * - * @return void - */ - public static function cleanConfig() - { - // Set to the property's default value to clear out potentially set values from other tests. - self::setStaticProperty('executablePaths', []); - - // Set to a usable value to circumvent Config trying to find a phpcs.xml config file. - self::setStaticProperty('overriddenDefaults', ['standards' => ['PSR1']]); - - // Set to values which prevent the test-runner user's `CodeSniffer.conf` file - // from being read and influencing the tests. - self::setStaticProperty('configData', []); - self::setStaticProperty('configDataFile', ''); - - }//end cleanConfig() - - - /** - * Clean up after each finished test. - * - * @after - * - * @return void - */ - public function resetConfig() - { - $_SERVER['argv'] = []; - - }//end resetConfig() - - - /** - * Reset the static properties in the Config class to their true defaults to prevent this class - * from influencing other tests. - * - * @afterClass - * - * @return void - */ - public static function resetConfigToDefaults() - { - self::setStaticProperty('overriddenDefaults', []); - self::setStaticProperty('executablePaths', []); - self::setStaticProperty('configData', null); - self::setStaticProperty('configDataFile', null); - $_SERVER['argv'] = []; - - }//end resetConfigToDefaults() - - /** * Test that report width without overrules will always be set to a non-0 positive integer. * @@ -88,7 +31,7 @@ public static function resetConfigToDefaults() */ public function testReportWidthDefault() { - $config = new Config(); + $config = new Config(['--standard=PSR1']); // Can't test the exact value as "auto" will resolve differently depending on the machine running the tests. $this->assertTrue(is_int($config->reportWidth), 'Report width is not an integer'); @@ -112,9 +55,9 @@ public function testReportWidthWillBeSetFromAutoWhenNotFoundInConfFile() 'show_warnings' => '0', ]; - $this->setStaticProperty('configData', $phpCodeSnifferConfig); + $this->setStaticConfigProperty('configData', $phpCodeSnifferConfig); - $config = new Config(); + $config = new Config(['--standard=PSR1']); // Can't test the exact value as "auto" will resolve differently depending on the machine running the tests. $this->assertTrue(is_int($config->reportWidth), 'Report width is not an integer'); @@ -139,9 +82,9 @@ public function testReportWidthCanBeSetFromConfFile() 'report_width' => '120', ]; - $this->setStaticProperty('configData', $phpCodeSnifferConfig); + $this->setStaticConfigProperty('configData', $phpCodeSnifferConfig); - $config = new Config(); + $config = new Config(['--standard=PSR1']); $this->assertSame(120, $config->reportWidth); }//end testReportWidthCanBeSetFromConfFile() @@ -159,6 +102,7 @@ public function testReportWidthCanBeSetFromCLI() { $_SERVER['argv'] = [ 'phpcs', + '--standard=PSR1', '--report-width=100', ]; @@ -180,6 +124,7 @@ public function testReportWidthWhenSetFromCLIFirstValuePrevails() { $_SERVER['argv'] = [ 'phpcs', + '--standard=PSR1', '--report-width=100', '--report-width=200', ]; @@ -209,10 +154,11 @@ public function testReportWidthSetFromCLIOverrulesConfFile() 'report_width' => '120', ]; - $this->setStaticProperty('configData', $phpCodeSnifferConfig); + $this->setStaticConfigProperty('configData', $phpCodeSnifferConfig); $cliArgs = [ 'phpcs', + '--standard=PSR1', '--report-width=180', ]; @@ -231,7 +177,7 @@ public function testReportWidthSetFromCLIOverrulesConfFile() */ public function testReportWidthInputHandlingForAuto() { - $config = new Config(); + $config = new Config(['--standard=PSR1']); $config->reportWidth = 'auto'; // Can't test the exact value as "auto" will resolve differently depending on the machine running the tests. @@ -244,7 +190,7 @@ public function testReportWidthInputHandlingForAuto() /** * Test that the report width will be set correctly for various types of input. * - * @param mixed $input Input value received. + * @param mixed $value Input value received. * @param int $expected Expected report width. * * @dataProvider dataReportWidthInputHandling @@ -252,10 +198,10 @@ public function testReportWidthInputHandlingForAuto() * * @return void */ - public function testReportWidthInputHandling($input, $expected) + public function testReportWidthInputHandling($value, $expected) { - $config = new Config(); - $config->reportWidth = $input; + $config = new Config(['--standard=PSR1']); + $config->reportWidth = $value; $this->assertSame($expected, $config->reportWidth); @@ -311,22 +257,4 @@ public static function dataReportWidthInputHandling() }//end dataReportWidthInputHandling() - /** - * Helper function to set a static property on the Config class. - * - * @param string $name The name of the property to set. - * @param mixed $value The value to set the property to. - * - * @return void - */ - public static function setStaticProperty($name, $value) - { - $property = new ReflectionProperty('PHP_CodeSniffer\Config', $name); - $property->setAccessible(true); - $property->setValue(null, $value); - $property->setAccessible(false); - - }//end setStaticProperty() - - }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/SniffsExcludeArgsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/SniffsExcludeArgsTest.php new file mode 100644 index 000000000..18b877c42 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Config/SniffsExcludeArgsTest.php @@ -0,0 +1,327 @@ + + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Config; + +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Config --sniffs and --exclude arguments. + * + * @covers \PHP_CodeSniffer\Config::parseSniffCodes + * @covers \PHP_CodeSniffer\Config::processLongArgument + */ +final class SniffsExcludeArgsTest extends TestCase +{ + + + /** + * Ensure that the expected error message is returned for invalid arguments. + * + * @param string $argument 'sniffs' or 'exclude'. + * @param string $value List of sniffs to include / exclude. + * @param array $errors Sniff code and associated help text. + * @param string|null $suggestion Help text shown to end user with correct syntax for argument. + * + * @return void + * @dataProvider dataInvalid + */ + public function testInvalid($argument, $value, $errors, $suggestion) + { + $cmd = 'phpcs'; + if (PHP_CODESNIFFER_CBF === true) { + $cmd = 'phpcbf'; + } + + $exception = 'PHP_CodeSniffer\Exceptions\DeepExitException'; + $message = 'ERROR: The --'.$argument.' option only supports sniff codes.'.PHP_EOL; + $message .= 'Sniff codes are in the form "Standard.Category.Sniff".'.PHP_EOL; + $message .= PHP_EOL; + $message .= 'The following problems were detected:'.PHP_EOL; + $message .= '* '.implode(PHP_EOL.'* ', $errors).PHP_EOL; + + if ($suggestion !== null) { + $message .= PHP_EOL; + $message .= "Perhaps try --$argument=\"$suggestion\" instead.".PHP_EOL; + } + + $message .= PHP_EOL; + $message .= "Run \"{$cmd} --help\" for usage information".PHP_EOL; + $message .= PHP_EOL; + + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException($exception); + $this->expectExceptionMessage($message); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $message); + } + + new ConfigDouble(["--$argument=$value"]); + + }//end testInvalid() + + + /** + * Data provider for testInvalid(). + * + * @see self::testInvalid() + * @return array|string|null>> + */ + public static function dataInvalid() + { + $arguments = [ + 'sniffs', + 'exclude', + ]; + $data = []; + + foreach ($arguments as $argument) { + // Empty values are errors. + $data[$argument.'; empty string'] = [ + 'argument' => $argument, + 'value' => '', + 'errors' => [ + 'No codes specified / empty argument', + ], + 'suggestion' => null, + ]; + $data[$argument.'; one comma alone'] = [ + 'argument' => $argument, + 'value' => ',', + 'errors' => [ + 'No codes specified / empty argument', + ], + 'suggestion' => null, + ]; + $data[$argument.'; two commas alone'] = [ + 'argument' => $argument, + 'value' => ',,', + 'errors' => [ + 'No codes specified / empty argument', + ], + 'suggestion' => null, + ]; + + // A standard is not a valid sniff. + $data[$argument.'; standard'] = [ + 'argument' => $argument, + 'value' => 'Standard', + 'errors' => [ + 'Standard codes are not supported: Standard', + ], + 'suggestion' => null, + ]; + + // A category is not a valid sniff. + $data[$argument.'; category'] = [ + 'argument' => $argument, + 'value' => 'Standard.Category', + 'errors' => [ + 'Category codes are not supported: Standard.Category', + ], + 'suggestion' => null, + ]; + + // An error-code is not a valid sniff. + $data[$argument.'; error-code'] = [ + 'argument' => $argument, + 'value' => 'Standard.Category.Sniff.Code', + 'errors' => [ + 'Message codes are not supported: Standard.Category.Sniff.Code', + ], + 'suggestion' => 'Standard.Category.Sniff', + ]; + + // Too many dots. + $data[$argument.'; too many dots'] = [ + 'argument' => $argument, + 'value' => 'Standard.Category.Sniff.Code.Extra', + 'errors' => [ + 'Too many parts: Standard.Category.Sniff.Code.Extra', + ], + 'suggestion' => 'Standard.Category.Sniff', + ]; + + // All errors are reported in one go. + $data[$argument.'; two errors'] = [ + 'argument' => $argument, + 'value' => 'StandardOne,StandardTwo', + 'errors' => [ + 'Standard codes are not supported: StandardOne', + 'Standard codes are not supported: StandardTwo', + ], + 'suggestion' => null, + ]; + + // Order of valid/invalid does not impact error reporting. + $data[$argument.'; valid followed by invalid'] = [ + 'argument' => $argument, + 'value' => 'StandardOne.Category.Sniff,StandardTwo.Category', + 'errors' => [ + 'Category codes are not supported: StandardTwo.Category', + ], + 'suggestion' => 'StandardOne.Category.Sniff', + ]; + $data[$argument.'; invalid followed by valid'] = [ + 'argument' => $argument, + 'value' => 'StandardOne.Category,StandardTwo.Category.Sniff', + 'errors' => [ + 'Category codes are not supported: StandardOne.Category', + ], + 'suggestion' => 'StandardTwo.Category.Sniff', + ]; + + // Different cases are reported individually (in duplicate), but suggestions are reduced. + $data[$argument.'; case mismatch - different errors'] = [ + 'argument' => $argument, + 'value' => 'Standard.Category.Sniff.Code,sTANDARD.cATEGORY.sNIFF.cODE.eXTRA', + 'errors' => [ + 'Message codes are not supported: Standard.Category.Sniff.Code', + 'Too many parts: sTANDARD.cATEGORY.sNIFF.cODE.eXTRA', + ], + 'suggestion' => 'Standard.Category.Sniff', + ]; + $data[$argument.'; case mismatch - same error'] = [ + 'argument' => $argument, + 'value' => 'sTANDARD.cATEGORY.sNIFF.cODE,Standard.Category.Sniff.Code', + 'errors' => [ + 'Message codes are not supported: sTANDARD.cATEGORY.sNIFF.cODE', + 'Message codes are not supported: Standard.Category.Sniff.Code', + ], + 'suggestion' => 'sTANDARD.cATEGORY.sNIFF', + ]; + }//end foreach + + return $data; + + }//end dataInvalid() + + + /** + * Ensure that the valid data does not throw an exception, and the value is stored. + * + * @param string $argument 'sniffs' or 'exclude'. + * @param string $value List of sniffs to include or exclude. + * @param array $result Expected sniffs to be set on the Config object. + * + * @return void + * @dataProvider dataValid + */ + public function testValid($argument, $value, $result) + { + $config = new ConfigDouble(["--$argument=$value"]); + + $this->assertSame($result, $config->$argument); + + }//end testValid() + + + /** + * Data provider for testValid(). + * + * @see self::testValid() + * @return array|string>> + */ + public static function dataValid() + { + $arguments = [ + 'sniffs', + 'exclude', + ]; + $data = []; + + foreach ($arguments as $argument) { + $data[$argument.'; one valid sniff'] = [ + 'argument' => $argument, + 'value' => 'Standard.Category.Sniff', + 'result' => ['Standard.Category.Sniff'], + ]; + $data[$argument.'; two valid sniffs'] = [ + 'argument' => $argument, + 'value' => 'StandardOne.Category.Sniff,StandardTwo.Category.Sniff', + 'result' => [ + 'StandardOne.Category.Sniff', + 'StandardTwo.Category.Sniff', + ], + ]; + + // Rogue commas are quietly ignored. + $data[$argument.'; trailing comma'] = [ + 'argument' => $argument, + 'value' => 'Standard.Category.Sniff,', + 'result' => ['Standard.Category.Sniff'], + ]; + $data[$argument.'; double comma between sniffs'] = [ + 'argument' => $argument, + 'value' => 'StandardOne.Category.Sniff,,StandardTwo.Category.Sniff', + 'result' => [ + 'StandardOne.Category.Sniff', + 'StandardTwo.Category.Sniff', + ], + ]; + + // Duplicates are reduced silently. + $data[$argument.'; one valid sniff twice'] = [ + 'argument' => $argument, + 'value' => 'Standard.Category.Sniff,Standard.Category.Sniff', + 'result' => ['Standard.Category.Sniff'], + ]; + $data[$argument.'; one valid sniff in different cases'] = [ + 'argument' => $argument, + 'value' => 'Standard.Category.Sniff, standard.category.sniff, STANDARD.CATEGORY.SNIFF', + 'result' => ['Standard.Category.Sniff'], + ]; + }//end foreach + + return $data; + + }//end dataValid() + + + /** + * Ensure that only the first argument is processed and others are ignored. + * + * @param string $argument 'sniffs' or 'exclude'. + * + * @return void + * @dataProvider dataOnlySetOnce + */ + public function testOnlySetOnce($argument) + { + $config = new ConfigDouble( + [ + "--$argument=StandardOne.Category.Sniff", + "--$argument=StandardTwo.Category.Sniff", + "--$argument=Standard.AnotherCategory.Sniff", + ] + ); + + $this->assertSame(['StandardOne.Category.Sniff'], $config->$argument); + + }//end testOnlySetOnce() + + + /** + * Data provider for testOnlySetOnce(). + * + * @return array> + */ + public static function dataOnlySetOnce() + { + return [ + 'sniffs' => ['sniffs'], + 'exclude' => ['exclude'], + ]; + + }//end dataOnlySetOnce() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/ErrorSuppressionTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/ErrorSuppressionTest.php index 4ae1e33ba..ebf851230 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/ErrorSuppressionTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/ErrorSuppressionTest.php @@ -9,8 +9,8 @@ namespace PHP_CodeSniffer\Tests\Core; -use PHP_CodeSniffer\Ruleset; use PHP_CodeSniffer\Files\DummyFile; +use PHP_CodeSniffer\Ruleset; use PHP_CodeSniffer\Tests\ConfigDouble; use PHPUnit\Framework\TestCase; @@ -605,7 +605,6 @@ public function testSuppressScope($before, $after, $expectedErrors=0) $ruleset = new Ruleset($config); } - $content = ' [ - 'before' => '', - 'after' => '', - 'expectedErrors' => 1, + 'before' => '', + 'after' => '', + 'expectedWarnings' => 1, ], // Process with suppression. diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindEndOfStatementTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindEndOfStatementTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindEndOfStatementTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindEndOfStatementTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindEndOfStatementTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindEndOfStatementTest.php similarity index 90% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindEndOfStatementTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindEndOfStatementTest.php index ba04cd591..ba62360a3 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindEndOfStatementTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindEndOfStatementTest.php @@ -7,9 +7,10 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\File; +namespace PHP_CodeSniffer\Tests\Core\Files\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; +use PHP_CodeSniffer\Util\Tokens; /** * Tests for the \PHP_CodeSniffer\Files\File::findEndOfStatement method. @@ -20,6 +21,42 @@ final class FindEndOfStatementTest extends AbstractMethodUnitTest { + /** + * Test that end of statement is NEVER before the "current" token. + * + * @return void + */ + public function testEndIsNeverLessThanCurrentToken() + { + $tokens = self::$phpcsFile->getTokens(); + $errors = []; + + for ($i = 0; $i < self::$phpcsFile->numTokens; $i++) { + if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) { + continue; + } + + $end = self::$phpcsFile->findEndOfStatement($i); + + // Collect all the errors. + if ($end < $i) { + $errors[] = sprintf( + 'End of statement for token %1$d (%2$s: %3$s) on line %4$d is %5$d (%6$s), which is less than %1$d', + $i, + $tokens[$i]['type'], + $tokens[$i]['content'], + $tokens[$i]['line'], + $end, + $tokens[$end]['type'] + ); + } + } + + $this->assertSame([], $errors); + + }//end testEndIsNeverLessThanCurrentToken() + + /** * Test a simple assignment. * diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindExtendedClassNameTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindExtendedClassNameTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindExtendedClassNameTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindExtendedClassNameTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindExtendedClassNameTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindExtendedClassNameTest.php similarity index 99% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindExtendedClassNameTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindExtendedClassNameTest.php index bb69f2568..327f486bf 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindExtendedClassNameTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindExtendedClassNameTest.php @@ -7,7 +7,7 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\File; +namespace PHP_CodeSniffer\Tests\Core\Files\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindImplementedInterfaceNamesTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindImplementedInterfaceNamesTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindImplementedInterfaceNamesTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindImplementedInterfaceNamesTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindImplementedInterfaceNamesTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindImplementedInterfaceNamesTest.php similarity index 97% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindImplementedInterfaceNamesTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindImplementedInterfaceNamesTest.php index ffb59300a..cb2081d8a 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindImplementedInterfaceNamesTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindImplementedInterfaceNamesTest.php @@ -7,7 +7,7 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\File; +namespace PHP_CodeSniffer\Tests\Core\Files\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; @@ -71,7 +71,7 @@ public function testFindImplementedInterfaceNames($identifier, $expected) * * @see testFindImplementedInterfaceNames() * - * @return array>> + * @return array|false>> */ public static function dataImplementedInterface() { diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindStartOfStatementTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindStartOfStatementTest.inc similarity index 69% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindStartOfStatementTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindStartOfStatementTest.inc index 148d8103a..5b601075a 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindStartOfStatementTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindStartOfStatementTest.inc @@ -14,7 +14,7 @@ while(true) {} $a = 1; /* testClosureAssignment */ -$a = function($b=false;){}; +$a = function($b=false){}; /* testHeredocFunctionArg */ myFunction(<< fn() => return 1, - 'b' => fn() => return 1, + 'a' => fn() => 1, + 'b' => fn() => 1, ]; /* testStaticArrowFunction */ @@ -139,11 +139,11 @@ switch ($foo) { /* testInsideCaseStatement */ $var = doSomething(); /* testInsideCaseBreakStatement */ - break 2; + break 1; case 2: /* testInsideCaseContinueStatement */ - continue 2; + continue 1; case 3: /* testInsideCaseReturnStatement */ @@ -157,8 +157,52 @@ switch ($foo) { /* testInsideCaseThrowStatement */ throw new Exception(); + case 6: + $var = doSomething(); + /* testInsideCaseGotoStatement */ + goto myLabel; + /* testDefaultStatement */ default: /* testInsideDefaultContinueStatement */ continue $var; } + +myLabel: +do_something(); + +match ($var) { + true => + /* test437ClosureDeclaration */ + function ($var) { + /* test437EchoNestedWithinClosureWithinMatch */ + echo $var, 'text', PHP_EOL; + }, + default => false +}; + +match ($var) { + /* test437NestedLongArrayWithinMatch */ + 'a' => array( 1, 2.5, $var), + /* test437NestedFunctionCallWithinMatch */ + 'b' => functionCall( 11, $var, 50.50), + /* test437NestedArrowFunctionWithinMatch */ + 'c' => fn($p1, /* test437FnSecondParamWithinMatch */ $p2) => $p1 + $p2, + default => false +}; + +callMe($paramA, match ($var) { + /* test437NestedLongArrayWithinNestedMatch */ + 'a' => array( 1, 2.5, $var), + /* test437NestedFunctionCallWithinNestedMatch */ + 'b' => functionCall( 11, $var, 50.50), + /* test437NestedArrowFunctionWithinNestedMatch */ + 'c' => fn($p1, /* test437FnSecondParamWithinNestedMatch */ $p2) => $p1 + $p2, + default => false +}); + +match ($var) { + /* test437NestedShortArrayWithinMatch */ + 'a' => [ 1, 2.5, $var], + default => false +}; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindStartOfStatementTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindStartOfStatementTest.php similarity index 56% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindStartOfStatementTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindStartOfStatementTest.php index c674a602d..4e0916dd0 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/FindStartOfStatementTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/FindStartOfStatementTest.php @@ -1,6 +1,6 @@ * @author Juliette Reinders Folmer @@ -9,12 +9,13 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\File; +namespace PHP_CodeSniffer\Tests\Core\Files\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; +use PHP_CodeSniffer\Util\Tokens; /** - * Tests for the \PHP_CodeSniffer\Files\File:findStartOfStatement method. + * Tests for the \PHP_CodeSniffer\Files\File::findStartOfStatement method. * * @covers \PHP_CodeSniffer\Files\File::findStartOfStatement */ @@ -22,6 +23,42 @@ final class FindStartOfStatementTest extends AbstractMethodUnitTest { + /** + * Test that start of statement is NEVER beyond the "current" token. + * + * @return void + */ + public function testStartIsNeverMoreThanCurrentToken() + { + $tokens = self::$phpcsFile->getTokens(); + $errors = []; + + for ($i = 0; $i < self::$phpcsFile->numTokens; $i++) { + if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) { + continue; + } + + $start = self::$phpcsFile->findStartOfStatement($i); + + // Collect all the errors. + if ($start > $i) { + $errors[] = sprintf( + 'Start of statement for token %1$d (%2$s: %3$s) on line %4$d is %5$d (%6$s), which is more than %1$d', + $i, + $tokens[$i]['type'], + $tokens[$i]['content'], + $tokens[$i]['line'], + $start, + $tokens[$start]['type'] + ); + } + } + + $this->assertSame([], $errors); + + }//end testStartIsNeverMoreThanCurrentToken() + + /** * Test a simple assignment. * @@ -92,7 +129,7 @@ public function testClosureAssignment() $start = $this->getTargetToken('/* testClosureAssignment */', T_CLOSE_CURLY_BRACKET); $found = self::$phpcsFile->findStartOfStatement($start); - $this->assertSame(($start - 12), $found); + $this->assertSame(($start - 11), $found); }//end testClosureAssignment() @@ -224,7 +261,7 @@ public function testArrowFunctionArrayValue() $start = $this->getTargetToken('/* testArrowFunctionArrayValue */', T_COMMA); $found = self::$phpcsFile->findStartOfStatement($start); - $this->assertSame(($start - 9), $found); + $this->assertSame(($start - 7), $found); }//end testArrowFunctionArrayValue() @@ -622,6 +659,16 @@ public static function dataFindStartInsideSwitchCaseDefaultStatements() 'targets' => T_CLOSE_PARENTHESIS, 'expectedTarget' => T_THROW, ], + 'Goto should be start for contents of the goto statement - goto label' => [ + 'testMarker' => '/* testInsideCaseGotoStatement */', + 'targets' => T_STRING, + 'expectedTarget' => T_GOTO, + ], + 'Goto should be start for contents of the goto statement - semicolon' => [ + 'testMarker' => '/* testInsideCaseGotoStatement */', + 'targets' => T_SEMICOLON, + 'expectedTarget' => T_GOTO, + ], 'Default keyword should be start of default statement - default itself' => [ 'testMarker' => '/* testDefaultStatement */', 'targets' => T_DEFAULT, @@ -637,4 +684,300 @@ public static function dataFindStartInsideSwitchCaseDefaultStatements() }//end dataFindStartInsideSwitchCaseDefaultStatements() + /** + * Test finding the start of a statement inside a closed scope nested within a match expressions. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $target The token to search for after the test marker. + * @param int|string $expectedTarget Token code of the expected start of statement stack pointer. + * + * @link https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/437 + * + * @dataProvider dataFindStartInsideClosedScopeNestedWithinMatch + * + * @return void + */ + public function testFindStartInsideClosedScopeNestedWithinMatch($testMarker, $target, $expectedTarget) + { + $testToken = $this->getTargetToken($testMarker, $target); + $expected = $this->getTargetToken($testMarker, $expectedTarget); + + $found = self::$phpcsFile->findStartOfStatement($testToken); + + $this->assertSame($expected, $found); + + }//end testFindStartInsideClosedScopeNestedWithinMatch() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataFindStartInsideClosedScopeNestedWithinMatch() + { + return [ + // These were already working correctly. + 'Closure function keyword should be start of closure - closure keyword' => [ + 'testMarker' => '/* test437ClosureDeclaration */', + 'target' => T_CLOSURE, + 'expectedTarget' => T_CLOSURE, + ], + 'Open curly is a statement/expression opener - open curly' => [ + 'testMarker' => '/* test437ClosureDeclaration */', + 'target' => T_OPEN_CURLY_BRACKET, + 'expectedTarget' => T_OPEN_CURLY_BRACKET, + ], + + 'Echo should be start for expression - echo keyword' => [ + 'testMarker' => '/* test437EchoNestedWithinClosureWithinMatch */', + 'target' => T_ECHO, + 'expectedTarget' => T_ECHO, + ], + 'Echo should be start for expression - variable' => [ + 'testMarker' => '/* test437EchoNestedWithinClosureWithinMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_ECHO, + ], + 'Echo should be start for expression - comma' => [ + 'testMarker' => '/* test437EchoNestedWithinClosureWithinMatch */', + 'target' => T_COMMA, + 'expectedTarget' => T_ECHO, + ], + + // These were not working correctly and would previously return the close curly of the match expression. + 'First token after comma in echo expression should be start for expression - text string' => [ + 'testMarker' => '/* test437EchoNestedWithinClosureWithinMatch */', + 'target' => T_CONSTANT_ENCAPSED_STRING, + 'expectedTarget' => T_CONSTANT_ENCAPSED_STRING, + ], + 'First token after comma in echo expression - PHP_EOL constant' => [ + 'testMarker' => '/* test437EchoNestedWithinClosureWithinMatch */', + 'target' => T_STRING, + 'expectedTarget' => T_STRING, + ], + 'First token after comma in echo expression - semicolon' => [ + 'testMarker' => '/* test437EchoNestedWithinClosureWithinMatch */', + 'target' => T_SEMICOLON, + 'expectedTarget' => T_STRING, + ], + ]; + + }//end dataFindStartInsideClosedScopeNestedWithinMatch() + + + /** + * Test finding the start of a statement for a token within a set of parentheses within a match expressions. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $target The token to search for after the test marker. + * @param int|string $expectedTarget Token code of the expected start of statement stack pointer. + * + * @link https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/437 + * + * @dataProvider dataFindStartInsideParenthesesNestedWithinMatch + * + * @return void + */ + public function testFindStartInsideParenthesesNestedWithinMatch($testMarker, $target, $expectedTarget) + { + $testToken = $this->getTargetToken($testMarker, $target); + $expected = $this->getTargetToken($testMarker, $expectedTarget); + + $found = self::$phpcsFile->findStartOfStatement($testToken); + + $this->assertSame($expected, $found); + + }//end testFindStartInsideParenthesesNestedWithinMatch() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataFindStartInsideParenthesesNestedWithinMatch() + { + return [ + 'Array item itself should be start for first array item' => [ + 'testMarker' => '/* test437NestedLongArrayWithinMatch */', + 'target' => T_LNUMBER, + 'expectedTarget' => T_LNUMBER, + ], + 'Array item itself should be start for second array item' => [ + 'testMarker' => '/* test437NestedLongArrayWithinMatch */', + 'target' => T_DNUMBER, + 'expectedTarget' => T_DNUMBER, + ], + 'Array item itself should be start for third array item' => [ + 'testMarker' => '/* test437NestedLongArrayWithinMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + + 'Parameter itself should be start for first param passed to function call' => [ + 'testMarker' => '/* test437NestedFunctionCallWithinMatch */', + 'target' => T_LNUMBER, + 'expectedTarget' => T_LNUMBER, + ], + 'Parameter itself should be start for second param passed to function call' => [ + 'testMarker' => '/* test437NestedFunctionCallWithinMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + 'Parameter itself should be start for third param passed to function call' => [ + 'testMarker' => '/* test437NestedFunctionCallWithinMatch */', + 'target' => T_DNUMBER, + 'expectedTarget' => T_DNUMBER, + ], + + 'Parameter itself should be start for first param declared in arrow function' => [ + 'testMarker' => '/* test437NestedArrowFunctionWithinMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + 'Parameter itself should be start for second param declared in arrow function' => [ + 'testMarker' => '/* test437FnSecondParamWithinMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + ]; + + }//end dataFindStartInsideParenthesesNestedWithinMatch() + + + /** + * Test finding the start of a statement for a token within a set of parentheses within a match expressions, + * which itself is nested within parentheses. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $target The token to search for after the test marker. + * @param int|string $expectedTarget Token code of the expected start of statement stack pointer. + * + * @link https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/437 + * + * @dataProvider dataFindStartInsideParenthesesNestedWithinNestedMatch + * + * @return void + */ + public function testFindStartInsideParenthesesNestedWithinNestedMatch($testMarker, $target, $expectedTarget) + { + $testToken = $this->getTargetToken($testMarker, $target); + $expected = $this->getTargetToken($testMarker, $expectedTarget); + + $found = self::$phpcsFile->findStartOfStatement($testToken); + + $this->assertSame($expected, $found); + + }//end testFindStartInsideParenthesesNestedWithinNestedMatch() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataFindStartInsideParenthesesNestedWithinNestedMatch() + { + return [ + 'Array item itself should be start for first array item' => [ + 'testMarker' => '/* test437NestedLongArrayWithinNestedMatch */', + 'target' => T_LNUMBER, + 'expectedTarget' => T_LNUMBER, + ], + 'Array item itself should be start for second array item' => [ + 'testMarker' => '/* test437NestedLongArrayWithinNestedMatch */', + 'target' => T_DNUMBER, + 'expectedTarget' => T_DNUMBER, + ], + 'Array item itself should be start for third array item' => [ + 'testMarker' => '/* test437NestedLongArrayWithinNestedMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + + 'Parameter itself should be start for first param passed to function call' => [ + 'testMarker' => '/* test437NestedFunctionCallWithinNestedMatch */', + 'target' => T_LNUMBER, + 'expectedTarget' => T_LNUMBER, + ], + 'Parameter itself should be start for second param passed to function call' => [ + 'testMarker' => '/* test437NestedFunctionCallWithinNestedMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + 'Parameter itself should be start for third param passed to function call' => [ + 'testMarker' => '/* test437NestedFunctionCallWithinNestedMatch */', + 'target' => T_DNUMBER, + 'expectedTarget' => T_DNUMBER, + ], + + 'Parameter itself should be start for first param declared in arrow function' => [ + 'testMarker' => '/* test437NestedArrowFunctionWithinNestedMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + 'Parameter itself should be start for second param declared in arrow function' => [ + 'testMarker' => '/* test437FnSecondParamWithinNestedMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + ]; + + }//end dataFindStartInsideParenthesesNestedWithinNestedMatch() + + + /** + * Test finding the start of a statement for a token within a short array within a match expressions. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param int|string $target The token to search for after the test marker. + * @param int|string $expectedTarget Token code of the expected start of statement stack pointer. + * + * @link https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/437 + * + * @dataProvider dataFindStartInsideShortArrayNestedWithinMatch + * + * @return void + */ + public function testFindStartInsideShortArrayNestedWithinMatch($testMarker, $target, $expectedTarget) + { + $testToken = $this->getTargetToken($testMarker, $target); + $expected = $this->getTargetToken($testMarker, $expectedTarget); + + $found = self::$phpcsFile->findStartOfStatement($testToken); + + $this->assertSame($expected, $found); + + }//end testFindStartInsideShortArrayNestedWithinMatch() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataFindStartInsideShortArrayNestedWithinMatch() + { + return [ + 'Array item itself should be start for first array item' => [ + 'testMarker' => '/* test437NestedShortArrayWithinMatch */', + 'target' => T_LNUMBER, + 'expectedTarget' => T_LNUMBER, + ], + 'Array item itself should be start for second array item' => [ + 'testMarker' => '/* test437NestedShortArrayWithinMatch */', + 'target' => T_DNUMBER, + 'expectedTarget' => T_DNUMBER, + ], + 'Array item itself should be start for third array item' => [ + 'testMarker' => '/* test437NestedShortArrayWithinMatch */', + 'target' => T_VARIABLE, + 'expectedTarget' => T_VARIABLE, + ], + ]; + + }//end dataFindStartInsideShortArrayNestedWithinMatch() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetClassPropertiesTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetClassPropertiesTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetClassPropertiesTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetClassPropertiesTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetClassPropertiesTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetClassPropertiesTest.php similarity index 99% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetClassPropertiesTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetClassPropertiesTest.php index 4841b50b6..5e3156b11 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetClassPropertiesTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetClassPropertiesTest.php @@ -7,7 +7,7 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\File; +namespace PHP_CodeSniffer\Tests\Core\Files\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetConditionTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetConditionTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetConditionTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetConditionTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetConditionTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetConditionTest.php similarity index 99% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetConditionTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetConditionTest.php index 5df0f5a27..9d6eecc62 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetConditionTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetConditionTest.php @@ -7,7 +7,7 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\File; +namespace PHP_CodeSniffer\Tests\Core\Files\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; use PHP_CodeSniffer\Util\Tokens; @@ -153,7 +153,7 @@ protected function setUpCaches() */ public function testNonExistentToken() { - $result = self::$phpcsFile->getCondition(100000, Tokens::$ooScopeTokens); + $result = self::$phpcsFile->getCondition(100000, T_CLASS); $this->assertFalse($result); $result = self::$phpcsFile->hasCondition(100000, T_IF); diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameJSTest.js b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameJSTest.js similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameJSTest.js rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameJSTest.js diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameJSTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameJSTest.php similarity index 98% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameJSTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameJSTest.php index af3fe56d2..5bdb56e29 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameJSTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameJSTest.php @@ -7,7 +7,7 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\File; +namespace PHP_CodeSniffer\Tests\Core\Files\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameParseError1Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameParseError1Test.inc new file mode 100644 index 000000000..451d4dfb8 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameParseError1Test.inc @@ -0,0 +1,5 @@ + + * @copyright 2025 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Files\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File:getDeclarationName method. + * + * @covers \PHP_CodeSniffer\Files\File::getDeclarationName + */ +final class GetDeclarationNameParseError1Test extends AbstractMethodUnitTest +{ + + + /** + * Test receiving "null" in case of a parse error. + * + * @return void + */ + public function testGetDeclarationNameNull() + { + $target = $this->getTargetToken('/* testLiveCoding */', T_FUNCTION); + $result = self::$phpcsFile->getDeclarationName($target); + $this->assertNull($result); + + }//end testGetDeclarationNameNull() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameParseError2Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameParseError2Test.inc new file mode 100644 index 000000000..e9a61cf41 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameParseError2Test.inc @@ -0,0 +1,6 @@ + + * @copyright 2025 PHPCSStandards Contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Files\File; + +use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; + +/** + * Tests for the \PHP_CodeSniffer\Files\File:getDeclarationName method. + * + * @covers \PHP_CodeSniffer\Files\File::getDeclarationName + */ +final class GetDeclarationNameParseError2Test extends AbstractMethodUnitTest +{ + + + /** + * Test receiving "null" in case of a parse error. + * + * @return void + */ + public function testGetDeclarationNameNull() + { + $target = $this->getTargetToken('/* testLiveCoding */', T_FUNCTION); + $result = self::$phpcsFile->getDeclarationName($target); + $this->assertNull($result); + + }//end testGetDeclarationNameNull() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameTest.inc similarity index 94% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameTest.inc index 14902245b..a7a53c9a1 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameTest.inc @@ -96,7 +96,3 @@ function &self() {} /* testFunctionReturnByRefWithReservedKeywordStatic */ function &static() {} - -/* testLiveCoding */ -// Intentional parse error. This has to be the last test in the file. -function // Comment. diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameTest.php similarity index 97% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameTest.php index 19c798f50..6da1544f7 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetDeclarationNameTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetDeclarationNameTest.php @@ -7,7 +7,7 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\File; +namespace PHP_CodeSniffer\Tests\Core\Files\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; @@ -84,10 +84,6 @@ public static function dataGetDeclarationNameNull() 'testMarker' => '/* testAnonClassExtendsWithoutParens */', 'targetType' => T_ANON_CLASS, ], - 'live-coding' => [ - 'testMarker' => '/* testLiveCoding */', - 'targetType' => T_FUNCTION, - ], ]; }//end dataGetDeclarationNameNull() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMemberPropertiesTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMemberPropertiesTest.inc similarity index 81% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMemberPropertiesTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMemberPropertiesTest.inc index f69a685ec..b5fcea940 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMemberPropertiesTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMemberPropertiesTest.inc @@ -339,3 +339,65 @@ class WhitespaceAndCommentsInTypes { /* testIntersectionTypeWithWhitespaceAndComment */ public \Foo /*comment*/ & Bar $hasWhitespaceAndComment; } + +trait DNFTypes { + /* testPHP82DNFTypeStatic */ + public static (Foo&\Bar)|bool $propA; + + /* testPHP82DNFTypeReadonlyA */ + protected readonly float|(Partially\Qualified&Traversable) $propB; + + /* testPHP82DNFTypeReadonlyB */ + private readonly (namespace\Foo&Bar)|string $propC; + + /* testPHP82DNFTypeIllegalNullable */ + // Intentional fatal error - nullable operator cannot be combined with DNF. + var ?(A&\Pck\B)|bool $propD; +} + +class WithFinalProperties { + /* testPHP84FinalPublicTypedProp */ + final public string $val1; + /* testPHP84FinalProtectedTypedProp */ + final protected string $val2; + /* testPHP84FinalMiddleTypedProp */ + public final string $val3; + /* testPHP84FinalMiddleStaticTypedProp */ + public final static string $val4; + /* testPHP84FinalLastTypedProp */ + public readonly final string $val5; + /* testPHP84FinalImplicitVisibilityTypedProp */ + final string $val6; + /* testPHP84FinalImplicitVisibilityProp */ + final $val7; + /* testPHP84FinalNullableTypedProp */ + final public ?string $val8; + /* testPHP84FinalComplexTypedProp */ + final public (Foo&\Bar)|bool $val9; +} + +class AsymVisibility { + /* testPHP84AsymPublicSetProperty */ + public(set) mixed $prop1; + /* testPHP84AsymPublicPublicSetProperty */ + public public(set) (A&B)|null $prop2; + /* testPHP84AsymPublicSetPublicProperty */ + public(set) public bool $prop3; + + /* testPHP84AsymProtectedSetProperty */ + protected(set) readonly mixed $prop4; + /* testPHP84AsymPublicProtectedSetProperty */ + public protected(set) string $prop5; + /* testPHP84AsymProtectedSetPublicProperty */ + protected(set) public ?float $prop6; + + /* testPHP84AsymPrivateSetProperty */ + private(set) string|int $prop7; + /* testPHP84AsymProtectedPrivateSetProperty */ + final protected private(set) $prop8; + /* testPHP84AsymPrivateSetPublicProperty */ + private(set) public mixed $prop9; + + /* testPHP84IllegalAsymPublicProtectedSetStaticProperty */ + public protected(set) static mixed $prop10; +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMemberPropertiesTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMemberPropertiesTest.php similarity index 67% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMemberPropertiesTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMemberPropertiesTest.php index 5f2c4cdf9..3c218911b 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMemberPropertiesTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMemberPropertiesTest.php @@ -7,7 +7,7 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\File; +namespace PHP_CodeSniffer\Tests\Core\Files\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; @@ -68,8 +68,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => false, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -81,8 +83,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => false, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '?int', 'type_token' => -2, 'type_end_token' => -2, @@ -94,8 +98,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -107,8 +113,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'string', 'type_token' => -2, 'type_end_token' => -2, @@ -120,8 +128,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -133,8 +143,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'bool', 'type_token' => -2, 'type_end_token' => -2, @@ -146,8 +158,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'private', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -159,8 +173,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'private', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'array', 'type_token' => -2, 'type_end_token' => -2, @@ -172,8 +188,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => false, + 'set_scope' => false, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -185,8 +203,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => false, + 'set_scope' => false, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '?string', 'type_token' => -2, 'type_end_token' => -2, @@ -198,8 +218,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => false, + 'set_scope' => false, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -211,8 +233,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => false, + 'set_scope' => false, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -224,8 +248,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -237,8 +263,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -250,8 +278,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'private', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -263,8 +293,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => false, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -276,8 +308,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -289,8 +323,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -302,8 +338,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'private', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -315,8 +353,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'float', 'type_token' => -6, 'type_end_token' => -6, @@ -328,8 +368,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'float', 'type_token' => -13, 'type_end_token' => -13, @@ -341,8 +383,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '?string', 'type_token' => -6, 'type_end_token' => -6, @@ -354,8 +398,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '?string', 'type_token' => -17, 'type_end_token' => -17, @@ -367,8 +413,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -380,8 +428,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -393,8 +443,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -406,8 +458,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'private', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -419,8 +473,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'private', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -432,8 +488,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'private', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -445,8 +503,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'private', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -458,8 +518,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'private', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -471,8 +533,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'private', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -484,8 +548,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'private', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -497,8 +563,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '?array', 'type_token' => -2, 'type_end_token' => -2, @@ -510,8 +578,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '\MyNamespace\MyClass', 'type_token' => -5, 'type_end_token' => -2, @@ -523,8 +593,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'private', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '?ClassName', 'type_token' => -2, 'type_end_token' => -2, @@ -536,8 +608,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '?Folder\ClassName', 'type_token' => -4, 'type_end_token' => -2, @@ -549,8 +623,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '\MyNamespace\MyClass\Foo', 'type_token' => -18, 'type_end_token' => -2, @@ -562,8 +638,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'private', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -579,8 +657,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -592,8 +672,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -605,8 +687,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => 'miXed', 'type_token' => -2, 'type_end_token' => -2, @@ -618,8 +702,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'private', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '?mixed', 'type_token' => -2, 'type_end_token' => -2, @@ -631,8 +717,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '?namespace\Name', 'type_token' => -4, 'type_end_token' => -2, @@ -644,8 +732,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'int|float', 'type_token' => -4, 'type_end_token' => -2, @@ -657,8 +747,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'private', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'MyClassA|\Package\MyClassB', 'type_token' => -7, 'type_end_token' => -2, @@ -670,8 +762,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'array|bool|int|float|NULL|object|string', 'type_token' => -14, 'type_end_token' => -2, @@ -683,8 +777,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => false, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'false|mixed|self|parent|iterable|Resource', 'type_token' => -12, 'type_end_token' => -2, @@ -696,8 +792,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, // Missing static, but that's OK as not an allowed syntax. 'type' => 'callable|void', 'type_token' => -4, @@ -710,8 +808,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '?int|float', 'type_token' => -4, 'type_end_token' => -2, @@ -723,8 +823,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'null', 'type_token' => -2, 'type_end_token' => -2, @@ -736,8 +838,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'false', 'type_token' => -2, 'type_end_token' => -2, @@ -749,8 +853,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'bool|FALSE', 'type_token' => -4, 'type_end_token' => -2, @@ -762,8 +868,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'object|ClassName', 'type_token' => -4, 'type_end_token' => -2, @@ -775,8 +883,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'iterable|array|Traversable', 'type_token' => -6, 'type_end_token' => -2, @@ -788,8 +898,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'int|string|INT', 'type_token' => -10, 'type_end_token' => -2, @@ -801,8 +913,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => true, + 'is_final' => false, 'type' => 'int', 'type_token' => -2, 'type_end_token' => -2, @@ -814,8 +928,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => true, + 'is_final' => false, 'type' => '?array', 'type_token' => -2, 'type_end_token' => -2, @@ -827,8 +943,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => true, + 'is_final' => false, 'type' => 'string|int', 'type_token' => -4, 'type_end_token' => -2, @@ -840,8 +958,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => true, + 'is_final' => false, 'type' => 'string|null', 'type_token' => -4, 'type_end_token' => -2, @@ -853,8 +973,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => false, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => true, + 'is_final' => false, 'type' => 'string|int', 'type_token' => -4, 'type_end_token' => -2, @@ -866,8 +988,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => false, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => true, + 'is_final' => false, 'type' => '\InterfaceA|\Sub\InterfaceB|false', 'type_token' => -11, 'type_end_token' => -3, @@ -879,8 +1003,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'private', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => true, 'is_readonly' => true, + 'is_final' => false, 'type' => '?string', 'type_token' => -2, 'type_end_token' => -2, @@ -892,8 +1018,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => true, 'is_readonly' => true, + 'is_final' => false, 'type' => '', 'type_token' => false, 'type_end_token' => false, @@ -905,8 +1033,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'string', 'type_token' => -2, 'type_end_token' => -2, @@ -918,8 +1048,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '?int|float', 'type_token' => -4, 'type_end_token' => -2, @@ -931,8 +1063,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'private', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'mixed', 'type_token' => -2, 'type_end_token' => -2, @@ -948,8 +1082,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'Foo&Bar', 'type_token' => -4, 'type_end_token' => -2, @@ -961,8 +1097,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'Foo&Bar&Baz', 'type_token' => -6, 'type_end_token' => -2, @@ -974,8 +1112,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'int&string', 'type_token' => -4, 'type_end_token' => -2, @@ -987,8 +1127,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '?Foo&Bar', 'type_token' => -4, 'type_end_token' => -2, @@ -1001,8 +1143,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'int|string', 'type_token' => -8, 'type_end_token' => -2, @@ -1014,8 +1158,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => '\Foo&Bar', 'type_token' => -9, 'type_end_token' => -2, @@ -1027,8 +1173,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'true', 'type_token' => -2, 'type_end_token' => -2, @@ -1040,8 +1188,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'protected', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => true, 'is_readonly' => false, + 'is_final' => false, 'type' => '?true', 'type_token' => -2, 'type_end_token' => -2, @@ -1053,8 +1203,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'private', 'scope_specified' => true, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => false, + 'is_final' => false, 'type' => 'int|string|true', 'type_token' => -6, 'type_end_token' => -2, @@ -1066,8 +1218,10 @@ public static function dataGetMemberProperties() 'expected' => [ 'scope' => 'public', 'scope_specified' => false, + 'set_scope' => false, 'is_static' => false, 'is_readonly' => true, + 'is_final' => false, 'type' => 'true|FALSE', 'type_token' => -4, 'type_end_token' => -2, @@ -1075,6 +1229,352 @@ public static function dataGetMemberProperties() ], ], + 'php8.2-dnf-with-static' => [ + 'identifier' => '/* testPHP82DNFTypeStatic */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '(Foo&\Bar)|bool', + 'type_token' => -9, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.2-dnf-with-readonly-1' => [ + 'identifier' => '/* testPHP82DNFTypeReadonlyA */', + 'expected' => [ + 'scope' => 'protected', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => true, + 'is_final' => false, + 'type' => 'float|(Partially\Qualified&Traversable)', + 'type_token' => -10, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.2-dnf-with-readonly-2' => [ + 'identifier' => '/* testPHP82DNFTypeReadonlyB */', + 'expected' => [ + 'scope' => 'private', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => true, + 'is_final' => false, + 'type' => '(namespace\Foo&Bar)|string', + 'type_token' => -10, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.2-dnf-with-illegal-nullable' => [ + 'identifier' => '/* testPHP82DNFTypeIllegalNullable */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '?(A&\Pck\B)|bool', + 'type_token' => -11, + 'type_end_token' => -2, + 'nullable_type' => true, + ], + ], + 'php8.4-final-public-property' => [ + 'identifier' => '/* testPHP84FinalPublicTypedProp */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => true, + 'type' => 'string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-final-protected-property' => [ + 'identifier' => '/* testPHP84FinalProtectedTypedProp */', + 'expected' => [ + 'scope' => 'protected', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => true, + 'type' => 'string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-final-middle-keyword-property' => [ + 'identifier' => '/* testPHP84FinalMiddleTypedProp */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => true, + 'type' => 'string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-final-middle-keyword-static-property' => [ + 'identifier' => '/* testPHP84FinalMiddleStaticTypedProp */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => true, + 'type' => 'string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-final-last-keyword-property' => [ + 'identifier' => '/* testPHP84FinalLastTypedProp */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => true, + 'is_final' => true, + 'type' => 'string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-final-implicit-public-typed-property' => [ + 'identifier' => '/* testPHP84FinalImplicitVisibilityTypedProp */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => true, + 'type' => 'string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-final-implicit-public-untyped-property' => [ + 'identifier' => '/* testPHP84FinalImplicitVisibilityProp */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => true, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'php8.4-final-public-nullable-typed-property' => [ + 'identifier' => '/* testPHP84FinalNullableTypedProp */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => true, + 'type' => '?string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => true, + ], + ], + 'php8.4-final-public-complex-type-property' => [ + 'identifier' => '/* testPHP84FinalComplexTypedProp */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => false, + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => true, + 'type' => '(Foo&\Bar)|bool', + 'type_token' => -9, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + + 'php8.4-asym-public-set' => [ + 'identifier' => '/* testPHP84AsymPublicSetProperty */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'set_scope' => 'public', + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'mixed', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-asym-public-public-set-dnf-type' => [ + 'identifier' => '/* testPHP84AsymPublicPublicSetProperty */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => 'public', + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '(A&B)|null', + 'type_token' => -8, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-asym-public-set-public' => [ + 'identifier' => '/* testPHP84AsymPublicSetPublicProperty */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => 'public', + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'bool', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-asym-protected-set-readonly' => [ + 'identifier' => '/* testPHP84AsymProtectedSetProperty */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'set_scope' => 'protected', + 'is_static' => false, + 'is_readonly' => true, + 'is_final' => false, + 'type' => 'mixed', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-asym-public-protected-set' => [ + 'identifier' => '/* testPHP84AsymPublicProtectedSetProperty */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => 'protected', + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'string', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-asym-protected-set-public-nullable-type' => [ + 'identifier' => '/* testPHP84AsymProtectedSetPublicProperty */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => 'protected', + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => '?float', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => true, + ], + ], + 'php8.4-asym-private-set-union-type' => [ + 'identifier' => '/* testPHP84AsymPrivateSetProperty */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => false, + 'set_scope' => 'private', + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'string|int', + 'type_token' => -4, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-asym-final-protected-private-set' => [ + 'identifier' => '/* testPHP84AsymProtectedPrivateSetProperty */', + 'expected' => [ + 'scope' => 'protected', + 'scope_specified' => true, + 'set_scope' => 'private', + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => true, + 'type' => '', + 'type_token' => false, + 'type_end_token' => false, + 'nullable_type' => false, + ], + ], + 'php8.4-asym-private-set-public' => [ + 'identifier' => '/* testPHP84AsymPrivateSetPublicProperty */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => 'private', + 'is_static' => false, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'mixed', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], + 'php8.4-illegal-asym-public-protected-set-static' => [ + 'identifier' => '/* testPHP84IllegalAsymPublicProtectedSetStaticProperty */', + 'expected' => [ + 'scope' => 'public', + 'scope_specified' => true, + 'set_scope' => 'protected', + 'is_static' => true, + 'is_readonly' => false, + 'is_final' => false, + 'type' => 'mixed', + 'type_token' => -2, + 'type_end_token' => -2, + 'nullable_type' => false, + ], + ], ]; }//end dataGetMemberProperties() @@ -1094,7 +1594,7 @@ public function testNotClassPropertyException($identifier) $this->expectRunTimeException('$stackPtr is not a class member var'); $variable = $this->getTargetToken($identifier, T_VARIABLE); - $result = self::$phpcsFile->getMemberProperties($variable); + self::$phpcsFile->getMemberProperties($variable); }//end testNotClassPropertyException() @@ -1130,8 +1630,8 @@ public function testNotAVariableException() { $this->expectRunTimeException('$stackPtr must be of type T_VARIABLE'); - $next = $this->getTargetToken('/* testNotAVariable */', T_RETURN); - $result = self::$phpcsFile->getMemberProperties($next); + $next = $this->getTargetToken('/* testNotAVariable */', T_RETURN); + self::$phpcsFile->getMemberProperties($next); }//end testNotAVariableException() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersParseError1Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersParseError1Test.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersParseError1Test.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersParseError1Test.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersParseError1Test.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersParseError1Test.php similarity index 95% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersParseError1Test.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersParseError1Test.php index 528d54873..db25407b3 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersParseError1Test.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersParseError1Test.php @@ -7,7 +7,7 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\File; +namespace PHP_CodeSniffer\Tests\Core\Files\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersParseError2Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersParseError2Test.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersParseError2Test.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersParseError2Test.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersParseError2Test.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersParseError2Test.php similarity index 95% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersParseError2Test.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersParseError2Test.php index 49cd94059..eda050d4d 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersParseError2Test.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersParseError2Test.php @@ -7,7 +7,7 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\File; +namespace PHP_CodeSniffer\Tests\Core\Files\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersTest.inc similarity index 89% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersTest.inc index f6f3cd9eb..3a12adeae 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersTest.inc @@ -118,7 +118,7 @@ function messyDeclaration( ?\MyNS /* comment */ \ SubCat // phpcs:ignore Standard.Cat.Sniff -- for reasons. \ MyClass $a, - $b /* test */ = /* test */ 'default' /* test*/, + $b /* comment */ = /* comment */ 'default' /* comment*/, // phpcs:ignore Stnd.Cat.Sniff -- For reasons. ? /*comment*/ bool // phpcs:disable Stnd.Cat.Sniff -- For reasons. @@ -217,6 +217,17 @@ class ConstructorPropertyPromotionWithOnlyReadOnly { public function __construct(readonly Foo&Bar $promotedProp, readonly ?bool $promotedToo,) {} } +class ConstructorPropertyPromotionWithAsymVisibility { + /* testPHP84ConstructorPropertyPromotionWithAsymVisibility */ + public function __construct( + protected(set) string|Book $book, + public private(set) ?Publisher $publisher, + Private(set) PROTECTED Author $author, + readonly public(set) int $pubYear, + protected(set) $illegalMissingType, + ) {} +} + /* testPHP8ConstructorPropertyPromotionGlobalFunction */ // Intentional fatal error. Property promotion not allowed in non-constructor, but that's not the concern of this method. function globalFunction(private $x) {} @@ -280,6 +291,23 @@ function newInInitializers( \Package\TypeB $newToo = new \Package\TypeB(10, 'string'), ) {} +/* testPHP82DNFTypes */ +function dnfTypes( + #[MyAttribute] + false|(Foo&Bar)|true $obj1, + (\Boo&\Pck\Bar)|(Boo&Baz) $obj2 = new Boo() +) {} + +/* testPHP82DNFTypesWithSpreadOperatorAndReference */ +function dnfInGlobalFunctionWithSpreadAndReference((Countable&MeMe)|iterable &$paramA, true|(Foo&Bar) ...$paramB) {} + +/* testPHP82DNFTypesIllegalNullable */ +// Intentional fatal error - nullable operator cannot be combined with DNF. +$dnf_closure = function (? ( MyClassA & /*comment*/ \Package\MyClassB & \Package\MyClassC ) $var): void {}; + +/* testPHP82DNFTypesInArrow */ +$dnf_arrow = fn((Hi&Ho)|FALSE &...$range): string => $a; + /* testFunctionCallFnPHPCS353-354 */ $value = $obj->fn(true); @@ -295,6 +323,9 @@ function() use() {}; /* testClosureUse */ function() use( $foo, $bar ) {}; +/* testClosureUseWithReference */ +$cl = function() use (&$foo, &$bar) {}; + /* testFunctionParamListWithTrailingComma */ function trailingComma( ?string $foo /*comment*/ , diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersTest.php similarity index 89% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersTest.php index 83419ddea..e660275fd 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodParametersTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodParametersTest.php @@ -9,7 +9,7 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\File; +namespace PHP_CodeSniffer\Tests\Core\Files\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; @@ -1268,8 +1268,8 @@ public function testMessyDeclaration() $expected[1] = [ 'token' => 29, 'name' => '$b', - 'content' => "\$b /* test */ = /* test */ 'default' /* test*/", - 'default' => "'default' /* test*/", + 'content' => "\$b /* comment */ = /* comment */ 'default' /* comment*/", + 'default' => "'default' /* comment*/", 'default_token' => 37, 'default_equal_token' => 33, 'has_attributes' => false, @@ -2190,6 +2190,122 @@ public function testPHP81ConstructorPropertyPromotionWithOnlyReadOnly() }//end testPHP81ConstructorPropertyPromotionWithOnlyReadOnly() + /** + * Verify recognition of PHP8 constructor with property promotion using PHP 8.4 asymmetric visibility. + * + * @return void + */ + public function testPHP84ConstructorPropertyPromotionWithAsymVisibility() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 12, + 'name' => '$book', + 'content' => 'protected(set) string|Book $book', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'string|Book', + 'type_hint_token' => 8, + 'type_hint_end_token' => 10, + 'nullable_type' => false, + 'property_visibility' => 'public', + 'visibility_token' => false, + 'set_visibility' => 'protected(set)', + 'set_visibility_token' => 6, + 'property_readonly' => false, + 'comma_token' => 13, + ]; + $expected[1] = [ + 'token' => 23, + 'name' => '$publisher', + 'content' => 'public private(set) ?Publisher $publisher', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?Publisher', + 'type_hint_token' => 21, + 'type_hint_end_token' => 21, + 'nullable_type' => true, + 'property_visibility' => 'public', + 'visibility_token' => 16, + 'set_visibility' => 'private(set)', + 'set_visibility_token' => 18, + 'property_readonly' => false, + 'comma_token' => 24, + ]; + $expected[2] = [ + 'token' => 33, + 'name' => '$author', + 'content' => 'Private(set) PROTECTED Author $author', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'Author', + 'type_hint_token' => 31, + 'type_hint_end_token' => 31, + 'nullable_type' => false, + 'property_visibility' => 'PROTECTED', + 'visibility_token' => 29, + 'set_visibility' => 'Private(set)', + 'set_visibility_token' => 27, + 'property_readonly' => false, + 'comma_token' => 34, + ]; + $expected[3] = [ + 'token' => 43, + 'name' => '$pubYear', + 'content' => 'readonly public(set) int $pubYear', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'int', + 'type_hint_token' => 41, + 'type_hint_end_token' => 41, + 'nullable_type' => false, + 'property_visibility' => 'public', + 'visibility_token' => false, + 'set_visibility' => 'public(set)', + 'set_visibility_token' => 39, + 'property_readonly' => true, + 'readonly_token' => 37, + 'comma_token' => 44, + ]; + $expected[4] = [ + 'token' => 49, + 'name' => '$illegalMissingType', + 'content' => 'protected(set) $illegalMissingType', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'property_visibility' => 'public', + 'visibility_token' => false, + 'set_visibility' => 'protected(set)', + 'set_visibility_token' => 47, + 'property_readonly' => false, + 'comma_token' => 50, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP84ConstructorPropertyPromotionWithAsymVisibility() + + /** * Verify behaviour when a non-constructor function uses PHP 8 property promotion syntax. * @@ -2450,7 +2566,7 @@ public function testPHP8IntersectionTypes() /** - * Verify recognition of PHP8 intersection type declaration when the variable + * Verify recognition of PHP8.1 intersection type declaration when the variable * has either a spread operator or a reference. * * @return void @@ -2702,6 +2818,161 @@ public function testPHP81NewInInitializers() }//end testPHP81NewInInitializers() + /** + * Verify recognition of 8.2 DNF parameter type declarations. + * + * @return void + */ + public function testPHP82DNFTypes() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 21, + 'name' => '$obj1', + 'content' => '#[MyAttribute] + false|(Foo&Bar)|true $obj1', + 'has_attributes' => true, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => 'false|(Foo&Bar)|true', + 'type_hint_token' => 11, + 'type_hint_end_token' => 19, + 'nullable_type' => false, + 'comma_token' => 22, + ]; + $expected[1] = [ + 'token' => 41, + 'name' => '$obj2', + 'content' => '(\Boo&\Pck\Bar)|(Boo&Baz) $obj2 = new Boo()', + 'default' => 'new Boo()', + 'default_token' => 45, + 'default_equal_token' => 43, + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '(\Boo&\Pck\Bar)|(Boo&Baz)', + 'type_hint_token' => 25, + 'type_hint_end_token' => 39, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypes() + + + /** + * Verify recognition of PHP 8.2 DNF parameter type declarations when the variable + * has either a spread operator or a reference. + * + * @return void + */ + public function testPHP82DNFTypesWithSpreadOperatorAndReference() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 13, + 'name' => '$paramA', + 'content' => '(Countable&MeMe)|iterable &$paramA', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 12, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '(Countable&MeMe)|iterable', + 'type_hint_token' => 4, + 'type_hint_end_token' => 10, + 'nullable_type' => false, + 'comma_token' => 14, + ]; + $expected[1] = [ + 'token' => 25, + 'name' => '$paramB', + 'content' => 'true|(Foo&Bar) ...$paramB', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => true, + 'variadic_token' => 24, + 'type_hint' => 'true|(Foo&Bar)', + 'type_hint_token' => 16, + 'type_hint_end_token' => 22, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypesWithSpreadOperatorAndReference() + + + /** + * Verify recognition of PHP 8.2 DNF parameter type declarations using the nullability operator (not allowed). + * + * @return void + */ + public function testPHP82DNFTypesIllegalNullable() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 27, + 'name' => '$var', + 'content' => '? ( MyClassA & /*comment*/ \Package\MyClassB & \Package\MyClassC ) $var', + 'has_attributes' => false, + 'pass_by_reference' => false, + 'reference_token' => false, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '?(MyClassA&\Package\MyClassB&\Package\MyClassC)', + 'type_hint_token' => 5, + 'type_hint_end_token' => 25, + 'nullable_type' => true, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypesIllegalNullable() + + + /** + * Verify recognition of PHP 8.2 DNF parameter type declarations in an arrow function. + * + * @return void + */ + public function testPHP82DNFTypesInArrow() + { + // Offsets are relative to the T_FUNCTION token. + $expected = []; + $expected[0] = [ + 'token' => 12, + 'name' => '$range', + 'content' => '(Hi&Ho)|FALSE &...$range', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 10, + 'variable_length' => true, + 'variadic_token' => 11, + 'type_hint' => '(Hi&Ho)|FALSE', + 'type_hint_token' => 2, + 'type_hint_end_token' => 8, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypesInArrow() + + /** * Verify handling of a closure. * @@ -2780,6 +3051,51 @@ public function testClosureUse() }//end testClosureUse() + /** + * Verify handling of a closure T_USE token with variables imported by reference. + * + * @return void + */ + public function testClosureUseWithReference() + { + // Offsets are relative to the T_USE token. + $expected = []; + $expected[0] = [ + 'token' => 4, + 'name' => '$foo', + 'content' => '&$foo', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 3, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => 5, + ]; + $expected[1] = [ + 'token' => 8, + 'name' => '$bar', + 'content' => '&$bar', + 'has_attributes' => false, + 'pass_by_reference' => true, + 'reference_token' => 7, + 'variable_length' => false, + 'variadic_token' => false, + 'type_hint' => '', + 'type_hint_token' => false, + 'type_hint_end_token' => false, + 'nullable_type' => false, + 'comma_token' => false, + ]; + + $this->getMethodParametersTestHelper('/* '.__FUNCTION__.' */', $expected, [T_USE]); + + }//end testClosureUseWithReference() + + /** * Verify function declarations with trailing commas are handled correctly. * @@ -3014,6 +3330,10 @@ private function getMethodParametersTestHelper($commentString, $expected, $targe $expected[$key]['visibility_token'] += $target; } + if (isset($param['set_visibility_token']) === true && is_int($param['set_visibility_token']) === true) { + $expected[$key]['set_visibility_token'] += $target; + } + if (isset($param['readonly_token']) === true) { $expected[$key]['readonly_token'] += $target; } diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodPropertiesTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodPropertiesTest.inc similarity index 85% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodPropertiesTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodPropertiesTest.inc index 24d8cc692..7f572f66c 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodPropertiesTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodPropertiesTest.inc @@ -170,6 +170,25 @@ function pseudoTypeTrue(): ?true {} // Intentional fatal error - Type contains both true and false, bool should be used instead, but that's not the concern of the method. function pseudoTypeFalseAndTrue(): true|false {} +/* testPHP82DNFType */ +function hasDNFType() : bool|(Foo&Bar)|string {} + +abstract class AbstractClass { + /* testPHP82DNFTypeAbstractMethod */ + abstract protected function abstractMethodDNFType() : float|(Foo&Bar); +} + +/* testPHP82DNFTypeIllegalNullable */ +// Intentional fatal error - nullable operator cannot be combined with DNF. +function illegalNullableDNF(): ?(A&\Pck\B)|bool {} + +/* testPHP82DNFTypeClosure */ +$closure = function() : object|(namespace\Foo&Countable) {}; + +/* testPHP82DNFTypeFn */ +// Intentional fatal error - void type cannot be combined with DNF. +$arrow = fn() : null|(Partially\Qualified&Traversable)|void => do_something(); + /* testNotAFunction */ return true; @@ -190,6 +209,18 @@ $value = $obj->fn(true); /* testFunctionDeclarationNestedInTernaryPHPCS2975 */ return (!$a ? [ new class { public function b(): c {} } ] : []); +/* testClosureWithUseNoReturnType */ +$closure = function () use($a) /*comment*/ {}; + +/* testClosureWithUseNoReturnTypeIllegalUseProp */ +$closure = function () use ($this->prop){}; + +/* testClosureWithUseWithReturnType */ +$closure = function () use /*comment*/ ($a): Type {}; + +/* testClosureWithUseMultiParamWithReturnType */ +$closure = function () use ($a, &$b, $c, $d, $e, $f, $g): ?array {}; + /* testArrowFunctionLiveCoding */ // Intentional parse error. This has to be the last test in the file. $fn = fn diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodPropertiesTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodPropertiesTest.php similarity index 84% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodPropertiesTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodPropertiesTest.php index 85a36bb2b..2b47ebbe4 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetMethodPropertiesTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetMethodPropertiesTest.php @@ -7,7 +7,7 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\File; +namespace PHP_CodeSniffer\Tests\Core\Files\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; @@ -356,7 +356,7 @@ public function testReturnNamespace() /** - * Test a method with a messy namespaces return type. + * Test a method with a messy namespaced return type. * * @return void */ @@ -1187,6 +1187,136 @@ public function testPHP82PseudoTypeFalseAndTrue() }//end testPHP82PseudoTypeFalseAndTrue() + /** + * Verify recognition of PHP 8.2 DNF return type declaration. + * + * @return void + */ + public function testPHP82DNFType() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'bool|(Foo&Bar)|string', + 'return_type_token' => 8, + 'return_type_end_token' => 16, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFType() + + + /** + * Verify recognition of PHP 8.2 DNF return type declaration on an abstract method. + * + * @return void + */ + public function testPHP82DNFTypeAbstractMethod() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'protected', + 'scope_specified' => true, + 'return_type' => 'float|(Foo&Bar)', + 'return_type_token' => 8, + 'return_type_end_token' => 14, + 'nullable_return_type' => false, + 'is_abstract' => true, + 'is_final' => false, + 'is_static' => false, + 'has_body' => false, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypeAbstractMethod() + + + /** + * Verify recognition of PHP 8.2 DNF return type declaration with illegal nullability. + * + * @return void + */ + public function testPHP82DNFTypeIllegalNullable() + { + // Offsets are relative to the T_FUNCTION token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?(A&\Pck\B)|bool', + 'return_type_token' => 8, + 'return_type_end_token' => 17, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypeIllegalNullable() + + + /** + * Verify recognition of PHP 8.2 DNF return type declaration on a closure. + * + * @return void + */ + public function testPHP82DNFTypeClosure() + { + // Offsets are relative to the T_CLOSURE token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'object|(namespace\Foo&Countable)', + 'return_type_token' => 6, + 'return_type_end_token' => 14, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypeClosure() + + + /** + * Verify recognition of PHP 8.2 DNF return type declaration on an arrow function. + * + * @return void + */ + public function testPHP82DNFTypeFn() + { + // Offsets are relative to the T_FN token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'null|(Partially\Qualified&Traversable)|void', + 'return_type_token' => 6, + 'return_type_end_token' => 16, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testPHP82DNFTypeFn() + + /** * Test for incorrect tokenization of array return type declarations in PHPCS < 2.8.0. * @@ -1297,6 +1427,111 @@ public function testFunctionDeclarationNestedInTernaryPHPCS2975() }//end testFunctionDeclarationNestedInTernaryPHPCS2975() + /** + * Test handling of closure declarations with a use variable import without a return type declaration. + * + * @return void + */ + public function testClosureWithUseNoReturnType() + { + // Offsets are relative to the T_CLOSURE token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testClosureWithUseNoReturnType() + + + /** + * Test handling of closure declarations with an illegal use variable for a property import (not allowed in PHP) + * without a return type declaration. + * + * @return void + */ + public function testClosureWithUseNoReturnTypeIllegalUseProp() + { + // Offsets are relative to the T_CLOSURE token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '', + 'return_type_token' => false, + 'return_type_end_token' => false, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testClosureWithUseNoReturnTypeIllegalUseProp() + + + /** + * Test handling of closure declarations with a use variable import with a return type declaration. + * + * @return void + */ + public function testClosureWithUseWithReturnType() + { + // Offsets are relative to the T_CLOSURE token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => 'Type', + 'return_type_token' => 14, + 'return_type_end_token' => 14, + 'nullable_return_type' => false, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testClosureWithUseWithReturnType() + + + /** + * Test handling of closure declarations with a use variable import with a return type declaration. + * + * @return void + */ + public function testClosureWithUseMultiParamWithReturnType() + { + // Offsets are relative to the T_CLOSURE token. + $expected = [ + 'scope' => 'public', + 'scope_specified' => false, + 'return_type' => '?array', + 'return_type_token' => 32, + 'return_type_end_token' => 32, + 'nullable_return_type' => true, + 'is_abstract' => false, + 'is_final' => false, + 'is_static' => false, + 'has_body' => true, + ]; + + $this->getMethodPropertiesTestHelper('/* '.__FUNCTION__.' */', $expected); + + }//end testClosureWithUseMultiParamWithReturnType() + + /** * Test helper. * diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetTokensAsStringTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetTokensAsStringTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetTokensAsStringTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetTokensAsStringTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetTokensAsStringTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetTokensAsStringTest.php similarity index 98% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetTokensAsStringTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetTokensAsStringTest.php index 7db977aaf..1adb94672 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/GetTokensAsStringTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/GetTokensAsStringTest.php @@ -7,7 +7,7 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\File; +namespace PHP_CodeSniffer\Tests\Core\Files\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; @@ -106,7 +106,7 @@ public function testLengthBeyondEndOfFile() * @param int $length Token length to get. * @param string $expected The expected function return value. * - * @dataProvider dataGetTokensAsString() + * @dataProvider dataGetTokensAsString * * @return void */ @@ -281,7 +281,7 @@ public static function dataGetTokensAsString() * @param int $length Token length to get. * @param string $expected The expected function return value. * - * @dataProvider dataGetOrigContent() + * @dataProvider dataGetOrigContent * * @return void */ diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/IsReferenceTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/IsReferenceTest.inc similarity index 95% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/IsReferenceTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/IsReferenceTest.inc index 93c7acc67..05af83905 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/IsReferenceTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/IsReferenceTest.inc @@ -169,7 +169,7 @@ functionCall( $something , &new Foobar() ); $closure = function() use (&$var){}; /* testUseByReferenceWithCommentFirstParam */ -$closure = function() use /*comment*/ (&$this->value){}; +$closure = function() use /*comment*/ (&$value){}; /* testUseByReferenceWithCommentSecondParam */ $closure = function() use /*comment*/ ($varA, &$varB){}; @@ -201,6 +201,12 @@ $closure = function &($param) use ($value) {}; /* testBitwiseAndArrowFunctionInDefault */ $fn = fn( $one = E_NOTICE & E_STRICT) => 1; +/* testIntersectionIsNotReference */ +function intersect(Foo&Bar $param) {} + +/* testDNFTypeIsNotReference */ +$fn = fn((Foo&\Bar)|null /* testParamPassByReference */ &$param) => $param; + /* testTokenizerIssue1284PHPCSlt280A */ if ($foo) {} [&$a, /* testTokenizerIssue1284PHPCSlt280B */ &$b] = $c; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/IsReferenceTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/IsReferenceTest.php similarity index 91% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/File/IsReferenceTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/IsReferenceTest.php index bbe31baef..bd9085394 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/File/IsReferenceTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Files/File/IsReferenceTest.php @@ -7,7 +7,7 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\File; +namespace PHP_CodeSniffer\Tests\Core\Files\File; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; @@ -23,29 +23,63 @@ final class IsReferenceTest extends AbstractMethodUnitTest /** * Test that false is returned when a non-"bitwise and" token is passed. * + * @param string $testMarker Comment which precedes the test case. + * @param array $targetTokens Type of tokens to look for. + * + * @dataProvider dataNotBitwiseAndToken + * * @return void */ - public function testNotBitwiseAndToken() + public function testNotBitwiseAndToken($testMarker, $targetTokens) { - $target = $this->getTargetToken('/* testBitwiseAndA */', T_STRING); + $targetTokens[] = T_BITWISE_AND; + + $target = $this->getTargetToken($testMarker, $targetTokens); $this->assertFalse(self::$phpcsFile->isReference($target)); }//end testNotBitwiseAndToken() + /** + * Data provider. + * + * @see testNotBitwiseAndToken() + * + * @return array>> + */ + public static function dataNotBitwiseAndToken() + { + return [ + 'Not ampersand token at all' => [ + 'testMarker' => '/* testBitwiseAndA */', + 'targetTokens' => [T_STRING], + ], + 'ampersand in intersection type' => [ + 'testMarker' => '/* testIntersectionIsNotReference */', + 'targetTokens' => [T_TYPE_INTERSECTION], + ], + 'ampersand in DNF type' => [ + 'testMarker' => '/* testDNFTypeIsNotReference */', + 'targetTokens' => [T_TYPE_INTERSECTION], + ], + ]; + + }//end dataNotBitwiseAndToken() + + /** * Test correctly identifying whether a "bitwise and" token is a reference or not. * - * @param string $identifier Comment which precedes the test case. + * @param string $testMarker Comment which precedes the test case. * @param bool $expected Expected function output. * * @dataProvider dataIsReference * * @return void */ - public function testIsReference($identifier, $expected) + public function testIsReference($testMarker, $expected) { - $bitwiseAnd = $this->getTargetToken($identifier, T_BITWISE_AND); + $bitwiseAnd = $this->getTargetToken($testMarker, T_BITWISE_AND); $result = self::$phpcsFile->isReference($bitwiseAnd); $this->assertSame($expected, $result); @@ -338,6 +372,10 @@ public static function dataIsReference() 'testMarker' => '/* testBitwiseAndArrowFunctionInDefault */', 'expected' => false, ], + 'reference: param pass by ref in arrow function' => [ + 'testMarker' => '/* testParamPassByReference */', + 'expected' => true, + ], 'issue-1284-short-list-directly-after-close-curly-control-structure' => [ 'testMarker' => '/* testTokenizerIssue1284PHPCSlt280A */', 'expected' => true, diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/AbstractFilterTestCase.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/AbstractFilterTestCase.php index d196ce691..3627d4aa2 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/AbstractFilterTestCase.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/AbstractFilterTestCase.php @@ -51,6 +51,29 @@ public static function initializeConfigAndRuleset() }//end initializeConfigAndRuleset() + /** + * Clean up after finished test by resetting all static properties on the Config class to their default values. + * + * Note: This is a PHPUnit cross-version compatible {@see \PHPUnit\Framework\TestCase::tearDownAfterClass()} + * method. + * + * @afterClass + * + * @return void + */ + public static function reset() + { + // Explicitly trigger __destruct() on the ConfigDouble to reset the Config statics. + // The explicit method call prevents potential stray test-local references to the $config object + // preventing the destructor from running the clean up (which without stray references would be + // automagically triggered when `self::$phpcsFile` is reset, but we can't definitively rely on that). + if (isset(self::$config) === true) { + self::$config->__destruct(); + } + + }//end reset() + + /** * Helper method to retrieve a mock object for a Filter class. * @@ -184,8 +207,8 @@ protected static function getFakeFileList() $basedir.'/src/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php', $basedir.'/src/Standards/Squiz/Tests', $basedir.'/src/Standards/Squiz/Tests/WhiteSpace', - $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc', - $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc.fixed', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc.fixed', $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js', $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed', $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php', @@ -200,10 +223,10 @@ protected static function getFakeFileList() * These type of tests should be able to run and pass on both *nix as well as Windows * based dev systems. This method is a helper to allow for this. * - * @param array $paths A single or multi-dimensional array containing - * file paths. + * @param array> $paths A single or multi-dimensional array containing + * file paths. * - * @return array + * @return array> */ protected static function mapPathsToRuntimeOs(array $paths) { diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/Filter/AcceptTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/Filter/AcceptTest.php index 8d622061d..d4da0a248 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/Filter/AcceptTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/Filter/AcceptTest.php @@ -56,7 +56,7 @@ public function testExcludePatterns($inputPaths, $expectedOutput) $fakeDI = new RecursiveArrayIterator($inputPaths); $filter = new Filter($fakeDI, '/', self::$config, self::$ruleset); - $this->assertEquals($expectedOutput, $this->getFilteredResultsAsArray($filter)); + $this->assertSame($expectedOutput, $this->getFilteredResultsAsArray($filter)); }//end testExcludePatterns() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/Filter/AcceptTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/Filter/AcceptTest.xml index 3d3e1de08..2800298eb 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/Filter/AcceptTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/Filter/AcceptTest.xml @@ -8,6 +8,8 @@ */Other/Main\.php$ + + /anything/* diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/GitModifiedTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/GitModifiedTest.php index 1b2189f90..c0b652126 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/GitModifiedTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/GitModifiedTest.php @@ -9,6 +9,7 @@ namespace PHP_CodeSniffer\Tests\Core\Filters; +use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Filters\GitModified; use PHP_CodeSniffer\Tests\Core\Filters\AbstractFilterTestCase; use RecursiveArrayIterator; @@ -45,7 +46,7 @@ public function testFileNamePassesAsBasePathWillTranslateToDirname() ->method('exec') ->willReturn(['autoload.php']); - $this->assertEquals([$rootFile], $this->getFilteredResultsAsArray($mockObj)); + $this->assertSame([$rootFile], $this->getFilteredResultsAsArray($mockObj)); }//end testFileNamePassesAsBasePathWillTranslateToDirname() @@ -76,7 +77,7 @@ public function testAcceptOnlyGitModified($inputPaths, $outputGitModified, $expe ->method('exec') ->willReturn($outputGitModified); - $this->assertEquals($expectedOutput, $this->getFilteredResultsAsArray($mockObj)); + $this->assertSame($expectedOutput, $this->getFilteredResultsAsArray($mockObj)); }//end testAcceptOnlyGitModified() @@ -175,8 +176,8 @@ public static function dataAcceptOnlyGitModified() '.yamllint.yml', 'autoload.php', 'src/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php', - 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc', - 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc.fixed', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc.fixed', 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js', 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed', 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php', @@ -191,7 +192,7 @@ public static function dataAcceptOnlyGitModified() $basedir.'/src/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php', $basedir.'/src/Standards/Squiz/Tests', $basedir.'/src/Standards/Squiz/Tests/WhiteSpace', - $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc', $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js', $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php', ], @@ -219,6 +220,10 @@ public function testExecAlwaysReturnsArray($cmd, $expected) $this->markTestSkipped('Not a git repository'); } + if (Config::getExecutablePath('git') === null) { + $this->markTestSkipped('git command not available'); + } + $fakeDI = new RecursiveArrayIterator(self::getFakeFileList()); $filter = new GitModified($fakeDI, '/', self::$config, self::$ruleset); diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/GitStagedTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/GitStagedTest.php index 545f5839f..0c936dedd 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/GitStagedTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Filters/GitStagedTest.php @@ -9,6 +9,7 @@ namespace PHP_CodeSniffer\Tests\Core\Filters; +use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Filters\GitStaged; use PHP_CodeSniffer\Tests\Core\Filters\AbstractFilterTestCase; use RecursiveArrayIterator; @@ -45,7 +46,7 @@ public function testFileNamePassesAsBasePathWillTranslateToDirname() ->method('exec') ->willReturn(['autoload.php']); - $this->assertEquals([$rootFile], $this->getFilteredResultsAsArray($mockObj)); + $this->assertSame([$rootFile], $this->getFilteredResultsAsArray($mockObj)); }//end testFileNamePassesAsBasePathWillTranslateToDirname() @@ -76,7 +77,7 @@ public function testAcceptOnlyGitStaged($inputPaths, $outputGitStaged, $expected ->method('exec') ->willReturn($outputGitStaged); - $this->assertEquals($expectedOutput, $this->getFilteredResultsAsArray($mockObj)); + $this->assertSame($expectedOutput, $this->getFilteredResultsAsArray($mockObj)); }//end testAcceptOnlyGitStaged() @@ -175,8 +176,8 @@ public static function dataAcceptOnlyGitStaged() '.yamllint.yml', 'autoload.php', 'src/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php', - 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc', - 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc.fixed', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc', + 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc.fixed', 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js', 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js.fixed', 'src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php', @@ -191,7 +192,7 @@ public static function dataAcceptOnlyGitStaged() $basedir.'/src/Standards/Squiz/Sniffs/WhiteSpace/OperatorSpacingSniff.php', $basedir.'/src/Standards/Squiz/Tests', $basedir.'/src/Standards/Squiz/Tests/WhiteSpace', - $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.inc', + $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.1.inc', $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.js', $basedir.'/src/Standards/Squiz/Tests/WhiteSpace/OperatorSpacingUnitTest.php', ], @@ -219,6 +220,10 @@ public function testExecAlwaysReturnsArray($cmd, $expected) $this->markTestSkipped('Not a git repository'); } + if (Config::getExecutablePath('git') === null) { + $this->markTestSkipped('git command not available'); + } + $fakeDI = new RecursiveArrayIterator(self::getFakeFileList()); $filter = new GitStaged($fakeDI, '/', self::$config, self::$ruleset); @@ -240,7 +245,7 @@ public function testExecAlwaysReturnsArray($cmd, $expected) * JRF: I've not managed to find a command which does so, let alone one, which then * doesn't have side-effects of uncatchable output while running the tests.} * - * @return array>> + * @return array>> */ public static function dataExecAlwaysReturnsArray() { diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/FixFileReturnValueAllGoodTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/FixFileReturnValueAllGoodTest.xml new file mode 100644 index 000000000..f71fd566e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/FixFileReturnValueAllGoodTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/FixFileReturnValueConflictTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/FixFileReturnValueConflictTest.xml new file mode 100644 index 000000000..732cfc517 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/FixFileReturnValueConflictTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/FixFileReturnValueNotEnoughLoopsTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/FixFileReturnValueNotEnoughLoopsTest.xml new file mode 100644 index 000000000..9072dd71d --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/FixFileReturnValueNotEnoughLoopsTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/FixFileReturnValueTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/FixFileReturnValueTest.php new file mode 100644 index 000000000..76e56364c --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/FixFileReturnValueTest.php @@ -0,0 +1,89 @@ +process(); + $fixed = $phpcsFile->fixer->fixFile(); + + $this->assertTrue($fixed); + + }//end testReturnValueIsTrueWhenFileWasFixed() + + + /** + * Test that the return value of the fixFile() method is false when the file failed to make all fixes. + * + * @param string $standard The ruleset file to use for the test. + * + * @dataProvider dataReturnValueIsFalse + * + * @return void + */ + public function testReturnValueIsFalse($standard) + { + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $testCaseFile = __DIR__.'/Fixtures/test.inc'; + $phpcsFile = new LocalFile($testCaseFile, $ruleset, $config); + $phpcsFile->process(); + $fixed = $phpcsFile->fixer->fixFile(); + + $this->assertFalse($fixed); + + }//end testReturnValueIsFalse() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataReturnValueIsFalse() + { + return [ + 'when there is a fixer conflict' => [ + 'standard' => __DIR__.'/FixFileReturnValueConflictTest.xml', + ], + 'when the fixer ran out of loops before all fixes could be applied' => [ + 'standard' => __DIR__.'/FixFileReturnValueNotEnoughLoopsTest.xml', + ], + ]; + + }//end dataReturnValueIsFalse() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/GenerateDiffTest-BlankLinesAtEnd.diff b/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/GenerateDiffTest-BlankLinesAtEnd.diff new file mode 100644 index 000000000..b9a217ed2 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/GenerateDiffTest-BlankLinesAtEnd.diff @@ -0,0 +1,10 @@ +--- tests/Core/Fixer/Fixtures/GenerateDiffTest-BlankLinesAtEnd.inc ++++ PHP_CodeSniffer +@@ -5,7 +5,3 @@ + if ($var) { + echo 'This line is tab indented'; + } +- +- +- +- diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/GenerateDiffTest-BlankLinesAtEnd.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/GenerateDiffTest-BlankLinesAtEnd.inc new file mode 100644 index 000000000..2e65b2b50 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/GenerateDiffTest-BlankLinesAtEnd.inc @@ -0,0 +1,11 @@ +getTokens(); + + if ($tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE + || $tokens[($stackPtr + 1)]['length'] > 51 + ) { + return; + } + + $error = 'There should be 52 spaces after an ECHO keyword'; + $fix = $phpcsFile->addFixableError($error, ($stackPtr + 1), 'ShortSpace'); + if ($fix === true) { + $phpcsFile->fixer->replaceToken(($stackPtr + 1), str_repeat(' ', 52)); + } + } +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/TestStandard/Sniffs/FixFileReturnValue/ConflictSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/TestStandard/Sniffs/FixFileReturnValue/ConflictSniff.php new file mode 100644 index 000000000..ca7afb915 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/TestStandard/Sniffs/FixFileReturnValue/ConflictSniff.php @@ -0,0 +1,101 @@ +getTokens(); + + // Demand a blank line after the PHP open tag. + // This error is here to ensure something will be fixed in the file. + $nextNonWhitespace = $phpcsFile->findNext(T_WHITESPACE, ($stackPtr + 1), null, true); + + if (($tokens[$nextNonWhitespace]['line'] - $tokens[$stackPtr]['line']) !== 2) { + $error = 'There must be a single blank line after the PHP open tag'; + $fix = $phpcsFile->addFixableError($error, $stackPtr, 'BlankLineAfterOpen'); + if ($fix === true) { + $phpcsFile->fixer->addNewline($stackPtr); + + // This return is here deliberately to force a new loop. + // This should ensure that loop 50 does *NOT* apply any fixes. + return; + } + } + + // Skip to the end of the file. + $stackPtr = ($phpcsFile->numTokens - 1); + + $eolCharLen = strlen($phpcsFile->eolChar); + $lastChars = substr($tokens[$stackPtr]['content'], ($eolCharLen * -1)); + + // Demand a newline at the end of a file. + if ($lastChars !== $phpcsFile->eolChar) { + $error = 'File must end with a newline character'; + $fix = $phpcsFile->addFixableError($error, $stackPtr, 'NoNewlineEOF'); + if ($fix === true) { + $phpcsFile->fixer->addNewline($stackPtr); + } + } + + // Demand NO newline at the end of a file. + if ($lastChars === $phpcsFile->eolChar) { + $error = 'File must not end with a newline character'; + $fix = $phpcsFile->addFixableError($error, $stackPtr, 'NewlineEOF'); + if ($fix === true) { + $phpcsFile->fixer->beginChangeset(); + + for ($i = $stackPtr; $i > 0; $i--) { + $newContent = rtrim($tokens[$i]['content'], $phpcsFile->eolChar); + $phpcsFile->fixer->replaceToken($i, $newContent); + + if ($newContent !== '') { + break; + } + } + + $phpcsFile->fixer->endChangeset(); + } + } + + // Ignore the rest of the file. + return $phpcsFile->numTokens; + } +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/TestStandard/Sniffs/FixFileReturnValue/NotEnoughLoopsSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/TestStandard/Sniffs/FixFileReturnValue/NotEnoughLoopsSniff.php new file mode 100644 index 000000000..e42d3fd7e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/TestStandard/Sniffs/FixFileReturnValue/NotEnoughLoopsSniff.php @@ -0,0 +1,40 @@ +getTokens(); + + if ($tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE + || $tokens[($stackPtr + 1)]['length'] > 60 + ) { + return; + } + + $error = 'There should be 60 spaces after an ECHO keyword'; + $fix = $phpcsFile->addFixableError($error, ($stackPtr + 1), 'ShortSpace'); + if ($fix === true) { + // The fixer deliberately only adds one space in each loop to ensure it runs out of loops before the file complies. + $phpcsFile->fixer->addContent($stackPtr, ' '); + } + } +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/TestStandard/ruleset.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/TestStandard/ruleset.xml new file mode 100644 index 000000000..6a202de3e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/TestStandard/ruleset.xml @@ -0,0 +1,4 @@ + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/test.inc new file mode 100644 index 000000000..76195b04c --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Fixer/Fixtures/test.inc @@ -0,0 +1,2 @@ + + * @copyright 2024 Juliette Reinders Folmer. All rights reserved. + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Fixer; + +use PHP_CodeSniffer\Files\LocalFile; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Tests for diff generation. + * + * Note: these tests are specifically about the Fixer::generateDiff() method and do not + * test running the fixer itself, nor generating a diff based on a fixer run. + * + * @covers PHP_CodeSniffer\Fixer::generateDiff + * @group Windows + */ +final class GenerateDiffTest extends TestCase +{ + + /** + * A \PHP_CodeSniffer\Files\File object to compare the files against. + * + * @var \PHP_CodeSniffer\Files\LocalFile + */ + private static $phpcsFile; + + + /** + * Initialize an \PHP_CodeSniffer\Files\File object with code. + * + * Things to take note of in the code snippet used for these tests: + * - Line endings are \n. + * - Tab indent. + * - Trailing whitespace. + * + * Also note that the Config object is deliberately created without a `tabWidth` setting to + * prevent doing tab replacement when parsing the file. This is to allow for testing a + * diff with tabs vs spaces (which wouldn't yield a diff if tabs had already been replaced). + * + * @beforeClass + * + * @return void + */ + public static function initializeFile() + { + $config = new ConfigDouble(); + $ruleset = new Ruleset($config); + + self::$phpcsFile = new LocalFile(__DIR__.'/Fixtures/GenerateDiffTest.inc', $ruleset, $config); + self::$phpcsFile->parse(); + self::$phpcsFile->fixer->startFile(self::$phpcsFile); + + }//end initializeFile() + + + /** + * Test generating a diff on the file object itself. + * + * @return void + */ + public function testGenerateDiffNoFile() + { + $diff = self::$phpcsFile->fixer->generateDiff(null, false); + + $this->assertSame('', $diff); + + }//end testGenerateDiffNoFile() + + + /** + * Test generating a diff between a PHPCS File object and a file on disk. + * + * @param string $filePath The path to the file to compare the File object against. + * + * @dataProvider dataGenerateDiff + * + * @return void + */ + public function testGenerateDiff($filePath) + { + $diff = self::$phpcsFile->fixer->generateDiff($filePath, false); + + // Allow for the tests to pass on Windows too. + $diff = str_replace('--- tests\Core\Fixer/', '--- tests/Core/Fixer/', $diff); + + $expectedDiffFile = str_replace('.inc', '.diff', $filePath); + + $this->assertStringEqualsFile($expectedDiffFile, $diff); + + }//end testGenerateDiff() + + + /** + * Data provider. + * + * @see testGenerateDiff() + * + * @return array> + */ + public static function dataGenerateDiff() + { + return [ + 'no difference' => [ + 'filePath' => __DIR__.'/Fixtures/GenerateDiffTest-NoDiff.inc', + ], + 'line removed' => [ + 'filePath' => __DIR__.'/Fixtures/GenerateDiffTest-LineRemoved.inc', + ], + 'line added' => [ + 'filePath' => __DIR__.'/Fixtures/GenerateDiffTest-LineAdded.inc', + ], + 'var name changed' => [ + 'filePath' => __DIR__.'/Fixtures/GenerateDiffTest-VarNameChanged.inc', + ], + 'trailing whitespace removed' => [ + 'filePath' => __DIR__.'/Fixtures/GenerateDiffTest-NoTrailingWhitespace.inc', + ], + 'tab replaced with spaces' => [ + 'filePath' => __DIR__.'/Fixtures/GenerateDiffTest-TabsToSpaces.inc', + ], + 'blank lines at start of file' => [ + 'filePath' => __DIR__.'/Fixtures/GenerateDiffTest-BlankLinesAtStart.inc', + ], + 'whitespace diff at start of file' => [ + 'filePath' => __DIR__.'/Fixtures/GenerateDiffTest-WhiteSpaceAtStart.inc', + ], + 'blank lines at end of file' => [ + 'filePath' => __DIR__.'/Fixtures/GenerateDiffTest-BlankLinesAtEnd.inc', + ], + 'whitespace diff at end of file' => [ + 'filePath' => __DIR__.'/Fixtures/GenerateDiffTest-WhiteSpaceAtEnd.inc', + ], + ]; + + }//end dataGenerateDiff() + + + /** + * Test generating a diff between a PHPCS File object and a file on disk and colourizing the output. + * + * @return void + */ + public function testGenerateDiffColoured() + { + $expected = "\033[31m--- tests/Core/Fixer/Fixtures/GenerateDiffTest-VarNameChanged.inc\033[0m".PHP_EOL; + $expected .= "\033[32m+++ PHP_CodeSniffer\033[0m".PHP_EOL; + $expected .= '@@ -1,7 +1,7 @@'.PHP_EOL; + $expected .= ' fixer->generateDiff($filePath); + + // Allow for the tests to pass on Windows too. + $diff = str_replace('--- tests\Core\Fixer/', '--- tests/Core/Fixer/', $diff); + + $this->assertSame($expected, $diff); + + }//end testGenerateDiffColoured() + + + /** + * Test generating a diff between a PHPCS File object using *nix line endings and a file on disk + * using Windows line endings. + * + * The point of this test is to verify that all lines are marked as having a difference. + * The actual lines endings used in the diff shown to the end-user are not relevant for this + * test. + * As the "diff" command is finicky with what type of line endings are used when the only + * difference on a line is the line ending, the test normalizes the line endings of the + * received diff before testing it. + * + * @return void + */ + public function testGenerateDiffDifferentLineEndings() + { + // By the looks of it, if the only diff between two files is line endings, the + // diff generated by the *nix "diff" command will always contain *nix line endings. + $expected = '--- tests/Core/Fixer/Fixtures/GenerateDiffTest-WindowsLineEndings.inc'."\n"; + $expected .= '+++ PHP_CodeSniffer'."\n"; + $expected .= '@@ -1,7 +1,7 @@'."\n"; + $expected .= '-fixer->generateDiff($filePath, false); + + // Allow for the tests to pass on Windows too. + $diff = str_replace('--- tests\Core\Fixer/', '--- tests/Core/Fixer/', $diff); + + // Normalize line endings of the diff. + $diff = preg_replace('`\R`', "\n", $diff); + + $this->assertSame($expected, $diff); + + }//end testGenerateDiffDifferentLineEndings() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/AllValidDocsTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/AllValidDocsTest.xml new file mode 100644 index 000000000..3bf637e6e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/AllValidDocsTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/AnchorLinksTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/AnchorLinksTest.xml new file mode 100644 index 000000000..17fb0cee0 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/AnchorLinksTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.html new file mode 100644 index 000000000..a51ad92a8 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.html @@ -0,0 +1,105 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Comparison, blank lines §

+

This is a standard block.

+ + + + + + + + + +
Valid: Checking handling of blank lines.Invalid: Checking handling of blank lines.
// First line of the code sample is
// deliberately empty.

// We also have a blank line in the middle.

// And a blank line at the end.
// First line of the code sample is
// deliberately empty.

// We also have a blank line in the middle.

// And a blank line at the end.
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.md new file mode 100644 index 000000000..ef25f893c --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.md @@ -0,0 +1,35 @@ +# GeneratorTest Coding Standard + +## Code Comparison, blank lines + +This is a standard block. + + + + + + + + + +
Valid: Checking handling of blank lines.Invalid: Checking handling of blank lines.
+ + // First line of the code sample is + // deliberately empty. + + // We also have a blank line in the middle. + + // And a blank line at the end. + + + + // First line of the code sample is + // deliberately empty. + + // We also have a blank line in the middle. + + // And a blank line at the end. + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.txt new file mode 100644 index 000000000..a7fd41d90 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlankLines.txt @@ -0,0 +1,18 @@ + +--------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE COMPARISON, BLANK LINES | +--------------------------------------------------------------- + +This is a standard block. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Checking handling of blank lines. | Invalid: Checking handling of blank lines. | +---------------------------------------------------------------------------------------------------- +| // First line of the code sample is | // First line of the code sample is | +| // deliberately empty. | // deliberately empty. | +| | | +| // We also have a blank line in the middle. | // We also have a blank line in the middle. | +| | | +| // And a blank line at the end. | // And a blank line at the end. | +---------------------------------------------------------------------------------------------------- + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.html new file mode 100644 index 000000000..881bac305 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.html @@ -0,0 +1,115 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Comparison, block length §

+

This is a standard block.

+ + + + + + + + + +
Valid: code sample A has more lines than B.Invalid: shorter.
// This code sample has more lines
// than the "invalid" one.
$one = 10;
$a = 10;
+ + + + + + + + + +
Valid: shorter.Invalid: code sample B has more lines than A.
echo $foo;// This code sample has more lines
// than the "valid" one.
print $foo;
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.md new file mode 100644 index 000000000..526f110b3 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.md @@ -0,0 +1,47 @@ +# GeneratorTest Coding Standard + +## Code Comparison, block length + +This is a standard block. + + + + + + + + + +
Valid: code sample A has more lines than B.Invalid: shorter.
+ + // This code sample has more lines + // than the "invalid" one. + $one = 10; + + + + $a = 10; + +
+ + + + + + + + + +
Valid: shorter.Invalid: code sample B has more lines than A.
+ + echo $foo; + + + + // This code sample has more lines + // than the "valid" one. + print $foo; + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.txt new file mode 100644 index 000000000..c2fb737f4 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonBlockLength.txt @@ -0,0 +1,23 @@ + +---------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE COMPARISON, BLOCK LENGTH | +---------------------------------------------------------------- + +This is a standard block. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: code sample A has more lines than B. | Invalid: shorter. | +---------------------------------------------------------------------------------------------------- +| // This code sample has more lines | $a = 10; | +| // than the "invalid" one. | | +| $one = 10; | | +---------------------------------------------------------------------------------------------------- + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: shorter. | Invalid: code sample B has more lines than A. | +---------------------------------------------------------------------------------------------------- +| echo $foo; | // This code sample has more lines | +| | // than the "valid" one. | +| | print $foo; | +---------------------------------------------------------------------------------------------------- + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.html new file mode 100644 index 000000000..a325def17 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.html @@ -0,0 +1,105 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Comparison, char encoding §

+

This is a standard block.

+ + + + + + + + + +
Valid: Vestibulum et orci condimentum.Invalid: Donec in nisl ut tortor convallis interdum.
<?php

// The above PHP tag is specifically testing
// handling of that in generated HTML doc.

// Now let's also check the handling of
// comparison operators in code samples...
$a = $b < $c;
$d = $e > $f;
$g = $h <= $i;
$j = $k >= $l;
$m = $n <=> $o;
<?php

// The above PHP tag is specifically testing
// handling of that in generated HTML doc.

// Now let's also check the handling of
// comparison operators in code samples
// in combination with "em" tags.
$a = $b < $c;
$d = $e > $f;
$g = $h <= $i;
$j = $k >= $l;
$m = $n <=> $o;
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.md new file mode 100644 index 000000000..052d3cb3e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.md @@ -0,0 +1,48 @@ +# GeneratorTest Coding Standard + +## Code Comparison, char encoding + +This is a standard block. + + + + + + + + + +
Valid: Vestibulum et orci condimentum.Invalid: Donec in nisl ut tortor convallis interdum.
+ + $f; + $g = $h <= $i; + $j = $k >= $l; + $m = $n <=> $o; + + + + $f; + $g = $h <= $i; + $j = $k >= $l; + $m = $n <=> $o; + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.txt new file mode 100644 index 000000000..7ffcf4df5 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonEncoding.txt @@ -0,0 +1,26 @@ + +----------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE COMPARISON, CHAR ENCODING | +----------------------------------------------------------------- + +This is a standard block. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Vestibulum et orci condimentum. | Invalid: Donec in nisl ut tortor convallis | +| | interdum. | +---------------------------------------------------------------------------------------------------- +| $f; | $a = $b < $c; | +| $g = $h <= $i; | $d = $e > $f; | +| $j = $k >= $l; | $g = $h <= $i; | +| $m = $n <=> $o; | $j = $k >= $l; | +| | $m = $n <=> $o; | +---------------------------------------------------------------------------------------------------- + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.html new file mode 100644 index 000000000..b1e83a42b --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.html @@ -0,0 +1,106 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Comparison, line length §

+

Ensure there is no PHP "Warning: str_repeat(): Second argument has to be greater than or equal to 0".
+Ref: squizlabs/PHP_CodeSniffer#2522

+ + + + + + + + + +
Valid: contains line which is too long.Invalid: contains line which is too long.
class Foo extends Bar implements Countable, Serializable
{
}
class Foo extends Bar
{
    public static function foobar($param1, $param2) {}
}
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.md new file mode 100644 index 000000000..8dbf56426 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.md @@ -0,0 +1,31 @@ +# GeneratorTest Coding Standard + +## Code Comparison, line length + +Ensure there is no PHP "Warning: str_repeat(): Second argument has to be greater than or equal to 0". +Ref: squizlabs/PHP_CodeSniffer#2522 + + + + + + + + + +
Valid: contains line which is too long.Invalid: contains line which is too long.
+ + class Foo extends Bar implements Countable, Serializable + { + } + + + + class Foo extends Bar + { + public static function foobar($param1, $param2) {} + } + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.txt new file mode 100644 index 000000000..e8a665cd4 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeComparisonLineLength.txt @@ -0,0 +1,18 @@ + +--------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE COMPARISON, LINE LENGTH | +--------------------------------------------------------------- + +Ensure there is no PHP "Warning: str_repeat(): Second argument has to be greater than or equal to +0". +Ref: squizlabs/PHP_CodeSniffer#2522 + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: contains line which is too long. | Invalid: contains line which is too long. | +---------------------------------------------------------------------------------------------------- +| class Foo extends Bar implements Countable, Serializable| class Foo extends Bar | +| { | { | +| } | public static function foobar($param1, $param2) {}| +| | } | +---------------------------------------------------------------------------------------------------- + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.html new file mode 100644 index 000000000..dbe9966de --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.html @@ -0,0 +1,135 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Title, line wrapping §

+

This is a standard block.

+ + + + + + + + + +
Valid: exactly 45 character long description.Invalid: exactly 45 char long description---.
// Dummy.// Dummy.
+ + + + + + + + + +
Valid: exactly 46 character long description-.Invalid: exactly 46 character long description
// Dummy.// Dummy.
+ + + + + + + + + +
Valid: exactly 47 character long description--.Invalid: exactly 47 character long description.
// Dummy.// Dummy.
+ + + + + + + + + +
Valid: this description is longer than 46 characters and will wrap.Invalid: this description is longer than 46 characters and will wrap.
// Dummy.// Dummy.
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.md new file mode 100644 index 000000000..a0d6a8e6a --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.md @@ -0,0 +1,79 @@ +# GeneratorTest Coding Standard + +## Code Title, line wrapping + +This is a standard block. + + + + + + + + + +
Valid: exactly 45 character long description.Invalid: exactly 45 char long description---.
+ + // Dummy. + + + + // Dummy. + +
+ + + + + + + + + +
Valid: exactly 46 character long description-.Invalid: exactly 46 character long description
+ + // Dummy. + + + + // Dummy. + +
+ + + + + + + + + +
Valid: exactly 47 character long description--.Invalid: exactly 47 character long description.
+ + // Dummy. + + + + // Dummy. + +
+ + + + + + + + + +
Valid: this description is longer than 46 characters and will wrap.Invalid: this description is longer than 46 characters and will wrap.
+ + // Dummy. + + + + // Dummy. + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.txt new file mode 100644 index 000000000..11925c4cb --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleLineWrapping.txt @@ -0,0 +1,33 @@ + +------------------------------------------------------------ +| GENERATORTEST CODING STANDARD: CODE TITLE, LINE WRAPPING | +------------------------------------------------------------ + +This is a standard block. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: exactly 45 character long description. | Invalid: exactly 45 char long description---. | +---------------------------------------------------------------------------------------------------- +| // Dummy. | // Dummy. | +---------------------------------------------------------------------------------------------------- + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: exactly 46 character long description-. | Invalid: exactly 46 character long description | +---------------------------------------------------------------------------------------------------- +| // Dummy. | // Dummy. | +---------------------------------------------------------------------------------------------------- + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: exactly 47 character long | Invalid: exactly 47 character long | +| description--. | description. | +---------------------------------------------------------------------------------------------------- +| // Dummy. | // Dummy. | +---------------------------------------------------------------------------------------------------- + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: this description is longer than 46 | Invalid: this description is longer than 46 | +| characters and will wrap. | characters and will wrap. | +---------------------------------------------------------------------------------------------------- +| // Dummy. | // Dummy. | +---------------------------------------------------------------------------------------------------- + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.html new file mode 100644 index 000000000..65a5a25f3 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.html @@ -0,0 +1,115 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Title, whitespace handling §

+

This is a standard block.

+ + + + + + + + + +
Valid: spaces at start of description.Invalid: spaces at end making line > 46 chars.
// Dummy.// Dummy.
+ + + + + + + + + +
Valid: spaces at start + end of description.Invalid: spaces '     ' in description.
// Note: description above without the
// trailing whitespace fits in 46 chars.
// Dummy.
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.md new file mode 100644 index 000000000..e623ba98d --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.md @@ -0,0 +1,44 @@ +# GeneratorTest Coding Standard + +## Code Title, whitespace handling + +This is a standard block. + + + + + + + + + +
Valid: spaces at start of description.Invalid: spaces at end making line > 46 chars.
+ + // Dummy. + + + + // Dummy. + +
+ + + + + + + + + +
Valid: spaces at start + end of description.Invalid: spaces '     ' in description.
+ + // Note: description above without the + // trailing whitespace fits in 46 chars. + + + + // Dummy. + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.txt new file mode 100644 index 000000000..0db5a7dfa --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputCodeTitleWhitespace.txt @@ -0,0 +1,20 @@ + +------------------------------------------------------------------ +| GENERATORTEST CODING STANDARD: CODE TITLE, WHITESPACE HANDLING | +------------------------------------------------------------------ + +This is a standard block. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: spaces at start of description. | Invalid: spaces at end making line > 46 chars. | +---------------------------------------------------------------------------------------------------- +| // Dummy. | // Dummy. | +---------------------------------------------------------------------------------------------------- + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: spaces at start + end of description. | Invalid: spaces ' ' in description. | +---------------------------------------------------------------------------------------------------- +| // Note: description above without the | // Dummy. | +| // trailing whitespace fits in 46 chars. | | +---------------------------------------------------------------------------------------------------- + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.html new file mode 100644 index 000000000..e72265197 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.html @@ -0,0 +1,95 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

lowercase title §

+

This is a standard block.

+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.md new file mode 100644 index 000000000..0d63b04a9 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.md @@ -0,0 +1,7 @@ +# GeneratorTest Coding Standard + +## lowercase title + +This is a standard block. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.txt new file mode 100644 index 000000000..c762a01d9 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleCase.txt @@ -0,0 +1,7 @@ + +-------------------------------------------------- +| GENERATORTEST CODING STANDARD: LOWERCASE TITLE | +-------------------------------------------------- + +This is a standard block. + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.html new file mode 100644 index 000000000..2640a6bfd --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.html @@ -0,0 +1,95 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

This is a very very very very very very very very very very very long title §

+

This is a standard block.

+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.md new file mode 100644 index 000000000..252f5fca6 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.md @@ -0,0 +1,7 @@ +# GeneratorTest Coding Standard + +## This is a very very very very very very very very very very very long title + +This is a standard block. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.txt new file mode 100644 index 000000000..2787b8cdf --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleLength.txt @@ -0,0 +1,7 @@ + +-------------------------------------------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: THIS IS A VERY VERY VERY VERY VERY VERY VERY VERY VERY VERY VERY LONG TITLE | +-------------------------------------------------------------------------------------------------------------- + +This is a standard block. + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitlePCREFallback.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitlePCREFallback.html new file mode 100644 index 000000000..b83b5e679 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitlePCREFallback.html @@ -0,0 +1,96 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Documentation Title PCRE Fallback §

+

Testing the document title can get determined from the sniff name if missing.

+

This file name contains an acronym on purpose to test the word splitting.

+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitlePCREFallback.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitlePCREFallback.md new file mode 100644 index 000000000..844f4fbb4 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitlePCREFallback.md @@ -0,0 +1,9 @@ +# GeneratorTest Coding Standard + +## Documentation Title PCRE Fallback + +Testing the document title can get determined from the sniff name if missing. + +This file name contains an acronym on purpose to test the word splitting. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitlePCREFallback.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitlePCREFallback.txt new file mode 100644 index 000000000..342cdfda5 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitlePCREFallback.txt @@ -0,0 +1,9 @@ + +-------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: DOCUMENTATION TITLE PCRE FALLBACK | +-------------------------------------------------------------------- + +Testing the document title can get determined from the sniff name if missing. + +This file name contains an acronym on purpose to test the word splitting. + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleToAnchorSlug.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleToAnchorSlug.html new file mode 100644 index 000000000..1d9923991 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputDocumentationTitleToAnchorSlug.html @@ -0,0 +1,107 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Table of Contents

+ +

URL enc@de non-àscíï chars §

+

The documentation title has non-ascii characters, which will be slugified for use in an HTML anchor link.

+

URL enc@de non-àscíï chars §

+

The documentation title has non-ascii characters, which will be slugified for use in an HTML anchor link.
+A duplicate anchor link will get a numeric suffix.

+

URL enc@de non-àscíï chars §

+

The documentation title has non-ascii characters, which will be slugified for use in an HTML anchor link.
+A duplicate anchor link will get a numeric suffix.

+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputEmpty.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputEmpty.txt new file mode 100644 index 000000000..e69de29bb diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.html new file mode 100644 index 000000000..59fcc7eb9 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.html @@ -0,0 +1,105 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Comparison, mismatched code blocks §

+

This doc has two code elements, one only has a title, one has actual code. Unbalanced

+ + + + + + + + + +
Code title
$a = 'Example code';
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.md new file mode 100644 index 000000000..bbd1f312a --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.md @@ -0,0 +1,25 @@ +# GeneratorTest Coding Standard + +## Code Comparison, mismatched code blocks + +This doc has two code elements, one only has a title, one has actual code. Unbalanced + + + + + + + + + +
Code title
+ + + + + + $a = 'Example code'; + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.txt new file mode 100644 index 000000000..85b3f31a0 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.txt @@ -0,0 +1,13 @@ + +-------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE COMPARISON, MISMATCHED CODE BLOCKS | +-------------------------------------------------------------------------- + +This doc has two code elements, one only has a title, one has actual code. Unbalanced + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Code title | | +---------------------------------------------------------------------------------------------------- +| | $a = 'Example code'; | +---------------------------------------------------------------------------------------------------- + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.html new file mode 100644 index 000000000..9f29d6af6 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.html @@ -0,0 +1,95 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Comparison, missing code element §

+

This is a standard block.

+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.md new file mode 100644 index 000000000..4cd4b41b4 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.md @@ -0,0 +1,7 @@ +# GeneratorTest Coding Standard + +## Code Comparison, missing code element + +This is a standard block. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.txt new file mode 100644 index 000000000..0c3c6d13d --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.txt @@ -0,0 +1,7 @@ + +------------------------------------------------------------------------ +| GENERATORTEST CODING STANDARD: CODE COMPARISON, MISSING CODE ELEMENT | +------------------------------------------------------------------------ + +This is a standard block. + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.html new file mode 100644 index 000000000..35d9144ac --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.html @@ -0,0 +1,101 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Comparison, no code §

+

This is a standard block.

+ + + + + +
Valid: no code.Invalid: no code.
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.md new file mode 100644 index 000000000..afbf10635 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.md @@ -0,0 +1,13 @@ +# GeneratorTest Coding Standard + +## Code Comparison, no code + +This is a standard block. + + + + + +
Valid: no code.Invalid: no code.
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.txt new file mode 100644 index 000000000..f6091cabd --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.txt @@ -0,0 +1,10 @@ + +----------------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE COMPARISON, NO CODE | +----------------------------------------------------------- + +This is a standard block. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: no code. | Invalid: no code. | +---------------------------------------------------------------------------------------------------- diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.html new file mode 100644 index 000000000..b09f3ccf7 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.html @@ -0,0 +1,95 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Comparison, no content §

+

This is a standard block.

+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.md new file mode 100644 index 000000000..1cea477ff --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.md @@ -0,0 +1,7 @@ +# GeneratorTest Coding Standard + +## Code Comparison, no content + +This is a standard block. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.txt new file mode 100644 index 000000000..0227cdc82 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.txt @@ -0,0 +1,7 @@ + +-------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE COMPARISON, NO CONTENT | +-------------------------------------------------------------- + +This is a standard block. + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.html new file mode 100644 index 000000000..7ee4bee47 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.html @@ -0,0 +1,105 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Comparison, one empty code element §

+

This doc has two code elements, but only one of them has a title and actual code.

+ + + + + + + + + +
Code title
$a = 'Example code';
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.md new file mode 100644 index 000000000..829f13635 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.md @@ -0,0 +1,25 @@ +# GeneratorTest Coding Standard + +## Code Comparison, one empty code element + +This doc has two code elements, but only one of them has a title and actual code. + + + + + + + + + +
Code title
+ + $a = 'Example code'; + + + + + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.txt new file mode 100644 index 000000000..7e9370595 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.txt @@ -0,0 +1,13 @@ + +-------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE COMPARISON, ONE EMPTY CODE ELEMENT | +-------------------------------------------------------------------------- + +This doc has two code elements, but only one of them has a title and actual code. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Code title | | +---------------------------------------------------------------------------------------------------- +| $a = 'Example code'; | | +---------------------------------------------------------------------------------------------------- + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.html new file mode 100644 index 000000000..4cc553d4c --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.html @@ -0,0 +1,95 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Comparison, two empty code elements §

+

This doc has two code elements, but neither of them contain any information.

+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.md new file mode 100644 index 000000000..7d1387677 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.md @@ -0,0 +1,7 @@ +# GeneratorTest Coding Standard + +## Code Comparison, two empty code elements + +This doc has two code elements, but neither of them contain any information. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.txt new file mode 100644 index 000000000..775e7ceeb --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.txt @@ -0,0 +1,7 @@ + +--------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE COMPARISON, TWO EMPTY CODE ELEMENTS | +--------------------------------------------------------------------------- + +This doc has two code elements, but neither of them contain any information. + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleEmpty.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleEmpty.html new file mode 100644 index 000000000..0efa0572f --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleEmpty.html @@ -0,0 +1,101 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Title, empty §

+

This is a standard block.

+ + + + + +
// Dummy.// Dummy.
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleEmpty.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleEmpty.md new file mode 100644 index 000000000..728ccc0bc --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleEmpty.md @@ -0,0 +1,21 @@ +# GeneratorTest Coding Standard + +## Code Title, empty + +This is a standard block. + + + + + +
+ + // Dummy. + + + + // Dummy. + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleEmpty.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleEmpty.txt new file mode 100644 index 000000000..d3ac256b1 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleEmpty.txt @@ -0,0 +1,11 @@ + +---------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE TITLE, EMPTY | +---------------------------------------------------- + +This is a standard block. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| // Dummy. | // Dummy. | +---------------------------------------------------------------------------------------------------- + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleMissing.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleMissing.html new file mode 100644 index 000000000..755f5a18e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleMissing.html @@ -0,0 +1,101 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Code Title, missing §

+

This is a standard block.

+ + + + + +
// Dummy.// Dummy.
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleMissing.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleMissing.md new file mode 100644 index 000000000..98e582295 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleMissing.md @@ -0,0 +1,21 @@ +# GeneratorTest Coding Standard + +## Code Title, missing + +This is a standard block. + + + + + +
+ + // Dummy. + + + + // Dummy. + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleMissing.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleMissing.txt new file mode 100644 index 000000000..3de51f08d --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidCodeTitleMissing.txt @@ -0,0 +1,11 @@ + +------------------------------------------------------ +| GENERATORTEST CODING STANDARD: CODE TITLE, MISSING | +------------------------------------------------------ + +This is a standard block. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| // Dummy. | // Dummy. | +---------------------------------------------------------------------------------------------------- + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.html new file mode 100644 index 000000000..7d0d9aa55 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.html @@ -0,0 +1,105 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Documentation Title Empty §

+

The above "documentation" element has an empty title attribute.

+ + + + + + + + + +
Valid: Lorem ipsum dolor sit amet.Invalid: Maecenas non rutrum dolor.
class Code {}class Comparison {}
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.md new file mode 100644 index 000000000..db8b2e40e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.md @@ -0,0 +1,25 @@ +# GeneratorTest Coding Standard + +## Documentation Title Empty + +The above "documentation" element has an empty title attribute. + + + + + + + + + +
Valid: Lorem ipsum dolor sit amet.Invalid: Maecenas non rutrum dolor.
+ + class Code {} + + + + class Comparison {} + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.txt new file mode 100644 index 000000000..85fe3779b --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.txt @@ -0,0 +1,13 @@ + +------------------------------------------------------------ +| GENERATORTEST CODING STANDARD: DOCUMENTATION TITLE EMPTY | +------------------------------------------------------------ + +The above "documentation" element has an empty title attribute. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Lorem ipsum dolor sit amet. | Invalid: Maecenas non rutrum dolor. | +---------------------------------------------------------------------------------------------------- +| class Code {} | class Comparison {} | +---------------------------------------------------------------------------------------------------- + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.html new file mode 100644 index 000000000..2f51fd474 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.html @@ -0,0 +1,105 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Documentation Title Missing §

+

The above "documentation" element is missing the title attribute.

+ + + + + + + + + +
Valid: Lorem ipsum dolor sit amet.Invalid: Maecenas non rutrum dolor.
class Code {}class Comparison {}
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.md new file mode 100644 index 000000000..bd9ebfd14 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.md @@ -0,0 +1,25 @@ +# GeneratorTest Coding Standard + +## Documentation Title Missing + +The above "documentation" element is missing the title attribute. + + + + + + + + + +
Valid: Lorem ipsum dolor sit amet.Invalid: Maecenas non rutrum dolor.
+ + class Code {} + + + + class Comparison {} + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.txt new file mode 100644 index 000000000..d49520381 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.txt @@ -0,0 +1,13 @@ + +-------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: DOCUMENTATION TITLE MISSING | +-------------------------------------------------------------- + +The above "documentation" element is missing the title attribute. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Lorem ipsum dolor sit amet. | Invalid: Maecenas non rutrum dolor. | +---------------------------------------------------------------------------------------------------- +| class Code {} | class Comparison {} | +---------------------------------------------------------------------------------------------------- + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidStandardNoContent.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidStandardNoContent.html new file mode 100644 index 000000000..2eecc8ae8 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidStandardNoContent.html @@ -0,0 +1,104 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Standard Element, no content §

+ + + + + + + + + +
Valid: Lorem ipsum dolor sit amet.Invalid: Maecenas non rutrum dolor.
class Code {}class Comparison {}
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidStandardNoContent.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidStandardNoContent.md new file mode 100644 index 000000000..8d5dbc254 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidStandardNoContent.md @@ -0,0 +1,24 @@ +# GeneratorTest Coding Standard + +## Standard Element, no content + + + + + + + + + + +
Valid: Lorem ipsum dolor sit amet.Invalid: Maecenas non rutrum dolor.
+ + class Code {} + + + + class Comparison {} + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidStandardNoContent.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidStandardNoContent.txt new file mode 100644 index 000000000..c0b96c7b7 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputInvalidStandardNoContent.txt @@ -0,0 +1,11 @@ + +--------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: STANDARD ELEMENT, NO CONTENT | +--------------------------------------------------------------- + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Lorem ipsum dolor sit amet. | Invalid: Maecenas non rutrum dolor. | +---------------------------------------------------------------------------------------------------- +| class Code {} | class Comparison {} | +---------------------------------------------------------------------------------------------------- + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.html new file mode 100644 index 000000000..798ae6373 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.html @@ -0,0 +1,95 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

One Standard Block, No Code §

+

Documentation contains one standard block and no code comparison.

+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.md new file mode 100644 index 000000000..f6130736f --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.md @@ -0,0 +1,7 @@ +# GeneratorTest Coding Standard + +## One Standard Block, No Code + +Documentation contains one standard block and no code comparison. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.txt new file mode 100644 index 000000000..75bbdcb00 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputOneDoc.txt @@ -0,0 +1,7 @@ + +-------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: ONE STANDARD BLOCK, NO CODE | +-------------------------------------------------------------- + +Documentation contains one standard block and no code comparison. + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.html new file mode 100644 index 000000000..ceaab32a6 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.html @@ -0,0 +1,97 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Standard Element, blank line handling §

+

There is a blank line at the start of this standard.

+

And the above blank line is also deliberate to test part of the logic.

+

Let's also end on a blank line to test that too.

+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.md new file mode 100644 index 000000000..f8663f14f --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.md @@ -0,0 +1,11 @@ +# GeneratorTest Coding Standard + +## Standard Element, blank line handling + +There is a blank line at the start of this standard. + +And the above blank line is also deliberate to test part of the logic. + +Let's also end on a blank line to test that too. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.txt new file mode 100644 index 000000000..1cdad0b11 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardBlankLines.txt @@ -0,0 +1,11 @@ + +------------------------------------------------------------------------ +| GENERATORTEST CODING STANDARD: STANDARD ELEMENT, BLANK LINE HANDLING | +------------------------------------------------------------------------ + +There is a blank line at the start of this standard. + +And the above blank line is also deliberate to test part of the logic. + +Let's also end on a blank line to test that too. + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.html new file mode 100644 index 000000000..93a77d455 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.html @@ -0,0 +1,96 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Standard Element, handling of HTML tags §

+

The use of tags in standard descriptions is allowed and their handling should be safeguarded.
+Other tags, like <a href="example.com">link</a>, <b>bold</bold>, <script></script> are not allowed and will be encoded for display when the HTML or Markdown report is used.

+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.md new file mode 100644 index 000000000..6183dc003 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.md @@ -0,0 +1,8 @@ +# GeneratorTest Coding Standard + +## Standard Element, handling of HTML tags + +The use of *tags* in standard descriptions is allowed and their handling should be *safeguarded*. +Other tags, like <a href="example.com">link</a>, <b>bold</bold>, <script></script> are not allowed and will be encoded for display when the HTML or Markdown report is used. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.txt new file mode 100644 index 000000000..a464b86e2 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardEncoding.txt @@ -0,0 +1,9 @@ + +-------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: STANDARD ELEMENT, HANDLING OF HTML TAGS | +-------------------------------------------------------------------------- + +The use of *tags* in standard descriptions is allowed and their handling should be *safeguarded*. +Other tags, like link, bold, are not allowed +and will be encoded for display when the HTML or Markdown report is used. + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.html new file mode 100644 index 000000000..8cf7c3419 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.html @@ -0,0 +1,98 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Standard Element, indentation should be ignored §

+

This line has no indentation.
+This line has 4 spaces indentation.
+This line has 8 spaces indentation.
+This line has 4 spaces indentation.

+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.md new file mode 100644 index 000000000..46bea4c34 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.md @@ -0,0 +1,10 @@ +# GeneratorTest Coding Standard + +## Standard Element, indentation should be ignored + +This line has no indentation. +This line has 4 spaces indentation. +This line has 8 spaces indentation. +This line has 4 spaces indentation. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.txt new file mode 100644 index 000000000..fef00b9dc --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardIndent.txt @@ -0,0 +1,10 @@ + +---------------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: STANDARD ELEMENT, INDENTATION SHOULD BE IGNORED | +---------------------------------------------------------------------------------- + +This line has no indentation. +This line has 4 spaces indentation. +This line has 8 spaces indentation. +This line has 4 spaces indentation. + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.html new file mode 100644 index 000000000..b9f4038a1 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.html @@ -0,0 +1,97 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Standard Element, line wrapping handling §

+

This line has to be exactly 99 chars to test part of the logic.------------------------------------
+And this line has to be exactly 100 chars.----------------------------------------------------------
+And here we have a line which should start wrapping as it is longer than 100 chars. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean pellentesque iaculis enim quis hendrerit. Morbi ultrices in odio pharetra commodo.

+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.md new file mode 100644 index 000000000..c94bed46b --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.md @@ -0,0 +1,9 @@ +# GeneratorTest Coding Standard + +## Standard Element, line wrapping handling + +This line has to be exactly 99 chars to test part of the logic.------------------------------------ +And this line has to be exactly 100 chars.---------------------------------------------------------- +And here we have a line which should start wrapping as it is longer than 100 chars. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean pellentesque iaculis enim quis hendrerit. Morbi ultrices in odio pharetra commodo. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.txt new file mode 100644 index 000000000..6f09fbe33 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStandardLineWrapping.txt @@ -0,0 +1,11 @@ + +--------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: STANDARD ELEMENT, LINE WRAPPING HANDLING | +--------------------------------------------------------------------------- + +This line has to be exactly 99 chars to test part of the logic.------------------------------------ +And this line has to be exactly 100 chars.---------------------------------------------------------- +And here we have a line which should start wrapping as it is longer than 100 chars. Lorem ipsum +dolor sit amet, consectetur adipiscing elit. Aenean pellentesque iaculis enim quis hendrerit. Morbi +ultrices in odio pharetra commodo. + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.html new file mode 100644 index 000000000..9aa1d6209 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.html @@ -0,0 +1,200 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Table of Contents

+ +

Code Comparison Only, Missing Standard Block §

+ + + + + + + + + +
Valid: Lorem ipsum dolor sit amet.Invalid: Maecenas non rutrum dolor.
class Code {}class Comparison {}
+

One Standard Block, Code Comparison §

+

Documentation contains one standard block and one code comparison.

+ + + + + + + + + +
Valid: Lorem ipsum dolor sit amet.Invalid: Maecenas non rutrum dolor.
class Code {}class Comparison {}
+

One Standard Block, No Code §

+

Documentation contains one standard block and no code comparison.

+

One Standard Block, Two Code Comparisons §

+

Documentation contains one standard block and two code comparisons.

+ + + + + + + + + +
Valid: Etiam commodo magna at vestibulum blandit.Invalid: Vivamus lacinia ante velit.
class Code {}class Comparison {}
+ + + + + + + + + +
Valid: Pellentesque nisi neque.Invalid: Mauris dictum metus quis maximus pharetra.
$one = 10;$a = 10;
+

Two Standard Blocks, No Code §

+

This is standard block one.

+

This is standard block two.

+

Two Standard Blocks, One Code Comparison §

+

This is standard block one.

+ + + + + + + + + +
Valid: Vestibulum et orci condimentum.Invalid: Donec in nisl ut tortor convallis interdum.
class Code {}class Comparison {}
+

This is standard block two.

+

Two Standard Blocks, Three Code Comparisons §

+

This is standard block one.

+ + + + + + + + + +
Valid: Vestibulum et orci condimentum.Invalid: Donec in nisl ut tortor convallis interdum.
class Code {}class Comparison {}
+

This is standard block two.

+ + + + + + + + + +
Valid: Pellentesque nisi neque.Invalid: Mauris dictum metus quis maximus pharetra.
$one = 10;$a = 10;
+ + + + + + + + + +
Valid: Quisque sagittis nisi vitae.Invalid: Morbi ac libero vitae lorem.
echo $foo;print $foo;
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.md new file mode 100644 index 000000000..fcbfcefe7 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.md @@ -0,0 +1,177 @@ +# GeneratorTest Coding Standard + +## Code Comparison Only, Missing Standard Block + + + + + + + + + + +
Valid: Lorem ipsum dolor sit amet.Invalid: Maecenas non rutrum dolor.
+ + class Code {} + + + + class Comparison {} + +
+ +## One Standard Block, Code Comparison + +Documentation contains one standard block and one code comparison. + + + + + + + + + +
Valid: Lorem ipsum dolor sit amet.Invalid: Maecenas non rutrum dolor.
+ + class Code {} + + + + class Comparison {} + +
+ +## One Standard Block, No Code + +Documentation contains one standard block and no code comparison. + +## One Standard Block, Two Code Comparisons + +Documentation contains one standard block and two code comparisons. + + + + + + + + + +
Valid: Etiam commodo magna at vestibulum blandit.Invalid: Vivamus lacinia ante velit.
+ + class Code {} + + + + class Comparison {} + +
+ + + + + + + + + +
Valid: Pellentesque nisi neque.Invalid: Mauris dictum metus quis maximus pharetra.
+ + $one = 10; + + + + $a = 10; + +
+ +## Two Standard Blocks, No Code + +This is standard block one. +This is standard block two. + +## Two Standard Blocks, One Code Comparison + +This is standard block one. + + + + + + + + + +
Valid: Vestibulum et orci condimentum.Invalid: Donec in nisl ut tortor convallis interdum.
+ + class Code {} + + + + class Comparison {} + +
+This is standard block two. + +## Two Standard Blocks, Three Code Comparisons + +This is standard block one. + + + + + + + + + +
Valid: Vestibulum et orci condimentum.Invalid: Donec in nisl ut tortor convallis interdum.
+ + class Code {} + + + + class Comparison {} + +
+This is standard block two. + + + + + + + + + +
Valid: Pellentesque nisi neque.Invalid: Mauris dictum metus quis maximus pharetra.
+ + $one = 10; + + + + $a = 10; + +
+ + + + + + + + + +
Valid: Quisque sagittis nisi vitae.Invalid: Morbi ac libero vitae lorem.
+ + echo $foo; + + + + print $foo; + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.txt new file mode 100644 index 000000000..4ca1dbcad --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputStructureDocs.txt @@ -0,0 +1,106 @@ + +------------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: CODE COMPARISON ONLY, MISSING STANDARD BLOCK | +------------------------------------------------------------------------------- + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Lorem ipsum dolor sit amet. | Invalid: Maecenas non rutrum dolor. | +---------------------------------------------------------------------------------------------------- +| class Code {} | class Comparison {} | +---------------------------------------------------------------------------------------------------- + + +---------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: ONE STANDARD BLOCK, CODE COMPARISON | +---------------------------------------------------------------------- + +Documentation contains one standard block and one code comparison. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Lorem ipsum dolor sit amet. | Invalid: Maecenas non rutrum dolor. | +---------------------------------------------------------------------------------------------------- +| class Code {} | class Comparison {} | +---------------------------------------------------------------------------------------------------- + + +-------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: ONE STANDARD BLOCK, NO CODE | +-------------------------------------------------------------- + +Documentation contains one standard block and no code comparison. + + +--------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: ONE STANDARD BLOCK, TWO CODE COMPARISONS | +--------------------------------------------------------------------------- + +Documentation contains one standard block and two code comparisons. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Etiam commodo magna at vestibulum | Invalid: Vivamus lacinia ante velit. | +| blandit. | | +---------------------------------------------------------------------------------------------------- +| class Code {} | class Comparison {} | +---------------------------------------------------------------------------------------------------- + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Pellentesque nisi neque. | Invalid: Mauris dictum metus quis maximus | +| | pharetra. | +---------------------------------------------------------------------------------------------------- +| $one = 10; | $a = 10; | +---------------------------------------------------------------------------------------------------- + + +--------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: TWO STANDARD BLOCKS, NO CODE | +--------------------------------------------------------------- + +This is standard block one. + +This is standard block two. + + +--------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: TWO STANDARD BLOCKS, ONE CODE COMPARISON | +--------------------------------------------------------------------------- + +This is standard block one. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Vestibulum et orci condimentum. | Invalid: Donec in nisl ut tortor convallis | +| | interdum. | +---------------------------------------------------------------------------------------------------- +| class Code {} | class Comparison {} | +---------------------------------------------------------------------------------------------------- + +This is standard block two. + + +------------------------------------------------------------------------------ +| GENERATORTEST CODING STANDARD: TWO STANDARD BLOCKS, THREE CODE COMPARISONS | +------------------------------------------------------------------------------ + +This is standard block one. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Vestibulum et orci condimentum. | Invalid: Donec in nisl ut tortor convallis | +| | interdum. | +---------------------------------------------------------------------------------------------------- +| class Code {} | class Comparison {} | +---------------------------------------------------------------------------------------------------- + +This is standard block two. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Pellentesque nisi neque. | Invalid: Mauris dictum metus quis maximus | +| | pharetra. | +---------------------------------------------------------------------------------------------------- +| $one = 10; | $a = 10; | +---------------------------------------------------------------------------------------------------- + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Quisque sagittis nisi vitae. | Invalid: Morbi ac libero vitae lorem. | +---------------------------------------------------------------------------------------------------- +| echo $foo; | print $foo; | +---------------------------------------------------------------------------------------------------- + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.html new file mode 100644 index 000000000..82fe75004 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.html @@ -0,0 +1,95 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

One element correct, one element wrong level §

+

This is a standard block at the correct level.

+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.md new file mode 100644 index 000000000..aa9cc4727 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.md @@ -0,0 +1,7 @@ +# GeneratorTest Coding Standard + +## One element correct, one element wrong level + +This is a standard block at the correct level. + +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.txt new file mode 100644 index 000000000..4d1aaeaa1 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.txt @@ -0,0 +1,7 @@ + +------------------------------------------------------------------------------- +| GENERATORTEST CODING STANDARD: ONE ELEMENT CORRECT, ONE ELEMENT WRONG LEVEL | +------------------------------------------------------------------------------- + +This is a standard block at the correct level. + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.html b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.html new file mode 100644 index 000000000..de06568db --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.html @@ -0,0 +1,105 @@ + + + GeneratorTest Coding Standards + + + +

GeneratorTest Coding Standards

+

Superfluous code element §

+

This is a standard block.

+ + + + + + + + + +
Valid: Checking handling of blank lines.Invalid: Checking handling of blank lines.
$valid = true;$invalid = true;
+
Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION#
+ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.md b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.md new file mode 100644 index 000000000..f6cdad946 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.md @@ -0,0 +1,25 @@ +# GeneratorTest Coding Standard + +## Superfluous code element + +This is a standard block. + + + + + + + + + +
Valid: Checking handling of blank lines.Invalid: Checking handling of blank lines.
+ + $valid = true; + + + + $invalid = true; + +
+ +Documentation generated on *REDACTED* by [PHP_CodeSniffer *VERSION*](https://github.com/PHPCSStandards/PHP_CodeSniffer) diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.txt b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.txt new file mode 100644 index 000000000..1307eebfd --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.txt @@ -0,0 +1,13 @@ + +----------------------------------------------------------- +| GENERATORTEST CODING STANDARD: SUPERFLUOUS CODE ELEMENT | +----------------------------------------------------------- + +This is a standard block. + +----------------------------------------- CODE COMPARISON ------------------------------------------ +| Valid: Checking handling of blank lines. | Invalid: Checking handling of blank lines. | +---------------------------------------------------------------------------------------------------- +| $valid = true; | $invalid = true; | +---------------------------------------------------------------------------------------------------- + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/HTMLDouble.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/HTMLDouble.php new file mode 100644 index 000000000..695c0c6d2 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/HTMLDouble.php @@ -0,0 +1,70 @@ +Documentation generated on #REDACTED# by PHP_CodeSniffer #VERSION# + +'; + + // Use the correct line endings based on the OS. + return str_replace("\n", PHP_EOL, $output).PHP_EOL; + } + + /** + * Retrieve the _real_ footer of the HTML page. + * + * @return string + */ + public function getRealFooter() + { + return parent::getFormattedFooter(); + } + + /** + * [VISIBILITY WIDENING ONLY] Print the header of the HTML page. + * + * @return void + */ + public function printHeader() + { + parent::printHeader(); + } + + /** + * [VISIBILITY WIDENING ONLY] Print the table of contents for the standard. + * + * @return void + */ + public function printToc() + { + parent::printToc(); + } + + /** + * [VISIBILITY WIDENING ONLY] Print the footer of the HTML page. + * + * @return void + */ + public function printFooter() + { + parent::printFooter(); + } +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/MarkdownDouble.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/MarkdownDouble.php new file mode 100644 index 000000000..79dc6b0bf --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/MarkdownDouble.php @@ -0,0 +1,68 @@ +getTitle($doc), PHP_EOL; + } +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonBlankLinesStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonBlankLinesStandard.xml new file mode 100644 index 000000000..bcaf82bbb --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonBlankLinesStandard.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonBlockLengthStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonBlockLengthStandard.xml new file mode 100644 index 000000000..c479a7fd0 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonBlockLengthStandard.xml @@ -0,0 +1,35 @@ + + + + + + + $one = 10; + ]]> + + + $a = 10; + ]]> + + + + + echo $foo; + ]]> + + + print $foo; + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonEncodingStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonEncodingStandard.xml new file mode 100644 index 000000000..c366553f3 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonEncodingStandard.xml @@ -0,0 +1,42 @@ + + + + + + + $f; +$g = $h <= $i; +$j = $k >= $l; +$m = $n <=> $o; + ]]> + + + + +// The above PHP tag is specifically testing +// handling of that in generated HTML doc. + +// Now let's also check the handling of +// comparison operators in code samples +// in combination with "em" tags. +$a = $b < $c; +$d = $e > $f; +$g = $h <= $i; +$j = $k >= $l; +$m = $n <=> $o; + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonLineLengthStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonLineLengthStandard.xml new file mode 100644 index 000000000..b4431ea84 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeComparisonLineLengthStandard.xml @@ -0,0 +1,25 @@ + + + + + + + Countable, Serializable +{ +} + ]]> + + + foobar($param1, $param2) {} +} + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeTitleLineWrappingStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeTitleLineWrappingStandard.xml new file mode 100644 index 000000000..b773f7a88 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeTitleLineWrappingStandard.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeTitleWhitespaceStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeTitleWhitespaceStandard.xml new file mode 100644 index 000000000..282972025 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/CodeTitleWhitespaceStandard.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleCaseStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleCaseStandard.xml new file mode 100644 index 000000000..a4078e3de --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleCaseStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleLengthStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleLengthStandard.xml new file mode 100644 index 000000000..244892764 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleLengthStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitlePCREFallbackStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitlePCREFallbackStandard.xml new file mode 100644 index 000000000..1aa3849bd --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitlePCREFallbackStandard.xml @@ -0,0 +1,9 @@ + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug1Standard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug1Standard.xml new file mode 100644 index 000000000..4edae6918 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug1Standard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug2Standard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug2Standard.xml new file mode 100644 index 000000000..43956e3fc --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug2Standard.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug3Standard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug3Standard.xml new file mode 100644 index 000000000..43956e3fc --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/DocumentationTitleToAnchorSlug3Standard.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardBlankLinesStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardBlankLinesStandard.xml new file mode 100644 index 000000000..10c47bf46 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardBlankLinesStandard.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardEncodingStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardEncodingStandard.xml new file mode 100644 index 000000000..3e34c3f9f --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardEncodingStandard.xml @@ -0,0 +1,8 @@ + + + tags in standard descriptions is allowed and their handling should be safeguarded. + Other tags, like link, bold, are not allowed and will be encoded for display when the HTML or Markdown report is used. + ]]> + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardIndentStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardIndentStandard.xml new file mode 100644 index 000000000..b2ec6c5e3 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardIndentStandard.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardLineWrappingStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardLineWrappingStandard.xml new file mode 100644 index 000000000..66bbb9627 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Content/StandardLineWrappingStandard.xml @@ -0,0 +1,9 @@ + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonMismatchedCodeElmsStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonMismatchedCodeElmsStandard.xml new file mode 100644 index 000000000..d0cfff411 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonMismatchedCodeElmsStandard.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonMissingCodeElmStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonMissingCodeElmStandard.xml new file mode 100644 index 000000000..999901ebb --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonMissingCodeElmStandard.xml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonNoCodeStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonNoCodeStandard.xml new file mode 100644 index 000000000..54b50ff8d --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonNoCodeStandard.xml @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonNoContentStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonNoContentStandard.xml new file mode 100644 index 000000000..0dfb12fa0 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonNoContentStandard.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonOneEmptyCodeElmStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonOneEmptyCodeElmStandard.xml new file mode 100644 index 000000000..b40674413 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonOneEmptyCodeElmStandard.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonTwoEmptyCodeElmsStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonTwoEmptyCodeElmsStandard.xml new file mode 100644 index 000000000..e6cb07145 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeComparisonTwoEmptyCodeElmsStandard.xml @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeTitleEmptyStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeTitleEmptyStandard.xml new file mode 100644 index 000000000..034bdf2fd --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeTitleEmptyStandard.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeTitleMissingStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeTitleMissingStandard.xml new file mode 100644 index 000000000..89599dd2b --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/CodeTitleMissingStandard.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/DocumentationTitleEmptyStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/DocumentationTitleEmptyStandard.xml new file mode 100644 index 000000000..c3ab071d1 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/DocumentationTitleEmptyStandard.xml @@ -0,0 +1,19 @@ + + + + + + + class Code {} + ]]> + + + class Comparison {} + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/DocumentationTitleMissingStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/DocumentationTitleMissingStandard.xml new file mode 100644 index 000000000..974071d9f --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/DocumentationTitleMissingStandard.xml @@ -0,0 +1,19 @@ + + + + + + + class Code {} + ]]> + + + class Comparison {} + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/StandardNoContentStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/StandardNoContentStandard.xml new file mode 100644 index 000000000..e6934706a --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Invalid/StandardNoContentStandard.xml @@ -0,0 +1,15 @@ + + + + + class Code {} + ]]> + + + class Comparison {} + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/NoContentStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/NoContentStandard.xml new file mode 100644 index 000000000..83afee8e8 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/NoContentStandard.xml @@ -0,0 +1,2 @@ + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/NoDocumentationElementStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/NoDocumentationElementStandard.xml new file mode 100644 index 000000000..ca8290f1b --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/NoDocumentationElementStandard.xml @@ -0,0 +1,2 @@ + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneCodeComparisonNoStandardStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneCodeComparisonNoStandardStandard.xml new file mode 100644 index 000000000..c2af9098a --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneCodeComparisonNoStandardStandard.xml @@ -0,0 +1,14 @@ + + + + class Code {} + ]]> + + + class Comparison {} + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockCodeComparisonStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockCodeComparisonStandard.xml new file mode 100644 index 000000000..c3ce35cd7 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockCodeComparisonStandard.xml @@ -0,0 +1,19 @@ + + + + + + + class Code {} + ]]> + + + class Comparison {} + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockNoCodeStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockNoCodeStandard.xml new file mode 100644 index 000000000..fc014949e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockNoCodeStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockTwoCodeComparisonsStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockTwoCodeComparisonsStandard.xml new file mode 100644 index 000000000..19559e672 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/OneStandardBlockTwoCodeComparisonsStandard.xml @@ -0,0 +1,31 @@ + + + + + + + class Code {} + ]]> + + + class Comparison {} + ]]> + + + + + $one = 10; + ]]> + + + $a = 10; + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksNoCodeStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksNoCodeStandard.xml new file mode 100644 index 000000000..f5f621ecd --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksNoCodeStandard.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksOneCodeComparisonStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksOneCodeComparisonStandard.xml new file mode 100644 index 000000000..a5b3a3216 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksOneCodeComparisonStandard.xml @@ -0,0 +1,24 @@ + + + + + + + Code {} + ]]> + + + Comparison {} + ]]> + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksThreeCodeComparisonsStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksThreeCodeComparisonsStandard.xml new file mode 100644 index 000000000..540ac7eaf --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Structure/TwoStandardBlocksThreeCodeComparisonsStandard.xml @@ -0,0 +1,48 @@ + + + + + + + class Code {} + ]]> + + + class Comparison {} + ]]> + + + + + + + + $one = 10; + ]]> + + + $a = 10; + ]]> + + + + + echo $foo; + ]]> + + + print $foo; + ]]> + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/ElementAtWrongLevelStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/ElementAtWrongLevelStandard.xml new file mode 100644 index 000000000..68519dd2b --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/ElementAtWrongLevelStandard.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/OneElmAtWrongLevelStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/OneElmAtWrongLevelStandard.xml new file mode 100644 index 000000000..6c1dd164a --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/OneElmAtWrongLevelStandard.xml @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/SuperfluousCodeElementStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/SuperfluousCodeElementStandard.xml new file mode 100644 index 000000000..333786a33 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/SuperfluousCodeElementStandard.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/UnknownElementStandard.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/UnknownElementStandard.xml new file mode 100644 index 000000000..c9ec3227f --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Docs/Unsupported/UnknownElementStandard.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/CodeComparisonBlankLinesSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/CodeComparisonBlankLinesSniff.php new file mode 100644 index 000000000..1e56bf9cf --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/Fixtures/StandardWithDocs/Sniffs/Content/CodeComparisonBlankLinesSniff.php @@ -0,0 +1,12 @@ + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/GeneratorTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/GeneratorTest.php new file mode 100644 index 000000000..8fb0ee251 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/GeneratorTest.php @@ -0,0 +1,227 @@ + $expected The expected list of found docs. + * + * @dataProvider dataConstructor + * + * @return void + */ + public function testConstructor($standard, array $expected) + { + // Set up the ruleset. + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $generator = new MockGenerator($ruleset); + $this->assertSame($expected, $generator->docFiles); + + }//end testConstructor() + + + /** + * Data provider. + * + * @return array>> + */ + public static function dataConstructor() + { + $pathToDocsInFixture = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'; + $pathToDocsInFixture .= DIRECTORY_SEPARATOR.'StandardWithDocs'; + $pathToDocsInFixture .= DIRECTORY_SEPARATOR.'Docs'.DIRECTORY_SEPARATOR; + + return [ + 'Standard without docs' => [ + 'standard' => __DIR__.'/NoDocsTest.xml', + 'expected' => [], + ], + 'Standard with an invalid doc file' => [ + 'standard' => __DIR__.'/NoValidDocsTest.xml', + 'expected' => [ + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'NoDocumentationElementStandard.xml', + ], + ], + 'Standard with one doc file' => [ + 'standard' => __DIR__.'/OneDocTest.xml', + 'expected' => [ + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'OneStandardBlockNoCodeStandard.xml', + ], + ], + 'Standard with multiple doc files' => [ + 'standard' => __DIR__.'/StructureDocsTest.xml', + 'expected' => [ + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'NoContentStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'OneCodeComparisonNoStandardStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'OneStandardBlockCodeComparisonStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'OneStandardBlockNoCodeStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'OneStandardBlockTwoCodeComparisonsStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'TwoStandardBlocksNoCodeStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'TwoStandardBlocksOneCodeComparisonStandard.xml', + $pathToDocsInFixture.'Structure'.DIRECTORY_SEPARATOR.'TwoStandardBlocksThreeCodeComparisonsStandard.xml', + ], + ], + ]; + + }//end dataConstructor() + + + /** + * Verify that an XML doc which isn't valid documentation yields an Exception to warn devs. + * + * This should not be hidden via defensive coding! + * + * @return void + */ + public function testGeneratingInvalidDocsResultsInException() + { + // Set up the ruleset. + $standard = __DIR__.'/NoValidDocsTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + if (PHP_VERSION_ID >= 80000) { + $exception = 'TypeError'; + $message = 'processSniff(): Argument #1 ($doc) must be of type DOMNode, null given'; + } else if (PHP_VERSION_ID >= 70000) { + $exception = 'TypeError'; + $message = 'processSniff() must be an instance of DOMNode, null given'; + } else { + $exception = 'PHPUnit_Framework_Error'; + $message = 'processSniff() must be an instance of DOMNode, null given'; + } + + if (method_exists($this, 'expectExceptionMessage') === true) { + // PHPUnit 5.2.0+. + $this->expectException($exception); + $this->expectExceptionMessage($message); + } else { + // Ancient PHPUnit. + $this->setExpectedException($exception, $message); + } + + $generator = new MockGenerator($ruleset); + $generator->generate(); + + }//end testGeneratingInvalidDocsResultsInException() + + + /** + * Verify the wiring for the generate() function. + * + * @param string $standard The standard to use for the test. + * @param string $expected The expected function output. + * + * @dataProvider dataGeneratingDocs + * + * @return void + */ + public function testGeneratingDocs($standard, $expected) + { + // Set up the ruleset. + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $this->expectOutputString($expected); + + $generator = new MockGenerator($ruleset); + $generator->generate(); + + }//end testGeneratingDocs() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataGeneratingDocs() + { + $multidocExpected = []; + $multidocExpected[] = 'No Content'; + $multidocExpected[] = 'Code Comparison Only, Missing Standard Block'; + $multidocExpected[] = 'One Standard Block, Code Comparison'; + $multidocExpected[] = 'One Standard Block, No Code'; + $multidocExpected[] = 'One Standard Block, Two Code Comparisons'; + $multidocExpected[] = 'Two Standard Blocks, No Code'; + $multidocExpected[] = 'Two Standard Blocks, One Code Comparison'; + $multidocExpected[] = 'Two Standard Blocks, Three Code Comparisons'; + $multidocExpected = implode(PHP_EOL, $multidocExpected).PHP_EOL; + + return [ + 'Standard without docs' => [ + 'standard' => __DIR__.'/NoDocsTest.xml', + 'expected' => '', + ], + 'Standard with one doc file' => [ + 'standard' => __DIR__.'/OneDocTest.xml', + 'expected' => 'One Standard Block, No Code'.PHP_EOL, + ], + 'Standard with multiple doc files' => [ + 'standard' => __DIR__.'/StructureDocsTest.xml', + 'expected' => $multidocExpected, + ], + ]; + + }//end dataGeneratingDocs() + + + /** + * Verify that if the `` title is missing, it will fallback to the file name + * and split the CamelCaps name correctly. + * + * @return void + */ + public function testGetTitleFallbackToFilename() + { + // Set up the ruleset. + $standard = __DIR__.'/AllValidDocsTest.xml'; + $sniffs = 'StandardWithDocs.Content.DocumentationTitlePCREFallback'; + $config = new ConfigDouble(["--standard=$standard", "--sniffs=$sniffs"]); + $ruleset = new Ruleset($config); + + // In tests, the `--sniffs` setting doesn't work out of the box. + $sniffParts = explode('.', $sniffs); + $sniffFile = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.$sniffParts[0].DIRECTORY_SEPARATOR; + $sniffFile .= 'Sniffs'.DIRECTORY_SEPARATOR.$sniffParts[1].DIRECTORY_SEPARATOR.$sniffParts[2].'Sniff.php'; + + $sniffParts = array_map('strtolower', $sniffParts); + $sniffName = $sniffParts[0].'\sniffs\\'.$sniffParts[1].'\\'.$sniffParts[2].'sniff'; + $restrictions = [$sniffName => true]; + $ruleset->registerSniffs([$sniffFile], $restrictions, []); + + // Make the test OS independent. + $this->expectOutputString('Documentation Title PCRE Fallback'.PHP_EOL); + + $generator = new MockGenerator($ruleset); + $generator->generate(); + + }//end testGetTitleFallbackToFilename() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/HTMLTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/HTMLTest.php new file mode 100644 index 000000000..91cd7d1e5 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/HTMLTest.php @@ -0,0 +1,426 @@ +assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new HTMLDouble($ruleset); + $generator->generate(); + + }//end testDocs() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataDocs() + { + return [ + 'Standard without docs' => [ + 'standard' => __DIR__.'/NoDocsTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Standard with one doc file' => [ + 'standard' => __DIR__.'/OneDocTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputOneDoc.html', + ], + 'Standard with multiple doc files' => [ + 'standard' => __DIR__.'/StructureDocsTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStructureDocs.html', + ], + ]; + + }//end dataDocs() + + + /** + * Test the generated docs for the handling of specific parts of the documentation. + * + * @param string $sniffs The specific fixture sniffs to verify the docs for. + * @param string $pathToExpected Path to a file containing the expected function output. + * + * @dataProvider dataDocSpecifics + * + * @return void + */ + public function testDocSpecifics($sniffs, $pathToExpected) + { + // Set up the ruleset. + $standard = __DIR__.'/AllValidDocsTest.xml'; + $config = new ConfigDouble(["--standard=$standard", "--sniffs=$sniffs"]); + $ruleset = new Ruleset($config); + + // In tests, the `--sniffs` setting doesn't work out of the box. + $sniffParts = explode('.', $sniffs); + $sniffFile = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.$sniffParts[0].DIRECTORY_SEPARATOR; + $sniffFile .= 'Sniffs'.DIRECTORY_SEPARATOR.$sniffParts[1].DIRECTORY_SEPARATOR.$sniffParts[2].'Sniff.php'; + + $sniffParts = array_map('strtolower', $sniffParts); + $sniffName = $sniffParts[0].'\sniffs\\'.$sniffParts[1].'\\'.$sniffParts[2].'sniff'; + $restrictions = [$sniffName => true]; + $ruleset->registerSniffs([$sniffFile], $restrictions, []); + + $expected = file_get_contents($pathToExpected); + $this->assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new HTMLDouble($ruleset); + $generator->generate(); + + }//end testDocSpecifics() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataDocSpecifics() + { + return [ + 'Documentation title: case' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleCase', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleCase.html', + ], + 'Documentation title: length' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleLength.html', + ], + 'Documentation title: fallback to file name' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitlePCREFallback', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitlePCREFallback.html', + ], + 'Standard Element: blank line handling' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardBlankLines', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardBlankLines.html', + ], + 'Standard Element: encoding of special characters' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardEncoding', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardEncoding.html', + ], + 'Standard Element: indent handling' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardIndent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardIndent.html', + ], + 'Standard Element: line wrapping' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardLineWrapping', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardLineWrapping.html', + ], + 'Code Title: line wrapping' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeTitleLineWrapping', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleLineWrapping.html', + ], + 'Code Title: whitespace handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeTitleWhitespace', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleWhitespace.html', + ], + 'Code Comparison: blank line handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonBlankLines', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonBlankLines.html', + ], + 'Code Comparison: different block lengths' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonBlockLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonBlockLength.html', + ], + 'Code Comparison: encoding of special characters' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonEncoding', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonEncoding.html', + ], + 'Code Comparison: line length handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonLineLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonLineLength.html', + ], + 'Unsupported: element at the wrong level' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.ElementAtWrongLevel', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Unsupported: one correct elm, one at wrong level' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.OneElmAtWrongLevel', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.html', + ], + 'Unsupported: superfluous code element' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.SuperfluousCodeElement', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.html', + ], + 'Unsupported: unknown element' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.UnknownElement', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Invalid: code comparison mismatched code elms' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonMismatchedCodeElms', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.html', + ], + 'Invalid: code comparison only has one code elm' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonMissingCodeElm', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.html', + ], + 'Invalid: code elements have no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonNoCode', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.html', + ], + 'Invalid: code comparison element has no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonNoContent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.html', + ], + 'Invalid: code comparison two code elms, one empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonOneEmptyCodeElm', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.html', + ], + 'Invalid: code comparison two empty code elms' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonTwoEmptyCodeElms', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.html', + ], + 'Invalid: code title attributes are empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeTitleEmpty', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeTitleEmpty.html', + ], + 'Invalid: code title attributes missing' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeTitleMissing', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeTitleMissing.html', + ], + 'Invalid: documentation title attribute is empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.DocumentationTitleEmpty', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.html', + ], + 'Invalid: documentation title attribute missing' => [ + 'sniffs' => 'StandardWithDocs.Invalid.DocumentationTitleMissing', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.html', + ], + 'Invalid: standard element has no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.StandardNoContent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidStandardNoContent.html', + ], + ]; + + }//end dataDocSpecifics() + + + /** + * Test anchor links in the generated docs are slugified and unique. + * + * @return void + */ + public function testAnchorLinks() + { + // Set up the ruleset. + $standard = __DIR__.'/AnchorLinksTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $pathToExpected = __DIR__.'/Expectations/ExpectedOutputDocumentationTitleToAnchorSlug.html'; + $expected = file_get_contents($pathToExpected); + $this->assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new HTMLDouble($ruleset); + $generator->generate(); + + }//end testAnchorLinks() + + + /** + * Test the generated footer. + * + * @return void + */ + public function testFooter() + { + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $regex = '`^
'; + $regex .= 'Documentation generated on [A-Z][a-z]{2}, [0-9]{2} [A-Z][a-z]{2} 20[0-9]{2} [0-2][0-9](?::[0-5][0-9]){2} [+-][0-9]{4}'; + $regex .= ' by PHP_CodeSniffer [3-9]\.[0-9]+.[0-9]+'; + $regex .= '
\R \R\R$`'; + + $generator = new HTMLDouble($ruleset); + $footer = $generator->getRealFooter(); + + if (method_exists($this, 'assertMatchesRegularExpression') === true) { + $this->assertMatchesRegularExpression($regex, $footer); + } else { + // PHPUnit < 9.1.0. + $this->assertRegExp($regex, $footer); + } + + }//end testFooter() + + + /** + * Safeguard that the footer logic doesn't permanently change the error level. + * + * @runInSeparateProcess + * @preserveGlobalState disabled + * + * @return void + */ + public function testFooterResetsErrorReportingToOriginalSetting() + { + $expected = error_reporting(); + + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $generator = new HTMLDouble($ruleset); + $generator->getRealFooter(); + + $this->assertSame($expected, error_reporting()); + + }//end testFooterResetsErrorReportingToOriginalSetting() + + + /** + * Safeguard that users won't see a PHP warning about the timezone not being set when calling date(). + * + * The warning we don't want to see is: + * "date(): It is not safe to rely on the system's timezone settings. You are *required* to use + * the date.timezone setting or the date_default_timezone_set() function. In case you used any of + * those methods and you are still getting this warning, you most likely misspelled the timezone + * identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select + * your timezone." + * + * JRF: Based on my tests, the warning only occurs on PHP < 7.0, but never a bad thing to safeguard this + * on a wider range of PHP versions. + * + * Note: as of PHP 8.2, PHP no longer accepts an empty string as timezone and will use `UTC` instead, + * so the warning on calling date() in the code itself would not display anyway. + * + * @requires PHP < 8.2 + * + * @doesNotPerformAssertions + * + * @return void + */ + public function testFooterDoesntThrowWarningOnMissingTimezone() + { + $originalIni = @ini_set('date.timezone', ''); + + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $generator = new HTMLDouble($ruleset); + $generator->getRealFooter(); + + // Reset the timezone to its original state. + ini_set('date.timezone', $originalIni); + + }//end testFooterDoesntThrowWarningOnMissingTimezone() + + + /** + * Perfunctory test to verify that extenders which call deprecated methods will see a deprecation notice. + * + * Note: not all deprecated methods are tested as some need arguments. + * + * @param string $methodName Name of the deprecated method to test. + * + * @dataProvider dataCallingDeprecatedMethodThrowsDeprecationNotice + * + * @return void + */ + public function testCallingDeprecatedMethodThrowsDeprecationNotice($methodName) + { + $exceptionClass = 'PHPUnit\Framework\Error\Deprecated'; + if (class_exists($exceptionClass) === false) { + $exceptionClass = 'PHPUnit_Framework_Error_Deprecated'; + } + + $regex = '`^The PHP_CodeSniffer\\\\Generators\\\\HTML::%s\(\) method is deprecated\. Use "echo [^\s]+::%s\(\)" instead\.$`'; + $regex = sprintf($regex, preg_quote($methodName, '`'), str_replace('print', 'getFormatted', $methodName)); + + if (method_exists($this, 'expectExceptionMessageMatches') === true) { + $this->expectException($exceptionClass); + $this->expectExceptionMessageMatches($regex); + } else if (method_exists($this, 'expectExceptionMessageRegExp') === true) { + // PHPUnit < 8.4.0. + $this->expectException($exceptionClass); + $this->expectExceptionMessageRegExp($regex); + } else { + // PHPUnit < 5.2.0. + $this->setExpectedExceptionRegExp($exceptionClass, $regex); + } + + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $generator = new HTMLDouble($ruleset); + $generator->$methodName(); + + }//end testCallingDeprecatedMethodThrowsDeprecationNotice() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataCallingDeprecatedMethodThrowsDeprecationNotice() + { + return [ + 'printHeader()' => ['printHeader'], + 'printToc()' => ['printToc'], + 'printFooter()' => ['printFooter'], + ]; + + }//end dataCallingDeprecatedMethodThrowsDeprecationNotice() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/MarkdownTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/MarkdownTest.php new file mode 100644 index 000000000..f9fd47796 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/MarkdownTest.php @@ -0,0 +1,397 @@ +assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new MarkdownDouble($ruleset); + $generator->generate(); + + }//end testDocs() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataDocs() + { + return [ + 'Standard without docs' => [ + 'standard' => __DIR__.'/NoDocsTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Standard with one doc file' => [ + 'standard' => __DIR__.'/OneDocTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputOneDoc.md', + ], + 'Standard with multiple doc files' => [ + 'standard' => __DIR__.'/StructureDocsTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStructureDocs.md', + ], + ]; + + }//end dataDocs() + + + /** + * Test the generated docs for the handling of specific parts of the documentation. + * + * @param string $sniffs The specific fixture sniffs to verify the docs for. + * @param string $pathToExpected Path to a file containing the expected function output. + * + * @dataProvider dataDocSpecifics + * + * @return void + */ + public function testDocSpecifics($sniffs, $pathToExpected) + { + // Set up the ruleset. + $standard = __DIR__.'/AllValidDocsTest.xml'; + $config = new ConfigDouble(["--standard=$standard", "--sniffs=$sniffs"]); + $ruleset = new Ruleset($config); + + // In tests, the `--sniffs` setting doesn't work out of the box. + $sniffParts = explode('.', $sniffs); + $sniffFile = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.$sniffParts[0].DIRECTORY_SEPARATOR; + $sniffFile .= 'Sniffs'.DIRECTORY_SEPARATOR.$sniffParts[1].DIRECTORY_SEPARATOR.$sniffParts[2].'Sniff.php'; + + $sniffParts = array_map('strtolower', $sniffParts); + $sniffName = $sniffParts[0].'\sniffs\\'.$sniffParts[1].'\\'.$sniffParts[2].'sniff'; + $restrictions = [$sniffName => true]; + $ruleset->registerSniffs([$sniffFile], $restrictions, []); + + $expected = file_get_contents($pathToExpected); + $this->assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new MarkdownDouble($ruleset); + $generator->generate(); + + }//end testDocSpecifics() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataDocSpecifics() + { + return [ + 'Documentation title: case' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleCase', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleCase.md', + ], + 'Documentation title: length' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleLength.md', + ], + 'Documentation title: fallback to file name' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitlePCREFallback', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitlePCREFallback.md', + ], + 'Standard Element: blank line handling' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardBlankLines', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardBlankLines.md', + ], + 'Standard Element: encoding of special characters' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardEncoding', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardEncoding.md', + ], + 'Standard Element: indent handling' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardIndent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardIndent.md', + ], + 'Standard Element: line wrapping' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardLineWrapping', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardLineWrapping.md', + ], + 'Code Title: line wrapping' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeTitleLineWrapping', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleLineWrapping.md', + ], + 'Code Title: whitespace handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeTitleWhitespace', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleWhitespace.md', + ], + 'Code Comparison: blank line handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonBlankLines', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonBlankLines.md', + ], + 'Code Comparison: different block lengths' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonBlockLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonBlockLength.md', + ], + 'Code Comparison: encoding of special characters' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonEncoding', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonEncoding.md', + ], + 'Code Comparison: line length handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonLineLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonLineLength.md', + ], + 'Unsupported: element at the wrong level' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.ElementAtWrongLevel', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Unsupported: one correct elm, one at wrong level' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.OneElmAtWrongLevel', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.md', + ], + 'Unsupported: superfluous code element' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.SuperfluousCodeElement', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.md', + ], + 'Unsupported: unknown element' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.UnknownElement', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Invalid: code comparison mismatched code elms' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonMismatchedCodeElms', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.md', + ], + 'Invalid: code comparison only has one code elm' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonMissingCodeElm', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.md', + ], + 'Invalid: code elements have no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonNoCode', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.md', + ], + 'Invalid: code comparison element has no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonNoContent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.md', + ], + 'Invalid: code comparison two code elms, one empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonOneEmptyCodeElm', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.md', + ], + 'Invalid: code comparison two empty code elms' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonTwoEmptyCodeElms', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.md', + ], + 'Invalid: code title attributes are empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeTitleEmpty', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeTitleEmpty.md', + ], + 'Invalid: code title attributes missing' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeTitleMissing', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeTitleMissing.md', + ], + 'Invalid: documentation title attribute is empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.DocumentationTitleEmpty', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.md', + ], + 'Invalid: documentation title attribute missing' => [ + 'sniffs' => 'StandardWithDocs.Invalid.DocumentationTitleMissing', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.md', + ], + 'Invalid: standard element has no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.StandardNoContent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidStandardNoContent.md', + ], + ]; + + }//end dataDocSpecifics() + + + /** + * Test the generated footer. + * + * @return void + */ + public function testFooter() + { + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $regex = '`^\RDocumentation generated on [A-Z][a-z]{2}, [0-9]{2} [A-Z][a-z]{2} 20[0-9]{2} [0-2][0-9](?::[0-5][0-9]){2} [+-][0-9]{4}'; + $regex .= ' by \[PHP_CodeSniffer [3-9]\.[0-9]+.[0-9]+\]\(https://github\.com/PHPCSStandards/PHP_CodeSniffer\)\R$`'; + + $generator = new MarkdownDouble($ruleset); + $footer = $generator->getRealFooter(); + + if (method_exists($this, 'assertMatchesRegularExpression') === true) { + $this->assertMatchesRegularExpression($regex, $footer); + } else { + // PHPUnit < 9.1.0. + $this->assertRegExp($regex, $footer); + } + + }//end testFooter() + + + /** + * Safeguard that the footer logic doesn't permanently change the error level. + * + * @runInSeparateProcess + * @preserveGlobalState disabled + * + * @return void + */ + public function testFooterResetsErrorReportingToOriginalSetting() + { + $expected = error_reporting(); + + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $generator = new MarkdownDouble($ruleset); + $generator->getRealFooter(); + + $this->assertSame($expected, error_reporting()); + + }//end testFooterResetsErrorReportingToOriginalSetting() + + + /** + * Safeguard that users won't see a PHP warning about the timezone not being set when calling date(). + * + * The warning we don't want to see is: + * "date(): It is not safe to rely on the system's timezone settings. You are *required* to use + * the date.timezone setting or the date_default_timezone_set() function. In case you used any of + * those methods and you are still getting this warning, you most likely misspelled the timezone + * identifier. We selected the timezone 'UTC' for now, but please set date.timezone to select + * your timezone." + * + * JRF: Based on my tests, the warning only occurs on PHP < 7.0, but never a bad thing to safeguard this + * on a wider range of PHP versions. + * + * Note: as of PHP 8.2, PHP no longer accepts an empty string as timezone and will use `UTC` instead, + * so the warning on calling date() in the code itself would not display anyway. + * + * @requires PHP < 8.2 + * + * @doesNotPerformAssertions + * + * @return void + */ + public function testFooterDoesntThrowWarningOnMissingTimezone() + { + $originalIni = @ini_set('date.timezone', ''); + + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $generator = new MarkdownDouble($ruleset); + $generator->getRealFooter(); + + // Reset the timezone to its original state. + ini_set('date.timezone', $originalIni); + + }//end testFooterDoesntThrowWarningOnMissingTimezone() + + + /** + * Perfunctory test to verify that extenders which call deprecated methods will see a deprecation notice. + * + * Note: not all deprecated methods are tested as some need arguments. + * + * @param string $methodName Name of the deprecated method to test. + * + * @dataProvider dataCallingDeprecatedMethodThrowsDeprecationNotice + * + * @return void + */ + public function testCallingDeprecatedMethodThrowsDeprecationNotice($methodName) + { + $exceptionClass = 'PHPUnit\Framework\Error\Deprecated'; + if (class_exists($exceptionClass) === false) { + $exceptionClass = 'PHPUnit_Framework_Error_Deprecated'; + } + + $regex = '`^The PHP_CodeSniffer\\\\Generators\\\\Markdown::%s\(\) method is deprecated\. Use "echo [^\s]+::%s\(\)" instead\.$`'; + $regex = sprintf($regex, preg_quote($methodName, '`'), str_replace('print', 'getFormatted', $methodName)); + + if (method_exists($this, 'expectExceptionMessageMatches') === true) { + $this->expectException($exceptionClass); + $this->expectExceptionMessageMatches($regex); + } else if (method_exists($this, 'expectExceptionMessageRegExp') === true) { + // PHPUnit < 8.4.0. + $this->expectException($exceptionClass); + $this->expectExceptionMessageRegExp($regex); + } else { + // PHPUnit < 5.2.0. + $this->setExpectedExceptionRegExp($exceptionClass, $regex); + } + + // Set up the ruleset. + $standard = __DIR__.'/OneDocTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $generator = new MarkdownDouble($ruleset); + $generator->$methodName(); + + }//end testCallingDeprecatedMethodThrowsDeprecationNotice() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataCallingDeprecatedMethodThrowsDeprecationNotice() + { + return [ + 'printHeader()' => ['printHeader'], + 'printFooter()' => ['printFooter'], + ]; + + }//end dataCallingDeprecatedMethodThrowsDeprecationNotice() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/NoDocsTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/NoDocsTest.xml new file mode 100644 index 000000000..efb29990a --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/NoDocsTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/NoValidDocsTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/NoValidDocsTest.xml new file mode 100644 index 000000000..9f5c9c493 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/NoValidDocsTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/OneDocTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/OneDocTest.xml new file mode 100644 index 000000000..50e64a884 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/OneDocTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/StructureDocsTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/StructureDocsTest.xml new file mode 100644 index 000000000..6199e2873 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/StructureDocsTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/TextTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/TextTest.php new file mode 100644 index 000000000..90bb7bf89 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Generators/TextTest.php @@ -0,0 +1,245 @@ +assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new Text($ruleset); + $generator->generate(); + + }//end testDocs() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataDocs() + { + return [ + 'Standard without docs' => [ + 'standard' => __DIR__.'/NoDocsTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Standard with one doc file' => [ + 'standard' => __DIR__.'/OneDocTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputOneDoc.txt', + ], + 'Standard with multiple doc files' => [ + 'standard' => __DIR__.'/StructureDocsTest.xml', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStructureDocs.txt', + ], + ]; + + }//end dataDocs() + + + /** + * Test the generated docs for the handling of specific parts of the documentation. + * + * @param string $sniffs The specific fixture sniffs to verify the docs for. + * @param string $pathToExpected Path to a file containing the expected function output. + * + * @dataProvider dataDocSpecifics + * + * @return void + */ + public function testDocSpecifics($sniffs, $pathToExpected) + { + // Set up the ruleset. + $standard = __DIR__.'/AllValidDocsTest.xml'; + $config = new ConfigDouble(["--standard=$standard", "--sniffs=$sniffs"]); + $ruleset = new Ruleset($config); + + // In tests, the `--sniffs` setting doesn't work out of the box. + $sniffParts = explode('.', $sniffs); + $sniffFile = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.$sniffParts[0].DIRECTORY_SEPARATOR; + $sniffFile .= 'Sniffs'.DIRECTORY_SEPARATOR.$sniffParts[1].DIRECTORY_SEPARATOR.$sniffParts[2].'Sniff.php'; + + $sniffParts = array_map('strtolower', $sniffParts); + $sniffName = $sniffParts[0].'\sniffs\\'.$sniffParts[1].'\\'.$sniffParts[2].'sniff'; + $restrictions = [$sniffName => true]; + $ruleset->registerSniffs([$sniffFile], $restrictions, []); + + $expected = file_get_contents($pathToExpected); + $this->assertNotFalse($expected, 'Output expectation file could not be found'); + + // Make the test OS independent. + $expected = str_replace("\n", PHP_EOL, $expected); + $this->expectOutputString($expected); + + $generator = new Text($ruleset); + $generator->generate(); + + }//end testDocSpecifics() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataDocSpecifics() + { + return [ + 'Documentation title: case' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleCase', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleCase.txt', + ], + 'Documentation title: length' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitleLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitleLength.txt', + ], + 'Documentation title: fallback to file name' => [ + 'sniffs' => 'StandardWithDocs.Content.DocumentationTitlePCREFallback', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputDocumentationTitlePCREFallback.txt', + ], + 'Standard Element: blank line handling' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardBlankLines', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardBlankLines.txt', + ], + 'Standard Element: encoding of special characters' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardEncoding', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardEncoding.txt', + ], + 'Standard Element: indent handling' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardIndent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardIndent.txt', + ], + 'Standard Element: line wrapping' => [ + 'sniffs' => 'StandardWithDocs.Content.StandardLineWrapping', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputStandardLineWrapping.txt', + ], + 'Code Title: line wrapping' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeTitleLineWrapping', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleLineWrapping.txt', + ], + 'Code Title: whitespace handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeTitleWhitespace', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeTitleWhitespace.txt', + ], + 'Code Comparison: blank line handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonBlankLines', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonBlankLines.txt', + ], + 'Code Comparison: different block lengths' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonBlockLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonBlockLength.txt', + ], + 'Code Comparison: encoding of special characters' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonEncoding', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonEncoding.txt', + ], + 'Code Comparison: line length handling' => [ + 'sniffs' => 'StandardWithDocs.Content.CodeComparisonLineLength', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputCodeComparisonLineLength.txt', + ], + 'Unsupported: element at the wrong level' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.ElementAtWrongLevel', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Unsupported: one correct elm, one at wrong level' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.OneElmAtWrongLevel', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedOneElmAtWrongLevel.txt', + ], + 'Unsupported: superfluous code element' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.SuperfluousCodeElement', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputUnsupportedSuperfluousCodeElement.txt', + ], + 'Unsupported: unknown element' => [ + 'sniffs' => 'StandardWithDocs.Unsupported.UnknownElement', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputEmpty.txt', + ], + 'Invalid: code comparison mismatched code elms' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonMismatchedCodeElms', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonMismatchedCodeElms.txt', + ], + 'Invalid: code comparison only has one code elm' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonMissingCodeElm', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonMissingCodeElm.txt', + ], + 'Invalid: code elements have no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonNoCode', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonNoCode.txt', + ], + 'Invalid: code comparison element has no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonNoContent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonNoContent.txt', + ], + 'Invalid: code comparison two code elms, one empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonOneEmptyCodeElm', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonOneEmptyCodeElm.txt', + ], + 'Invalid: code comparison two empty code elms' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeComparisonTwoEmptyCodeElms', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeComparisonTwoEmptyCodeElms.txt', + ], + 'Invalid: code title attributes are empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeTitleEmpty', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeTitleEmpty.txt', + ], + 'Invalid: code title attributes missing' => [ + 'sniffs' => 'StandardWithDocs.Invalid.CodeTitleMissing', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidCodeTitleMissing.txt', + ], + 'Invalid: documentation title attribute is empty' => [ + 'sniffs' => 'StandardWithDocs.Invalid.DocumentationTitleEmpty', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidDocumentationTitleEmpty.txt', + ], + 'Invalid: documentation title attribute missing' => [ + 'sniffs' => 'StandardWithDocs.Invalid.DocumentationTitleMissing', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidDocumentationTitleMissing.txt', + ], + 'Invalid: standard element has no content' => [ + 'sniffs' => 'StandardWithDocs.Invalid.StandardNoContent', + 'pathToExpected' => __DIR__.'/Expectations/ExpectedOutputInvalidStandardNoContent.txt', + ], + ]; + + }//end dataDocSpecifics() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/AbstractRulesetTestCase.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/AbstractRulesetTestCase.php new file mode 100644 index 000000000..41c639443 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/AbstractRulesetTestCase.php @@ -0,0 +1,115 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHPUnit\Framework\TestCase; + +abstract class AbstractRulesetTestCase extends TestCase +{ + + /** + * The fully qualified name of the PHPCS runtime exception class. + * + * @var string + */ + const RUNTIME_EXCEPTION = 'PHP_CodeSniffer\Exceptions\RuntimeException'; + + + /** + * Asserts that an object has a specified property in a PHPUnit cross-version compatible manner. + * + * @param string $propertyName The name of the property. + * @param object $object The object on which to check whether the property exists. + * @param string $message Optional failure message to display. + * + * @return void + */ + protected function assertXObjectHasProperty($propertyName, $object, $message='') + { + if (method_exists($this, 'assertObjectHasProperty') === true) { + $this->assertObjectHasProperty($propertyName, $object, $message); + } else { + // PHPUnit < 9.6.11. + $this->assertObjectHasAttribute($propertyName, $object, $message); + } + + }//end assertXObjectHasProperty() + + + /** + * Asserts that an object does not have a specified property + * in a PHPUnit cross-version compatible manner. + * + * @param string $propertyName The name of the property. + * @param object $object The object on which to check whether the property exists. + * @param string $message Optional failure message to display. + * + * @return void + */ + protected function assertXObjectNotHasProperty($propertyName, $object, $message='') + { + if (method_exists($this, 'assertObjectNotHasProperty') === true) { + $this->assertObjectNotHasProperty($propertyName, $object, $message); + } else { + // PHPUnit < 9.6.11. + $this->assertObjectNotHasAttribute($propertyName, $object, $message); + } + + }//end assertXObjectNotHasProperty() + + + /** + * Helper method to tell PHPUnit to expect a PHPCS RuntimeException with a certain message + * in a PHPUnit cross-version compatible manner. + * + * @param string $message The expected exception message. + * + * @return void + */ + protected function expectRuntimeExceptionMessage($message) + { + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException(self::RUNTIME_EXCEPTION); + $this->expectExceptionMessage($message); + } else { + // PHPUnit 4. + $this->setExpectedException(self::RUNTIME_EXCEPTION, $message); + } + + }//end expectRuntimeExceptionMessage() + + + /** + * Helper method to tell PHPUnit to expect a PHPCS RuntimeException which matches a regex patten + * in a PHPUnit cross-version compatible manner. + * + * @param string $regex The regex which should match. + * + * @return void + */ + protected function expectRuntimeExceptionRegex($regex) + { + if (method_exists($this, 'expectExceptionMessageMatches') === true) { + $this->expectException(self::RUNTIME_EXCEPTION); + $this->expectExceptionMessageMatches($regex); + } else if (method_exists($this, 'expectExceptionMessageRegExp') === true) { + // PHPUnit < 8.4.0. + $this->expectException(self::RUNTIME_EXCEPTION); + $this->expectExceptionMessageRegExp($regex); + } else { + // PHPUnit < 5.2.0. + $this->setExpectedExceptionRegExp(self::RUNTIME_EXCEPTION, $regex); + } + + }//end expectRuntimeExceptionRegex() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ConstructorNoSniffsTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ConstructorNoSniffsTest.xml new file mode 100644 index 000000000..cc61e3c53 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ConstructorNoSniffsTest.xml @@ -0,0 +1,6 @@ + + + + . + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ConstructorTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ConstructorTest.php new file mode 100644 index 000000000..eaea6c239 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ConstructorTest.php @@ -0,0 +1,293 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Autoload; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test various aspects of the Ruleset::__construct() method not covered via other tests. + * + * @covers \PHP_CodeSniffer\Ruleset::__construct + */ +final class ConstructorTest extends AbstractRulesetTestCase +{ + + + /** + * Test setting the ruleset name. + * + * @param array $cliArgs The CLI args to pass to the Config. + * @param string $expected The expected set ruleset name. + * + * @dataProvider dataHandlingStandardsPassedViaCLI + * + * @return void + */ + public function testHandlingStandardsPassedViaCLI($cliArgs, $expected) + { + $config = new ConfigDouble($cliArgs); + $ruleset = new Ruleset($config); + + $this->assertSame($expected, $ruleset->name); + + }//end testHandlingStandardsPassedViaCLI() + + + /** + * Data provider. + * + * @see testHandlingStandardsPassedViaCLI() + * + * @return array>> + */ + public static function dataHandlingStandardsPassedViaCLI() + { + return [ + 'Single standard passed' => [ + 'cliArgs' => ['--standard=PSR1'], + 'expected' => 'PSR1', + ], + 'Multiple standards passed' => [ + 'cliArgs' => ['--standard=PSR1,Zend'], + 'expected' => 'PSR1, Zend', + ], + 'Absolute path to standard directory passed' => [ + 'cliArgs' => [ + '--standard='.__DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'TestStandard', + // Limit this to a valid sniff to prevent running into error messages unrelated to what + // is being tested here. + '--sniffs=TestStandard.ValidSniffs.RegisterEmptyArray', + ], + 'expected' => 'TestStandard', + ], + ]; + + }//end dataHandlingStandardsPassedViaCLI() + + + /** + * Verify that standards are registered with the Autoloader. + * + * @param array $cliArgs The CLI args to pass to the Config. + * @param array $expected Minimum set of standards expected to be registered with the autoloader. + * + * @dataProvider dataStandardsAreRegisteredWithAutoloader + * + * @return void + */ + public function testStandardsAreRegisteredWithAutoloader($cliArgs, $expected) + { + $config = new ConfigDouble($cliArgs); + new Ruleset($config); + + $autoloadPaths = Autoload::getSearchPaths(); + + // Note: doing a full comparison of the Autoloader registered standards would make this test unstable + // as the `CodeSniffer.conf` of the user running the tests could interfer if they have additional + // external standards registered. + // Also note that `--runtime-set` is being used to set `installed_paths` to prevent making any changes to + // the `CodeSniffer.conf` file of the user running the tests. + foreach ($expected as $path => $namespacedStandardName) { + $this->assertArrayHasKey($path, $autoloadPaths, "Path $path has not been registered with the autoloader"); + $this->assertSame($namespacedStandardName, $autoloadPaths[$path], 'Expected (namespaced) standard name does not match'); + } + + }//end testStandardsAreRegisteredWithAutoloader() + + + /** + * Data provider. + * + * @see testStandardsAreRegisteredWithAutoloader() + * + * @return array>> + */ + public static function dataStandardsAreRegisteredWithAutoloader() + { + $basePath = dirname(dirname(dirname(__DIR__))).DIRECTORY_SEPARATOR.'src'.DIRECTORY_SEPARATOR.'Standards'.DIRECTORY_SEPARATOR; + $defaultPaths = [ + $basePath.'MySource' => 'MySource', + $basePath.'PEAR' => 'PEAR', + $basePath.'PSR1' => 'PSR1', + $basePath.'PSR12' => 'PSR12', + $basePath.'PSR2' => 'PSR2', + $basePath.'Squiz' => 'Squiz', + $basePath.'Zend' => 'Zend', + ]; + + $data = [ + 'Default standards' => [ + 'cliArgs' => [ + '--standard=PSR1', + '--runtime-set installed_paths .', + ], + 'expected' => $defaultPaths, + ], + ]; + + $extraInstalledPath = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'DirectoryExpansion'; + $extraInstalledPath .= DIRECTORY_SEPARATOR.'.hiddenAbove'.DIRECTORY_SEPARATOR.'src'.DIRECTORY_SEPARATOR.'MyStandard'; + $data['Additional non-namespaced standard'] = [ + 'cliArgs' => [ + '--standard=MyStandard', + '--runtime-set', + 'installed_paths', + $extraInstalledPath, + ], + 'expected' => ($defaultPaths + [$extraInstalledPath => 'MyStandard']), + ]; + + $extraInstalledPath = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'TestStandard'; + $data['Additional namespaced standard'] = [ + 'cliArgs' => [ + '--standard=TestStandard', + '--runtime-set', + 'installed_paths', + $extraInstalledPath, + // Limit this to a valid sniff to prevent running into error messages unrelated to what + // is being tested here. + '--sniffs=TestStandard.ValidSniffs.RegisterEmptyArray', + ], + 'expected' => ($defaultPaths + [$extraInstalledPath => 'Fixtures\TestStandard']), + ]; + + return $data; + + }//end dataStandardsAreRegisteredWithAutoloader() + + + /** + * Verify handling of sniff restrictions in combination with the caching setting. + * + * @param array $cliArgs The CLI args to pass to the Config. + * @param bool $cache Whether to turn the cache on or off. + * @param array $expected Sniffs which are expected to have been registered. + * + * @dataProvider dataCachingVersusRestrictions + * + * @return void + */ + public function testCachingVersusRestrictions($cliArgs, $cache, $expected) + { + $config = new ConfigDouble($cliArgs); + + // Overrule the cache setting (which is being ignored in the Config when the tests are running). + $config->cache = $cache; + + $ruleset = new Ruleset($config); + + $actual = array_keys($ruleset->sniffs); + sort($actual); + + $this->assertSame($expected, $actual); + + }//end testCachingVersusRestrictions() + + + /** + * Data provider. + * + * Note: the test cases only use `--exclude` to restrict, + * + * @see testCachingVersusRestrictions() + * + * @return array>> + */ + public static function dataCachingVersusRestrictions() + { + $completeSet = [ + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Files\\ByteOrderMarkSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowAlternativePHPTagsSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowShortOpenTagSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Classes\\ClassDeclarationSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Files\\SideEffectsSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Methods\\CamelCapsMethodNameSniff', + 'PHP_CodeSniffer\\Standards\\Squiz\\Sniffs\\Classes\\ValidClassNameSniff', + ]; + + return [ + 'No restrictions, cache off' => [ + 'cliArgs' => ['--standard=PSR1'], + 'cache' => false, + 'expected' => $completeSet, + ], + 'Has exclusions, cache off' => [ + 'cliArgs' => [ + '--standard=PSR1', + '--exclude=Generic.Files.ByteOrderMark,Generic.PHP.DisallowShortOpenTag,PSR1.Files.SideEffects,Generic.PHP.DisallowAlternativePHPTags', + ], + 'cache' => false, + 'expected' => [ + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Classes\\ClassDeclarationSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Methods\\CamelCapsMethodNameSniff', + 'PHP_CodeSniffer\\Standards\\Squiz\\Sniffs\\Classes\\ValidClassNameSniff', + ], + ], + 'Has sniff selection, cache off' => [ + 'cliArgs' => [ + '--standard=PSR1', + '--sniffs=Generic.Files.ByteOrderMark,Generic.PHP.DisallowShortOpenTag,PSR1.Files.SideEffects,Generic.PHP.DisallowAlternativePHPTags', + ], + 'cache' => false, + 'expected' => [ + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Files\\ByteOrderMarkSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowAlternativePHPTagsSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowShortOpenTagSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Files\\SideEffectsSniff', + ], + ], + 'No restrictions, cache on' => [ + 'cliArgs' => ['--standard=PSR1'], + 'cache' => true, + 'expected' => $completeSet, + ], + 'Has exclusions, cache on' => [ + 'cliArgs' => [ + '--standard=PSR1', + '--exclude=Generic.Files.ByteOrderMark,Generic.PHP.DisallowAlternativePHPTags,Generic.PHP.DisallowShortOpenTag,PSR1.Files.SideEffects', + ], + 'cache' => true, + 'expected' => $completeSet, + ], + + /* + * "Has sniff selection, cache on" case cannot be tested due to the `Ruleset` class + * containing special handling of sniff selection when the tests are running. + */ + + ]; + + }//end dataCachingVersusRestrictions() + + + /** + * Test an exception is thrown when no sniffs have been registered via the ruleset. + * + * @return void + */ + public function testNoSniffsRegisteredException() + { + $standard = __DIR__.'/ConstructorNoSniffsTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $message = 'ERROR: No sniffs were registered.'.PHP_EOL.PHP_EOL; + $this->expectRuntimeExceptionMessage($message); + + new Ruleset($config); + + }//end testNoSniffsRegisteredException() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/DisplayCachedMessagesTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/DisplayCachedMessagesTest.php new file mode 100644 index 000000000..55b0b7081 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/DisplayCachedMessagesTest.php @@ -0,0 +1,312 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; +use PHP_CodeSniffer\Util\MessageCollector; +use ReflectionMethod; +use ReflectionProperty; + +/** + * Test error handling for the Ruleset. + * + * Note: this is purely a unit test of the `displayCachedMessages()` method. + * The errors themselves are mocked. + * + * @covers \PHP_CodeSniffer\Ruleset::displayCachedMessages + */ +final class DisplayCachedMessagesTest extends AbstractRulesetTestCase +{ + + + /** + * Test that no exception nor output is generated when there are no cached messsages. + * + * @return void + */ + public function testDisplayCachedMessagesStaysSilentWithoutErrors() + { + $ruleset = $this->getPlainRuleset(); + + $this->expectOutputString(''); + + $this->invokeDisplayCachedMessages($ruleset); + + }//end testDisplayCachedMessagesStaysSilentWithoutErrors() + + + /** + * Verify that blocking errors encountered while loading the ruleset(s) result in an exception being thrown. + * + * @param array $messages The messages encountered. + * @param string $expected The expected function output to screen (via an internally handled exception). + * + * @dataProvider dataBlockingErrorsAreDisplayedViaAnException + * + * @return void + */ + public function testBlockingErrorsAreDisplayedViaAnException($messages, $expected) + { + $ruleset = $this->getPlainRuleset(); + $this->mockCachedMessages($ruleset, $messages); + + $this->expectRuntimeExceptionMessage($expected); + + $this->invokeDisplayCachedMessages($ruleset); + + }//end testBlockingErrorsAreDisplayedViaAnException() + + + /** + * Data provider. + * + * @see testBlockingErrorsAreDisplayedViaAnException() + * + * @return array>> + */ + public static function dataBlockingErrorsAreDisplayedViaAnException() + { + return [ + 'One error' => [ + 'messages' => ['This is a serious blocking issue' => MessageCollector::ERROR], + 'expected' => 'ERROR: This is a serious blocking issue'.PHP_EOL.PHP_EOL, + ], + 'Multiple blocking errors' => [ + 'messages' => [ + 'This is a serious blocking issue' => MessageCollector::ERROR, + 'And here is another one' => MessageCollector::ERROR, + 'OMG, why do you think that would work ?' => MessageCollector::ERROR, + ], + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Test readability is more important. + 'expected' => 'ERROR: This is a serious blocking issue'.PHP_EOL + . 'ERROR: And here is another one'.PHP_EOL + . 'ERROR: OMG, why do you think that would work ?'.PHP_EOL.PHP_EOL, + // phpcs:enable + ], + 'Mix of blocking and non-blocking errors' => [ + 'messages' => [ + 'This is a serious blocking issue' => MessageCollector::ERROR, + 'Something something deprecated and will be removed in v x.x.x' => MessageCollector::DEPRECATED, + 'Careful, this may not be correct' => MessageCollector::NOTICE, + ], + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Test readability is more important. + 'expected' => 'ERROR: This is a serious blocking issue'.PHP_EOL + . 'NOTICE: Careful, this may not be correct'.PHP_EOL + . 'DEPRECATED: Something something deprecated and will be removed in v x.x.x'.PHP_EOL.PHP_EOL, + // phpcs:enable + ], + ]; + + }//end dataBlockingErrorsAreDisplayedViaAnException() + + + /** + * Test display of non-blocking messages encountered while loading the ruleset(s). + * + * @param array $messages The messages encountered. + * @param string $expected The expected function output to screen. + * + * @dataProvider dataNonBlockingErrorsGenerateOutput + * + * @return void + */ + public function testNonBlockingErrorsGenerateOutput($messages, $expected) + { + $ruleset = $this->getPlainRuleset(); + $this->mockCachedMessages($ruleset, $messages); + + $this->expectOutputString($expected); + + $this->invokeDisplayCachedMessages($ruleset); + + }//end testNonBlockingErrorsGenerateOutput() + + + /** + * Data provider. + * + * @see testNonBlockingErrorsGenerateOutput() + * + * @return array>> + */ + public static function dataNonBlockingErrorsGenerateOutput() + { + return [ + 'One deprecation' => [ + 'messages' => ['My deprecation message' => MessageCollector::DEPRECATED], + 'expected' => 'DEPRECATED: My deprecation message'.PHP_EOL.PHP_EOL, + ], + 'One notice' => [ + 'messages' => ['My notice message' => MessageCollector::NOTICE], + 'expected' => 'NOTICE: My notice message'.PHP_EOL.PHP_EOL, + ], + 'One warning' => [ + 'messages' => ['My warning message' => MessageCollector::WARNING], + 'expected' => 'WARNING: My warning message'.PHP_EOL.PHP_EOL, + ], + 'Multiple non-blocking errors' => [ + 'messages' => [ + 'Something something deprecated and will be removed in v x.x.x' => MessageCollector::DEPRECATED, + 'Something is not supported and support may be removed' => MessageCollector::WARNING, + 'Some other deprecation notice' => MessageCollector::DEPRECATED, + 'Careful, this may not be correct' => MessageCollector::NOTICE, + ], + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Test readability is more important. + 'expected' => 'WARNING: Something is not supported and support may be removed'.PHP_EOL + .'NOTICE: Careful, this may not be correct'.PHP_EOL + .'DEPRECATED: Something something deprecated and will be removed in v x.x.x'.PHP_EOL + .'DEPRECATED: Some other deprecation notice'.PHP_EOL.PHP_EOL, + // phpcs:enable + ], + ]; + + }//end dataNonBlockingErrorsGenerateOutput() + + + /** + * Test that blocking errors will always show, independently of specific command-line options being used. + * + * @param array $configArgs Arguments to pass to the Config. + * + * @dataProvider dataSelectiveDisplayOfMessages + * + * @return void + */ + public function testBlockingErrorsAlwaysShow($configArgs) + { + $config = new ConfigDouble($configArgs); + $ruleset = new Ruleset($config); + + $message = 'Some serious error'; + $errors = [$message => MessageCollector::ERROR]; + $this->mockCachedMessages($ruleset, $errors); + + $this->expectRuntimeExceptionMessage('ERROR: '.$message.PHP_EOL); + + $this->invokeDisplayCachedMessages($ruleset); + + }//end testBlockingErrorsAlwaysShow() + + + /** + * Test that non-blocking messsages will not show when specific command-line options are being used. + * + * @param array $configArgs Arguments to pass to the Config. + * + * @dataProvider dataSelectiveDisplayOfMessages + * + * @return void + */ + public function testNonBlockingErrorsDoNotShowUnderSpecificCircumstances($configArgs) + { + $config = new ConfigDouble($configArgs); + $ruleset = new Ruleset($config); + $this->mockCachedMessages($ruleset, ['Deprecation notice' => MessageCollector::DEPRECATED]); + + $this->expectOutputString(''); + + $this->invokeDisplayCachedMessages($ruleset); + + }//end testNonBlockingErrorsDoNotShowUnderSpecificCircumstances() + + + /** + * Data provider. + * + * @see testBlockingErrorsAlwaysShow() + * @see testNonBlockingErrorsDoNotShow() + * + * @return array>> + */ + public static function dataSelectiveDisplayOfMessages() + { + $data = [ + 'Explain mode' => [ + 'configArgs' => ['-e'], + ], + 'Quiet mode' => [ + 'configArgs' => ['-q'], + ], + ]; + + // Setting the `--generator` arg is only supported when running `phpcs`. + if (PHP_CODESNIFFER_CBF === false) { + $data['Documentation is requested'] = [ + 'configArgs' => ['--generator=text'], + ]; + } + + return $data; + + }//end dataSelectiveDisplayOfMessages() + + + /** + * Test Helper. + * + * @return \PHP_CodeSniffer\Ruleset + */ + private function getPlainRuleset() + { + static $ruleset; + + if (isset($ruleset) === false) { + $config = new ConfigDouble(); + $ruleset = new Ruleset($config); + } + + return $ruleset; + + }//end getPlainRuleset() + + + /** + * Add mock messages to the message cache. + * + * @param \PHP_CodeSniffer\Ruleset $ruleset The ruleset object. + * @param array $messages The messages to add to the message cache. + * + * @return void + */ + private function mockCachedMessages(Ruleset $ruleset, $messages) + { + $reflProperty = new ReflectionProperty($ruleset, 'msgCache'); + $reflProperty->setAccessible(true); + + $msgCache = $reflProperty->getValue($ruleset); + foreach ($messages as $msg => $type) { + $msgCache->add($msg, $type); + } + + $reflProperty->setAccessible(false); + + }//end mockCachedMessages() + + + /** + * Invoke the display of the cached messages. + * + * @param \PHP_CodeSniffer\Ruleset $ruleset The ruleset object. + * + * @return void + */ + private function invokeDisplayCachedMessages(Ruleset $ruleset) + { + $reflMethod = new ReflectionMethod($ruleset, 'displayCachedMessages'); + $reflMethod->setAccessible(true); + $reflMethod->invoke($ruleset); + $reflMethod->setAccessible(false); + + }//end invokeDisplayCachedMessages() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceCaseMismatch1Test.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceCaseMismatch1Test.xml new file mode 100644 index 000000000..e72c4b9dd --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceCaseMismatch1Test.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceCaseMismatch2Test.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceCaseMismatch2Test.xml new file mode 100644 index 000000000..a10137491 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceCaseMismatch2Test.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathFailTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathFailTest.xml new file mode 100644 index 000000000..5298b54af --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathFailTest.xml @@ -0,0 +1,8 @@ + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathTest.php new file mode 100644 index 000000000..10a4dd981 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathTest.php @@ -0,0 +1,121 @@ + + * @copyright 2025 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test home path handling in the Ruleset::expandRulesetReference() method. + * + * @covers \PHP_CodeSniffer\Ruleset::expandRulesetReference + */ +final class ExpandRulesetReferenceHomePathTest extends AbstractRulesetTestCase +{ + + /** + * Original value of the user's home path environment variable. + * + * @var string|false Path or false is the `HOME` environment variable is not available. + */ + private static $homepath = false; + + + /** + * Store the user's home path. + * + * @beforeClass + * + * @return void + */ + public static function storeHomePath() + { + self::$homepath = getenv('HOME'); + + }//end storeHomePath() + + + /** + * Restore the user's home path environment variable in case the test changed it or created it. + * + * @afterClass + * + * @return void + */ + public static function restoreHomePath() + { + if (is_string(self::$homepath) === true) { + putenv('HOME='.self::$homepath); + } else { + // Remove the environment variable as it didn't exist before. + putenv('HOME'); + } + + }//end restoreHomePath() + + + /** + * Set the home path to an alternative location. + * + * @before + * + * @return void + */ + protected function setHomePath() + { + $fakeHomePath = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'FakeHomePath'; + putenv("HOME=$fakeHomePath"); + + }//end setHomePath() + + + /** + * Verify that a sniff reference with the magic "home path" placeholder gets expanded correctly + * and finds sniffs if the path exists underneath the "home path". + * + * @return void + */ + public function testHomePathRefGetsExpandedAndFindsSniff() + { + // Set up the ruleset. + $standard = __DIR__.'/ExpandRulesetReferenceHomePathTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $expected = ['MyStandard.Category.Valid' => 'FakeHomePath\\MyStandard\\Sniffs\\Category\\ValidSniff']; + + $this->assertSame($expected, $ruleset->sniffCodes); + + }//end testHomePathRefGetsExpandedAndFindsSniff() + + + /** + * Verify that a sniff reference with the magic "home path" placeholder gets expanded correctly + * and still fails to find sniffs if the path doesn't exists underneath the "home path". + * + * @return void + */ + public function testHomePathRefGetsExpandedAndThrowsExceptionWhenPathIsInvalid() + { + // Set up the ruleset. + $standard = __DIR__.'/ExpandRulesetReferenceHomePathFailTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $exceptionMessage = 'ERROR: Referenced sniff "~/src/MyStandard/Sniffs/DoesntExist/" does not exist.'.PHP_EOL; + $exceptionMessage .= 'ERROR: No sniffs were registered.'.PHP_EOL.PHP_EOL; + $this->expectRuntimeExceptionMessage($exceptionMessage); + + new Ruleset($config); + + }//end testHomePathRefGetsExpandedAndThrowsExceptionWhenPathIsInvalid() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathTest.xml new file mode 100644 index 000000000..e21f2a6e0 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceHomePathTest.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalIgnoreTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalIgnoreTest.xml new file mode 100644 index 000000000..edd9b1e87 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalIgnoreTest.xml @@ -0,0 +1,15 @@ + + + + + + + 0 + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalStandardTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalStandardTest.xml new file mode 100644 index 000000000..d01c68cfb --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalStandardTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalTest.php new file mode 100644 index 000000000..5f0180dac --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInternalTest.php @@ -0,0 +1,71 @@ + + * @copyright 2025 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test handling of "internal" references in the Ruleset::expandRulesetReference() method. + * + * @covers \PHP_CodeSniffer\Ruleset::expandRulesetReference + */ +final class ExpandRulesetReferenceInternalTest extends AbstractRulesetTestCase +{ + + + /** + * Verify that a ruleset reference starting with "Internal." (including the dot) doesn't cause any sniffs to be registered. + * + * @return void + */ + public function testInternalRefDoesNotGetExpanded() + { + // Set up the ruleset. + $standard = __DIR__.'/ExpandRulesetReferenceInternalIgnoreTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $expected = ['Generic.PHP.BacktickOperator' => 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\BacktickOperatorSniff']; + + $this->assertSame($expected, $ruleset->sniffCodes); + + }//end testInternalRefDoesNotGetExpanded() + + + /** + * While definitely not recommended, including a standard named "Internal", _does_ allow for sniffs to be registered. + * + * Note: customizations (exclusions/property setting etc) for individual sniffs may not always be handled correctly, + * which is why naming a standard "Internal" is definitely not recommended. + * + * @return void + */ + public function testInternalStandardDoesGetExpanded() + { + $message = 'DEPRECATED: The name "Internal" is reserved for internal use. A PHP_CodeSniffer standard should not be called "Internal".'.PHP_EOL; + $message .= 'Contact the maintainer of the standard to fix this.'.PHP_EOL.PHP_EOL; + + $this->expectOutputString($message); + + // Set up the ruleset. + $standard = __DIR__.'/ExpandRulesetReferenceInternalStandardTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $expected = ['Internal.Valid.Valid' => 'Fixtures\\Internal\\Sniffs\\Valid\\ValidSniff']; + + $this->assertSame($expected, $ruleset->sniffCodes); + + }//end testInternalStandardDoesGetExpanded() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode1Test.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode1Test.xml new file mode 100644 index 000000000..a5531bda4 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode1Test.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode2Test.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode2Test.xml new file mode 100644 index 000000000..c18ba25c5 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode2Test.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode3Test.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode3Test.xml new file mode 100644 index 000000000..46ac2641f --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidErrorCode3Test.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidHomePathRefTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidHomePathRefTest.xml new file mode 100644 index 000000000..349449edf --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceInvalidHomePathRefTest.xml @@ -0,0 +1,8 @@ + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceMissingFileTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceMissingFileTest.xml new file mode 100644 index 000000000..18e8c390b --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceMissingFileTest.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceTest.php new file mode 100644 index 000000000..284bdf7fb --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceTest.php @@ -0,0 +1,134 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test various aspects of the Ruleset::expandRulesetReference() method not covered by other tests. + * + * @covers \PHP_CodeSniffer\Ruleset::expandRulesetReference + */ +final class ExpandRulesetReferenceTest extends AbstractRulesetTestCase +{ + + + /** + * Test handling of path references relative to the originally included ruleset. + * + * @return void + */ + public function testRulesetRelativePathReferences() + { + // Set up the ruleset. + $standard = __DIR__.'/ExpandRulesetReferenceTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $expected = [ + 'ExternalA.CheckSomething.Valid' => 'Fixtures\\ExternalA\\Sniffs\\CheckSomething\\ValidSniff', + 'TestStandard.ValidSniffs.RegisterEmptyArray' => 'Fixtures\\TestStandard\\Sniffs\\ValidSniffs\\RegisterEmptyArraySniff', + 'ExternalB.CheckMore.Valid' => 'Fixtures\\ExternalB\\Sniffs\\CheckMore\\ValidSniff', + ]; + + $this->assertSame($expected, $ruleset->sniffCodes); + + }//end testRulesetRelativePathReferences() + + + /** + * Test that an exception is thrown if a ruleset contains an unresolvable reference. + * + * @param string $standard The standard to use for the test. + * @param string $replacement The reference which will be used in the exception message. + * + * @dataProvider dataUnresolvableReferenceThrowsException + * + * @return void + */ + public function testUnresolvableReferenceThrowsException($standard, $replacement) + { + // Set up the ruleset. + $standard = __DIR__.'/'.$standard; + $config = new ConfigDouble(["--standard=$standard"]); + + $exceptionMessage = 'ERROR: Referenced sniff "%s" does not exist.'.PHP_EOL; + $exceptionMessage .= 'ERROR: No sniffs were registered.'.PHP_EOL.PHP_EOL; + $this->expectRuntimeExceptionMessage(sprintf($exceptionMessage, $replacement)); + + new Ruleset($config); + + }//end testUnresolvableReferenceThrowsException() + + + /** + * Data provider. + * + * @see testUnresolvableReferenceThrowsException() + * + * @return array> + */ + public static function dataUnresolvableReferenceThrowsException() + { + $data = [ + 'Referencing a non-existent XML file' => [ + 'standard' => 'ExpandRulesetReferenceMissingFileTest.xml', + 'replacement' => './MissingFile.xml', + ], + 'Referencing an invalid directory starting with "~"' => [ + 'standard' => 'ExpandRulesetReferenceInvalidHomePathRefTest.xml', + 'replacement' => '~/src/Standards/Squiz/Sniffs/Files/', + ], + 'Referencing an unknown standard' => [ + 'standard' => 'ExpandRulesetReferenceUnknownStandardTest.xml', + 'replacement' => 'UnknownStandard', + ], + 'Referencing a non-existent category in a known standard' => [ + 'standard' => 'ExpandRulesetReferenceUnknownCategoryTest.xml', + 'replacement' => 'TestStandard.UnknownCategory', + ], + 'Referencing a non-existent sniff in a known standard' => [ + 'standard' => 'ExpandRulesetReferenceUnknownSniffTest.xml', + 'replacement' => 'TestStandard.InvalidSniffs.UnknownRule', + ], + 'Referencing an invalid error code - no standard name' => [ + 'standard' => 'ExpandRulesetReferenceInvalidErrorCode1Test.xml', + 'replacement' => '.Invalid.Undetermined.Found', + ], + 'Referencing an invalid error code - no category name' => [ + 'standard' => 'ExpandRulesetReferenceInvalidErrorCode2Test.xml', + 'replacement' => 'Standard..Undetermined.Found', + ], + 'Referencing an invalid error code - no sniff name' => [ + 'standard' => 'ExpandRulesetReferenceInvalidErrorCode3Test.xml', + 'replacement' => 'Standard.Invalid..Found', + ], + ]; + + // Add tests which are only relevant for case-sensitive OSes. + if (stripos(PHP_OS, 'WIN') === false) { + $data['Referencing an existing sniff, but there is a case mismatch (OS-dependent) [1]'] = [ + 'standard' => 'ExpandRulesetReferenceCaseMismatch1Test.xml', + 'replacement' => 'psr12.functions.nullabletypedeclaration', + ]; + $data['Referencing an existing sniff, but there is a case mismatch (OS-dependent) [2]'] = [ + 'standard' => 'ExpandRulesetReferenceCaseMismatch2Test.xml', + 'replacement' => 'PSR12.Functions.ReturntypeDeclaration', + ]; + } + + return $data; + + }//end dataUnresolvableReferenceThrowsException() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceTest.xml new file mode 100644 index 000000000..f3147c5e1 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceTest.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownCategoryTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownCategoryTest.xml new file mode 100644 index 000000000..17ec1a7bd --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownCategoryTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownSniffTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownSniffTest.xml new file mode 100644 index 000000000..8cff25e1c --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownSniffTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownStandardTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownStandardTest.xml new file mode 100644 index 000000000..c8b56b10e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandRulesetReferenceUnknownStandardTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandSniffDirectoryTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandSniffDirectoryTest.php new file mode 100644 index 000000000..ddd3a5148 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandSniffDirectoryTest.php @@ -0,0 +1,67 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test the Ruleset::expandSniffDirectory() method. + * + * @covers \PHP_CodeSniffer\Ruleset::expandSniffDirectory + */ +final class ExpandSniffDirectoryTest extends TestCase +{ + + + /** + * Test finding sniff files based on a given directory. + * + * This test verifies that: + * - Hidden (sub)directories are ignored, but the given directory is allowed to be within a hidden directory. + * - Hidden files are ignored. + * - Files without a "php" extension are ignored. + * - Files without a "Sniff" suffix in the file name are ignored. + * + * Note: the "[Another]AbstractSniff" files will be found and included in the return value + * from `Ruleset::expandSniffDirectory()`. + * Those are filtered out later in the `Ruleset::registerSniffs()` method. + * + * @return void + */ + public function testExpandSniffDirectory() + { + // Set up the ruleset. + $standard = __DIR__.'/ExpandSniffDirectoryTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $expectedPathToRuleset = __DIR__.'/Fixtures/DirectoryExpansion/.hiddenAbove/src/MyStandard/ruleset.xml'; + $expectedPathToRuleset = realpath($expectedPathToRuleset); + $this->assertNotFalse($expectedPathToRuleset, 'Ruleset file could not be found'); + $this->assertContains($expectedPathToRuleset, $ruleset->paths, 'Ruleset file not included in the "seen ruleset paths"'); + + $expectedSniffCodes = [ + 'MyStandard.CategoryA.FindMe' => 'MyStandard\\Sniffs\\CategoryA\\FindMeSniff', + 'MyStandard.CategoryB.FindMe' => 'MyStandard\\Sniffs\\CategoryB\\FindMeSniff', + ]; + + // Sort the value to make the tests stable as different OSes will read directories + // in a different order and the order is not relevant for these tests. Just the values. + $actual = $ruleset->sniffCodes; + ksort($actual); + + $this->assertSame($expectedSniffCodes, $actual, 'Registered sniffs do not match expectation'); + + }//end testExpandSniffDirectory() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandSniffDirectoryTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandSniffDirectoryTest.xml new file mode 100644 index 000000000..158805e5c --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExpandSniffDirectoryTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainCustomRulesetTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainCustomRulesetTest.xml index cbca4fd51..77b6c2c87 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainCustomRulesetTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainCustomRulesetTest.xml @@ -1,5 +1,5 @@ - + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainSingleSniffTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainSingleSniffTest.xml index 159b7efa8..d345779d1 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainSingleSniffTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainSingleSniffTest.xml @@ -1,5 +1,5 @@ - + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainTest.php index fc84f88ac..38c74be31 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ExplainTest.php @@ -10,7 +10,6 @@ namespace PHP_CodeSniffer\Tests\Core\Ruleset; use PHP_CodeSniffer\Ruleset; -use PHP_CodeSniffer\Runner; use PHP_CodeSniffer\Tests\ConfigDouble; use PHPUnit\Framework\TestCase; @@ -185,21 +184,23 @@ public function testExplainWithDeprecatedSniffs() $ruleset = new Ruleset($config); $expected = PHP_EOL; - $expected .= 'The SniffDeprecationTest standard contains 9 sniffs'.PHP_EOL.PHP_EOL; - - $expected .= 'Fixtures (9 sniffs)'.PHP_EOL; - $expected .= '-------------------'.PHP_EOL; - $expected .= ' Fixtures.Deprecated.WithLongReplacement *'.PHP_EOL; - $expected .= ' Fixtures.Deprecated.WithoutReplacement *'.PHP_EOL; - $expected .= ' Fixtures.Deprecated.WithReplacement *'.PHP_EOL; - $expected .= ' Fixtures.Deprecated.WithReplacementContainingLinuxNewlines *'.PHP_EOL; - $expected .= ' Fixtures.Deprecated.WithReplacementContainingNewlines *'.PHP_EOL; - $expected .= ' Fixtures.SetProperty.AllowedAsDeclared'.PHP_EOL; - $expected .= ' Fixtures.SetProperty.AllowedViaMagicMethod'.PHP_EOL; - $expected .= ' Fixtures.SetProperty.AllowedViaStdClass'.PHP_EOL; - $expected .= ' Fixtures.SetProperty.NotAllowedViaAttribute'.PHP_EOL.PHP_EOL; - - $expected .= '* Sniffs marked with an asterix are deprecated.'.PHP_EOL; + $expected .= 'The ShowSniffDeprecationsTest standard contains 11 sniffs'.PHP_EOL.PHP_EOL; + + $expected .= 'TestStandard (11 sniffs)'.PHP_EOL; + $expected .= '------------------------'.PHP_EOL; + $expected .= ' TestStandard.Deprecated.WithLongReplacement *'.PHP_EOL; + $expected .= ' TestStandard.Deprecated.WithoutReplacement *'.PHP_EOL; + $expected .= ' TestStandard.Deprecated.WithReplacement *'.PHP_EOL; + $expected .= ' TestStandard.Deprecated.WithReplacementContainingLinuxNewlines *'.PHP_EOL; + $expected .= ' TestStandard.Deprecated.WithReplacementContainingNewlines *'.PHP_EOL; + $expected .= ' TestStandard.SetProperty.AllowedAsDeclared'.PHP_EOL; + $expected .= ' TestStandard.SetProperty.AllowedViaMagicMethod'.PHP_EOL; + $expected .= ' TestStandard.SetProperty.AllowedViaStdClass'.PHP_EOL; + $expected .= ' TestStandard.SetProperty.NotAllowedViaAttribute'.PHP_EOL; + $expected .= ' TestStandard.SetProperty.PropertyTypeHandling'.PHP_EOL; + $expected .= ' TestStandard.ValidSniffs.RegisterEmptyArray'.PHP_EOL.PHP_EOL; + + $expected .= '* Sniffs marked with an asterisk are deprecated.'.PHP_EOL; $this->expectOutputString($expected); @@ -208,51 +209,4 @@ public function testExplainWithDeprecatedSniffs() }//end testExplainWithDeprecatedSniffs() - /** - * Test that each standard passed on the command-line is explained separately. - * - * @covers \PHP_CodeSniffer\Runner::runPHPCS - * - * @return void - */ - public function testExplainWillExplainEachStandardSeparately() - { - $standard = __DIR__.'/ExplainSingleSniffTest.xml'; - $_SERVER['argv'] = [ - 'phpcs', - '-e', - "--standard=PSR1,$standard", - '--report-width=80', - ]; - - $expected = PHP_EOL; - $expected .= 'The PSR1 standard contains 8 sniffs'.PHP_EOL.PHP_EOL; - $expected .= 'Generic (4 sniffs)'.PHP_EOL; - $expected .= '------------------'.PHP_EOL; - $expected .= ' Generic.Files.ByteOrderMark'.PHP_EOL; - $expected .= ' Generic.NamingConventions.UpperCaseConstantName'.PHP_EOL; - $expected .= ' Generic.PHP.DisallowAlternativePHPTags'.PHP_EOL; - $expected .= ' Generic.PHP.DisallowShortOpenTag'.PHP_EOL.PHP_EOL; - $expected .= 'PSR1 (3 sniffs)'.PHP_EOL; - $expected .= '---------------'.PHP_EOL; - $expected .= ' PSR1.Classes.ClassDeclaration'.PHP_EOL; - $expected .= ' PSR1.Files.SideEffects'.PHP_EOL; - $expected .= ' PSR1.Methods.CamelCapsMethodName'.PHP_EOL.PHP_EOL; - $expected .= 'Squiz (1 sniff)'.PHP_EOL; - $expected .= '---------------'.PHP_EOL; - $expected .= ' Squiz.Classes.ValidClassName'.PHP_EOL.PHP_EOL; - - $expected .= 'The ExplainSingleSniffTest standard contains 1 sniff'.PHP_EOL.PHP_EOL; - $expected .= 'Squiz (1 sniff)'.PHP_EOL; - $expected .= '---------------'.PHP_EOL; - $expected .= ' Squiz.Scope.MethodScope'.PHP_EOL; - - $this->expectOutputString($expected); - - $runner = new Runner(); - $exitCode = $runner->runPHPCS(); - - }//end testExplainWillExplainEachStandardSeparately() - - }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/BrokenNamingConventions/Sniffs/Category/Sniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/BrokenNamingConventions/Sniffs/Category/Sniff.php new file mode 100644 index 000000000..9da190d17 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/BrokenNamingConventions/Sniffs/Category/Sniff.php @@ -0,0 +1,24 @@ + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ExternalA/Sniffs/CheckSomething/ValidSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ExternalA/Sniffs/CheckSomething/ValidSniff.php new file mode 100644 index 000000000..51061e3b5 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ExternalA/Sniffs/CheckSomething/ValidSniff.php @@ -0,0 +1,25 @@ + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ExternalB/Sniffs/CheckMore/ValidSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ExternalB/Sniffs/CheckMore/ValidSniff.php new file mode 100644 index 000000000..1584f7050 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ExternalB/Sniffs/CheckMore/ValidSniff.php @@ -0,0 +1,25 @@ + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/FakeHomePath/src/MyStandard/Sniffs/Category/ValidSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/FakeHomePath/src/MyStandard/Sniffs/Category/ValidSniff.php new file mode 100644 index 000000000..9346df9eb --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/FakeHomePath/src/MyStandard/Sniffs/Category/ValidSniff.php @@ -0,0 +1,25 @@ + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Internal/Sniffs/Valid/ValidSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Internal/Sniffs/Valid/ValidSniff.php new file mode 100644 index 000000000..e7a04f495 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Internal/Sniffs/Valid/ValidSniff.php @@ -0,0 +1,25 @@ + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/Sniffs b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/Sniffs new file mode 100644 index 000000000..e69de29bb diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/ruleset.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/ruleset.xml new file mode 100644 index 000000000..5b0897c47 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/InvalidNoSniffsDir/ruleset.xml @@ -0,0 +1,4 @@ + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadAlways.1.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadAlways.1.php new file mode 100644 index 000000000..2b1fadaf5 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadAlways.1.php @@ -0,0 +1,8 @@ +string,10=>10,float=>1.5,null=>null,true=>true,false=>false +// phpcs:set TestStandard.SetProperty.PropertyTypeHandling expectsEmptyArray[] + +// phpcs:set TestStandard.SetProperty.PropertyTypeHandling expectsOldSchoolArrayWithOnlyValues[] string, 10, 1.5, null, true, false +// phpcs:set TestStandard.SetProperty.PropertyTypeHandling expectsOldSchoolArrayWithKeysAndValues[] string=>string,10=>10,float=>1.5,null=>null,true=>true,false=>false +// phpcs:set TestStandard.SetProperty.PropertyTypeHandling expectsOldSchoolEmptyArray[] + +echo 'hello!'; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithLongReplacementSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithLongReplacementSniff.php similarity index 96% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithLongReplacementSniff.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithLongReplacementSniff.php index 40c23113d..659d89ee2 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithLongReplacementSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithLongReplacementSniff.php @@ -5,7 +5,7 @@ * @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest */ -namespace Fixtures\Sniffs\Deprecated; +namespace Fixtures\TestStandard\Sniffs\Deprecated; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\DeprecatedSniff; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithReplacementContainingLinuxNewlinesSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithReplacementContainingLinuxNewlinesSniff.php similarity index 95% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithReplacementContainingLinuxNewlinesSniff.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithReplacementContainingLinuxNewlinesSniff.php index 0363927db..d870cbf7e 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithReplacementContainingLinuxNewlinesSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithReplacementContainingLinuxNewlinesSniff.php @@ -5,7 +5,7 @@ * @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest */ -namespace Fixtures\Sniffs\Deprecated; +namespace Fixtures\TestStandard\Sniffs\Deprecated; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\DeprecatedSniff; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithReplacementContainingNewlinesSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithReplacementContainingNewlinesSniff.php similarity index 95% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithReplacementContainingNewlinesSniff.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithReplacementContainingNewlinesSniff.php index e9e76c8c0..2516d7cd2 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithReplacementContainingNewlinesSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithReplacementContainingNewlinesSniff.php @@ -5,7 +5,7 @@ * @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest */ -namespace Fixtures\Sniffs\Deprecated; +namespace Fixtures\TestStandard\Sniffs\Deprecated; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\DeprecatedSniff; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithReplacementSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithReplacementSniff.php similarity index 93% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithReplacementSniff.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithReplacementSniff.php index a63398281..195344867 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithReplacementSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithReplacementSniff.php @@ -5,7 +5,7 @@ * @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest */ -namespace Fixtures\Sniffs\Deprecated; +namespace Fixtures\TestStandard\Sniffs\Deprecated; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\DeprecatedSniff; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithoutReplacementSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithoutReplacementSniff.php similarity index 93% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithoutReplacementSniff.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithoutReplacementSniff.php index d6d388710..888e08fd1 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/Deprecated/WithoutReplacementSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/Deprecated/WithoutReplacementSniff.php @@ -5,7 +5,7 @@ * @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest */ -namespace Fixtures\Sniffs\Deprecated; +namespace Fixtures\TestStandard\Sniffs\Deprecated; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\DeprecatedSniff; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/EmptyDeprecationVersionSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/EmptyDeprecationVersionSniff.php similarity index 92% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/EmptyDeprecationVersionSniff.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/EmptyDeprecationVersionSniff.php index 8d3dcd421..4e26b7b76 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/EmptyDeprecationVersionSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/EmptyDeprecationVersionSniff.php @@ -5,7 +5,7 @@ * @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest */ -namespace Fixtures\Sniffs\DeprecatedInvalid; +namespace Fixtures\TestStandard\Sniffs\DeprecatedInvalid; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\DeprecatedSniff; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/EmptyRemovalVersionSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/EmptyRemovalVersionSniff.php similarity index 92% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/EmptyRemovalVersionSniff.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/EmptyRemovalVersionSniff.php index 828b16928..cdf15c303 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/EmptyRemovalVersionSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/EmptyRemovalVersionSniff.php @@ -5,7 +5,7 @@ * @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest */ -namespace Fixtures\Sniffs\DeprecatedInvalid; +namespace Fixtures\TestStandard\Sniffs\DeprecatedInvalid; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\DeprecatedSniff; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/InvalidDeprecationMessageSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/InvalidDeprecationMessageSniff.php similarity index 92% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/InvalidDeprecationMessageSniff.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/InvalidDeprecationMessageSniff.php index a6819825f..368bd4140 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/InvalidDeprecationMessageSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/InvalidDeprecationMessageSniff.php @@ -5,7 +5,7 @@ * @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest */ -namespace Fixtures\Sniffs\DeprecatedInvalid; +namespace Fixtures\TestStandard\Sniffs\DeprecatedInvalid; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\DeprecatedSniff; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/InvalidDeprecationVersionSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/InvalidDeprecationVersionSniff.php similarity index 92% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/InvalidDeprecationVersionSniff.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/InvalidDeprecationVersionSniff.php index d51aa876c..b8218ad57 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/InvalidDeprecationVersionSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/InvalidDeprecationVersionSniff.php @@ -5,7 +5,7 @@ * @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest */ -namespace Fixtures\Sniffs\DeprecatedInvalid; +namespace Fixtures\TestStandard\Sniffs\DeprecatedInvalid; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\DeprecatedSniff; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/InvalidRemovalVersionSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/InvalidRemovalVersionSniff.php similarity index 92% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/InvalidRemovalVersionSniff.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/InvalidRemovalVersionSniff.php index a10997bbc..1177e7333 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/Sniffs/DeprecatedInvalid/InvalidRemovalVersionSniff.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/DeprecatedInvalid/InvalidRemovalVersionSniff.php @@ -5,7 +5,7 @@ * @see \PHP_CodeSniffer\Tests\Core\Ruleset\SniffDeprecationTest */ -namespace Fixtures\Sniffs\DeprecatedInvalid; +namespace Fixtures\TestStandard\Sniffs\DeprecatedInvalid; use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\DeprecatedSniff; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/InvalidSniffError/NoImplementsNoProcessSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/InvalidSniffError/NoImplementsNoProcessSniff.php new file mode 100644 index 000000000..d6aa4ee6a --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/InvalidSniffError/NoImplementsNoProcessSniff.php @@ -0,0 +1,17 @@ + + */ + public $expectsArrayWithOnlyValues; + + /** + * Used to verify that array properties with keys get parsed to a proper array. + * + * @var array + */ + public $expectsArrayWithKeysAndValues; + + /** + * Used to verify that array properties can get extended. + * + * @var array + */ + public $expectsArrayWithExtendedValues; + + /** + * Used to verify that array properties can get extended. + * + * @var array + */ + public $expectsArrayWithExtendedKeysAndValues; + + /** + * Used to verify that array properties allow for setting a property to an empty array. + * + * @var array + */ + public $expectsEmptyArray; + + /** + * Used to verify that array properties passed as a string get parsed to a proper array. + * + * @var array + */ + public $expectsOldSchoolArrayWithOnlyValues; + + /** + * Used to verify that array properties passed as a string with keys get parsed to a proper array. + * + * @var array + */ + public $expectsOldSchoolArrayWithKeysAndValues; + + /** + * Used to verify that array properties passed as a string can get extended. + * + * @var array + */ + public $expectsOldSchoolArrayWithExtendedValues; + + /** + * Used to verify that array properties passed as a string can get extended. + * + * @var array + */ + public $expectsOldSchoolArrayWithExtendedKeysAndValues; + + /** + * Used to verify that array properties passed as a string allow for setting a property to an empty array. + * + * @var array + */ + public $expectsOldSchoolEmptyArray; + + public function register() + { + return [T_ECHO]; + } + + public function process(File $phpcsFile, $stackPtr) + { + // Do something. + } +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SupportedTokenizers/ImplementsDeprecatedInterfaceSniff.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SupportedTokenizers/ImplementsDeprecatedInterfaceSniff.php new file mode 100644 index 000000000..af095072b --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SupportedTokenizers/ImplementsDeprecatedInterfaceSniff.php @@ -0,0 +1,46 @@ + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ruleset.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ruleset.xml deleted file mode 100644 index 11a899ada..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/Fixtures/ruleset.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIgnorePatternsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIgnorePatternsTest.php new file mode 100644 index 000000000..ae6b8bea5 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIgnorePatternsTest.php @@ -0,0 +1,111 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test the Ruleset::getIgnorePatterns() method. + * + * @covers \PHP_CodeSniffer\Ruleset::getIgnorePatterns + */ +final class GetIgnorePatternsTest extends TestCase +{ + + /** + * The Ruleset object. + * + * @var \PHP_CodeSniffer\Ruleset + */ + private static $ruleset; + + + /** + * Initialize the config and ruleset objects for this test. + * + * @beforeClass + * + * @return void + */ + public static function initializeConfigAndRuleset() + { + // Set up the ruleset. + $standard = __DIR__."/GetIgnorePatternsTest.xml"; + $config = new ConfigDouble(["--standard=$standard"]); + self::$ruleset = new Ruleset($config); + + }//end initializeConfigAndRuleset() + + + /** + * Test retrieving ignore patterns. + * + * @param string|null $listener The listener to get patterns for or null for all patterns. + * @param array> $expected The expected function output. + * + * @dataProvider dataGetIgnorePatterns + * + * @return void + */ + public function testGetIgnorePatterns($listener, $expected) + { + $this->assertSame($expected, self::$ruleset->getIgnorePatterns($listener)); + + }//end testGetIgnorePatterns() + + + /** + * Data provider. + * + * @see self::testGetIgnorePatterns() + * + * @return array>|null>> + */ + public static function dataGetIgnorePatterns() + { + return [ + 'All ignore patterns' => [ + 'listener' => null, + 'expected' => [ + 'PSR1.Classes.ClassDeclaration' => [ + './src/*/file.php' => 'absolute', + './bin/' => 'relative', + ], + 'Generic.Formatting.SpaceAfterCast' => [ + './src/*/test\\.php$' => 'absolute', + ], + './tests/' => 'absolute', + './vendor/*' => 'absolute', + '*/node-modules/*' => 'relative', + ], + ], + 'Ignore patterns for PSR1.Classes.ClassDeclaration' => [ + 'listener' => 'PSR1.Classes.ClassDeclaration', + 'expected' => [ + './src/*/file.php' => 'absolute', + './bin/' => 'relative', + ], + ], + 'Ignore patterns for Generic.Formatting.SpaceAfterCast' => [ + 'listener' => 'Generic.Formatting.SpaceAfterCast', + 'expected' => ['./src/*/test\\.php$' => 'absolute'], + ], + 'Ignore patterns for sniff without ignore patterns' => [ + 'listener' => 'PSR1.Files.SideEffects', + 'expected' => [], + ], + ]; + + }//end dataGetIgnorePatterns() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIgnorePatternsTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIgnorePatternsTest.xml new file mode 100644 index 000000000..a0496c802 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIgnorePatternsTest.xml @@ -0,0 +1,19 @@ + + + + ./tests/ + ./vendor/* + */node-modules/* + + + + + ./src/*/file.php + ./bin/ + + + + ./src/*/test\.php$ + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIncludePatternsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIncludePatternsTest.php new file mode 100644 index 000000000..a38401b61 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIncludePatternsTest.php @@ -0,0 +1,108 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test the Ruleset::getIncludePatterns() method. + * + * @covers \PHP_CodeSniffer\Ruleset::getIncludePatterns + */ +final class GetIncludePatternsTest extends TestCase +{ + + /** + * The Ruleset object. + * + * @var \PHP_CodeSniffer\Ruleset + */ + private static $ruleset; + + + /** + * Initialize the config and ruleset objects for this test. + * + * @beforeClass + * + * @return void + */ + public static function initializeConfigAndRuleset() + { + // Set up the ruleset. + $standard = __DIR__."/GetIncludePatternsTest.xml"; + $config = new ConfigDouble(["--standard=$standard"]); + self::$ruleset = new Ruleset($config); + + }//end initializeConfigAndRuleset() + + + /** + * Test retrieving include patterns. + * + * @param string|null $listener The listener to get patterns for or null for all patterns. + * @param array> $expected The expected function output. + * + * @dataProvider dataGetIncludePatterns + * + * @return void + */ + public function testGetIncludePatterns($listener, $expected) + { + $this->assertSame($expected, self::$ruleset->getIncludePatterns($listener)); + + }//end testGetIncludePatterns() + + + /** + * Data provider. + * + * @see self::testGetIncludePatterns() + * + * @return array>|null>> + */ + public static function dataGetIncludePatterns() + { + return [ + 'All include patterns' => [ + 'listener' => null, + 'expected' => [ + 'PSR1.Classes.ClassDeclaration' => [ + './src/*/file.php' => 'absolute', + './bin/' => 'relative', + ], + 'Generic.Formatting.SpaceAfterCast' => [ + './src/*/test\\.php$' => 'absolute', + ], + ], + ], + 'Include patterns for PSR1.Classes.ClassDeclaration' => [ + 'listener' => 'PSR1.Classes.ClassDeclaration', + 'expected' => [ + './src/*/file.php' => 'absolute', + './bin/' => 'relative', + ], + ], + 'Include patterns for Generic.Formatting.SpaceAfterCast' => [ + 'listener' => 'Generic.Formatting.SpaceAfterCast', + 'expected' => ['./src/*/test\\.php$' => 'absolute'], + ], + 'Include patterns for sniff without include patterns' => [ + 'listener' => 'PSR1.Files.SideEffects', + 'expected' => [], + ], + ]; + + }//end dataGetIncludePatterns() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIncludePatternsTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIncludePatternsTest.xml new file mode 100644 index 000000000..e59c89917 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/GetIncludePatternsTest.xml @@ -0,0 +1,15 @@ + + + + + + + ./src/*/file.php + ./bin/ + + + + ./src/*/test\.php$ + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersNamingConventionsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersNamingConventionsTest.php new file mode 100644 index 000000000..d93840521 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersNamingConventionsTest.php @@ -0,0 +1,82 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test handling of sniffs not following the PHPCS naming conventions in the Ruleset::populateTokenListeners() method. + * + * @covers \PHP_CodeSniffer\Ruleset::populateTokenListeners + */ +final class PopulateTokenListenersNamingConventionsTest extends TestCase +{ + + + /** + * Verify a warning is shown for sniffs not complying with the PHPCS naming conventions. + * + * Including sniffs which do not comply with the PHPCS naming conventions is soft deprecated since + * PHPCS 3.12.0, hard deprecated since PHPCS 3.13.0 and support will be removed in PHPCS 4.0.0. + * + * @return void + */ + public function testBrokenNamingConventions() + { + // Set up the ruleset. + $standard = __DIR__.'/PopulateTokenListenersNamingConventionsTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + // The "Generic.PHP.BacktickOperator" sniff is the only valid sniff. + $expectedSniffCodes = [ + '..NoNamespace' => 'NoNamespaceSniff', + '.Sniffs.MissingCategoryDir' => 'BrokenNamingConventions\\Sniffs\\MissingCategoryDirSniff', + '.Sniffs.PartialNamespace' => 'Sniffs\\PartialNamespaceSniff', + 'BrokenNamingConventions.Category.' => 'BrokenNamingConventions\\Sniffs\\Category\\Sniff', + 'BrokenNamingConventions.Sniffs.CategoryCalledSniffs' => 'BrokenNamingConventions\\Sniffs\\Sniffs\\CategoryCalledSniffsSniff', + 'Generic.PHP.BacktickOperator' => 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\BacktickOperatorSniff', + 'Sniffs.SubDir.TooDeeplyNested' => 'BrokenNamingConventions\\Sniffs\\Category\\SubDir\\TooDeeplyNestedSniff', + ]; + + // Sort the value to make the tests stable as different OSes will read directories + // in a different order and the order is not relevant for these tests. Just the values. + $actual = $ruleset->sniffCodes; + ksort($actual); + + $this->assertSame($expectedSniffCodes, $actual, 'Registered sniffs do not match expectation'); + + $expectedMessage = 'DEPRECATED: The sniff BrokenNamingConventions\\Sniffs\\MissingCategoryDirSniff does not comply'; + $expectedMessage .= ' with the PHP_CodeSniffer naming conventions. This will no longer be supported in PHPCS 4.0.'.PHP_EOL; + $expectedMessage .= 'Contact the sniff author to fix the sniff.'.PHP_EOL; + $expectedMessage .= 'DEPRECATED: The sniff NoNamespaceSniff does not comply with the PHP_CodeSniffer naming conventions.'; + $expectedMessage .= ' This will no longer be supported in PHPCS 4.0.'.PHP_EOL; + $expectedMessage .= 'Contact the sniff author to fix the sniff.'.PHP_EOL; + $expectedMessage .= 'DEPRECATED: The sniff Sniffs\\PartialNamespaceSniff does not comply with the PHP_CodeSniffer naming conventions.'; + $expectedMessage .= ' This will no longer be supported in PHPCS 4.0.'.PHP_EOL; + $expectedMessage .= 'Contact the sniff author to fix the sniff.'.PHP_EOL; + $expectedMessage .= 'DEPRECATED: The sniff BrokenNamingConventions\\Sniffs\\Category\\Sniff does not comply'; + $expectedMessage .= ' with the PHP_CodeSniffer naming conventions. This will no longer be supported in PHPCS 4.0.'.PHP_EOL; + $expectedMessage .= 'Contact the sniff author to fix the sniff.'.PHP_EOL; + $expectedMessage .= 'DEPRECATED: The sniff BrokenNamingConventions\\Sniffs\\Sniffs\\CategoryCalledSniffsSniff does not'; + $expectedMessage .= ' comply with the PHP_CodeSniffer naming conventions. This will no longer be supported in PHPCS 4.0.'.PHP_EOL; + $expectedMessage .= 'Contact the sniff author to fix the sniff.'.PHP_EOL; + $expectedMessage .= 'DEPRECATED: The sniff BrokenNamingConventions\\Sniffs\\Category\\SubDir\\TooDeeplyNestedSniff'; + $expectedMessage .= ' does not comply with the PHP_CodeSniffer naming conventions. This will no longer be supported in PHPCS 4.0.'.PHP_EOL; + $expectedMessage .= 'Contact the sniff author to fix the sniff.'.PHP_EOL.PHP_EOL; + + $this->expectOutputString($expectedMessage); + + }//end testBrokenNamingConventions() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersNamingConventionsTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersNamingConventionsTest.xml new file mode 100644 index 000000000..58e54a92c --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersNamingConventionsTest.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersRegisterNoArrayTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersRegisterNoArrayTest.xml new file mode 100644 index 000000000..23c59c00a --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersRegisterNoArrayTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersSupportedTokenizersTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersSupportedTokenizersTest.php new file mode 100644 index 000000000..87e6da802 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersSupportedTokenizersTest.php @@ -0,0 +1,111 @@ + + * @copyright 2025 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test the Ruleset::populateTokenListeners() method shows a deprecation notice for sniffs supporting JS and/or CSS tokenizers. + * + * @covers \PHP_CodeSniffer\Ruleset::populateTokenListeners + */ +final class PopulateTokenListenersSupportedTokenizersTest extends AbstractRulesetTestCase +{ + + /** + * The Config object. + * + * @var \PHP_CodeSniffer\Config + */ + private static $config; + + + /** + * Initialize the config and ruleset objects for this test. + * + * @beforeClass + * + * @return void + */ + public static function initializeConfig() + { + // Set up the ruleset. + $standard = __DIR__.'/PopulateTokenListenersSupportedTokenizersTest.xml'; + self::$config = new ConfigDouble(["--standard=$standard"]); + + }//end initializeConfig() + + + /** + * Verify that a deprecation notice is shown if a non-deprecated sniff supports the JS/CSS tokenizer(s). + * + * Additionally, this test verifies that: + * - No deprecation notice is thrown if the complete sniff is deprecated. + * - No deprecation notice is thrown when the sniff _also_ supports PHP. + * - No deprecation notice is thrown when no tokenizers are supported (not sure why anyone would do that, but :shrug:). + * + * {@internal The test uses a data provider to verify the messages as the _order_ of the messages depends + * on the OS on which the tests are run (order in which files are retrieved), which makes the order within the + * complete message too unpredictable to test in one go.} + * + * @param string $expected The expected message output in regex format. + * + * @dataProvider dataDeprecatedTokenizersTriggerDeprecationNotice + * + * @return void + */ + public function testDeprecatedTokenizersTriggerDeprecationNotice($expected) + { + $this->expectOutputRegex($expected); + + new Ruleset(self::$config); + + }//end testDeprecatedTokenizersTriggerDeprecationNotice() + + + /** + * Data provider. + * + * @see testDeprecatedTokenizersTriggerDeprecationNotice() + * + * @return array> + */ + public static function dataDeprecatedTokenizersTriggerDeprecationNotice() + { + $cssJsDeprecated = '`DEPRECATED: Scanning CSS/JS files is deprecated and support will be removed in PHP_CodeSniffer 4\.0\.\R'; + $cssJsDeprecated .= 'The %1$s sniff is listening for %2$s\.\R`'; + + $customTokenizer = '`DEPRECATED: Support for custom tokenizers will be removed in PHP_CodeSniffer 4\.0\.\R'; + $customTokenizer .= 'The %1$s sniff is listening for %2$s\.\R`'; + + return [ + 'Listens for CSS' => [ + 'expected' => sprintf($cssJsDeprecated, 'TestStandard.SupportedTokenizers.ListensForCSS', 'CSS'), + ], + 'Listens for JS' => [ + 'expected' => sprintf($cssJsDeprecated, 'TestStandard.SupportedTokenizers.ListensForJS', 'JS'), + ], + 'Listens for both CSS and JS' => [ + 'expected' => sprintf($cssJsDeprecated, 'TestStandard.SupportedTokenizers.ListensForCSSAndJS', 'CSS, JS'), + ], + 'Listens for CSS and something unrecognized' => [ + 'expected' => sprintf($cssJsDeprecated, 'TestStandard.SupportedTokenizers.ListensForCSSAndUnrecognized', 'CSS, Unrecognized'), + ], + 'Listens for only unrecognized tokenizers' => [ + 'expected' => sprintf($customTokenizer, 'TestStandard.SupportedTokenizers.ListensForUnrecognizedTokenizers', 'SCSS, TypeScript'), + ], + ]; + + }//end dataDeprecatedTokenizersTriggerDeprecationNotice() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersSupportedTokenizersTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersSupportedTokenizersTest.xml new file mode 100644 index 000000000..377cb2f6a --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersSupportedTokenizersTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersTest.php new file mode 100644 index 000000000..347ffddee --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersTest.php @@ -0,0 +1,553 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; +use PHP_CodeSniffer\Util\Tokens; +use ReflectionObject; +use ReflectionProperty; + +/** + * Test the Ruleset::populateTokenListeners() method. + * + * @covers \PHP_CodeSniffer\Ruleset::populateTokenListeners + */ +final class PopulateTokenListenersTest extends AbstractRulesetTestCase +{ + + /** + * The Ruleset object. + * + * @var \PHP_CodeSniffer\Ruleset + */ + private static $ruleset; + + + /** + * Initialize the config and ruleset objects for this test only once (but do allow recording code coverage). + * + * @before + * + * @return void + */ + protected function initializeConfigAndRuleset() + { + if (isset(self::$ruleset) === false) { + // Set up the ruleset. + $standard = __DIR__.'/PopulateTokenListenersTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + self::$ruleset = new Ruleset($config); + } + + }//end initializeConfigAndRuleset() + + + /** + * Test an exception is thrown when the register() method of a sniff doesn't return an array. + * + * @return void + */ + public function testSniffWhereRegisterDoesNotReturnAnArrayThrowsException() + { + $standard = __DIR__.'/PopulateTokenListenersRegisterNoArrayTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $sniffClass = 'Fixtures\\TestStandard\\Sniffs\\InvalidSniffs\\RegisterNoArraySniff'; + $message = "ERROR: The sniff {$sniffClass}::register() method must return an array.".PHP_EOL.PHP_EOL; + $this->expectRuntimeExceptionMessage($message); + + new Ruleset($config); + + // Verify that the sniff has not been registered/has been unregistered. + // These assertions will only take effect for PHPUnit 10+. + $this->assertArrayNotHasKey($sniffClass, self::$ruleset->sniffs, "Sniff class $sniffClass is listed in registered sniffs"); + $this->assertArrayNotHasKey('TestStandard.InvalidSniffs.RegisterNoArray', self::$ruleset->sniffCodes, 'Sniff code is registered'); + + }//end testSniffWhereRegisterDoesNotReturnAnArrayThrowsException() + + + /** + * Test that a sniff not registering any tokens is not listed as a listener. + * + * @return void + */ + public function testSniffWithRegisterMethodReturningEmptyArrayIsSilentlyIgnored() + { + $target = 'Fixtures\\TestStandard\\Sniffs\\ValidSniffs\\RegisterEmptyArraySniff'; + + foreach (self::$ruleset->tokenListeners as $token => $listeners) { + $this->assertTrue(is_array($listeners), 'No listeners registered for token'.Tokens::tokenName($token)); + $this->assertArrayNotHasKey( + $target, + $listeners, + sprintf('Found the %s sniff registered for token %s', $target, Tokens::tokenName($token)) + ); + } + + }//end testSniffWithRegisterMethodReturningEmptyArrayIsSilentlyIgnored() + + + /** + * Tests that sniffs registering tokens, will end up listening to these tokens. + * + * @param string $sniffClass The FQN for the sniff class to check. + * @param int $expectedCount Expected number of tokens to which the sniff should be listening. + * + * @dataProvider dataSniffListensToTokenss + * + * @return void + */ + public function testRegistersSniffsToListenToTokens($sniffClass, $expectedCount) + { + $counter = 0; + + foreach (self::$ruleset->tokenListeners as $listeners) { + if (isset($listeners[$sniffClass]) === true) { + ++$counter; + } + } + + $this->assertSame($expectedCount, $counter); + + }//end testRegistersSniffsToListenToTokens() + + + /** + * Data provider. + * + * @see testSniffListensToTokens() + * + * @return array> + */ + public static function dataSniffListensToTokenss() + { + return [ + 'TestStandard.SupportedTokenizers.ListensForPHPAndCSSAndJS' => [ + 'sniffClass' => 'Fixtures\\TestStandard\\Sniffs\\SupportedTokenizers\\ListensForPHPAndCSSAndJSSniff', + 'expectedCount' => 2, + ], + 'Generic.NamingConventions.UpperCaseConstantName' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff', + 'expectedCount' => 2, + ], + 'PSR1.Files.SideEffects' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Files\\SideEffectsSniff', + 'expectedCount' => 1, + ], + 'PSR12.ControlStructures.BooleanOperatorPlacement' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\PSR12\\Sniffs\\ControlStructures\\BooleanOperatorPlacementSniff', + 'expectedCount' => 5, + ], + 'Squiz.ControlStructures.ForEachLoopDeclaration' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\Squiz\\Sniffs\\ControlStructures\\ForEachLoopDeclarationSniff', + 'expectedCount' => 1, + ], + 'TestStandard.Deprecated.WithReplacement' => [ + 'sniffClass' => 'Fixtures\\TestStandard\\Sniffs\\Deprecated\\WithReplacementSniff', + 'expectedCount' => 1, + ], + 'TestStandard.ValidSniffs.RegisterEmptyArray' => [ + 'sniffClass' => 'Fixtures\\TestStandard\\Sniffs\\ValidSniffs\\RegisterEmptyArraySniff', + 'expectedCount' => 0, + ], + ]; + + }//end dataSniffListensToTokenss() + + + /** + * Test that deprecated sniffs get recognized and added to the $deprecatedSniffs list. + * + * @return void + */ + public function testRegistersWhenADeprecatedSniffIsLoaded() + { + $property = new ReflectionProperty(self::$ruleset, 'deprecatedSniffs'); + $property->setAccessible(true); + $actualValue = $property->getValue(self::$ruleset); + $property->setAccessible(false); + + // Only verify there is one deprecated sniff registered. + // There are other tests which test the deprecated sniff handling in more detail. + $this->assertTrue(is_array($actualValue)); + $this->assertCount(1, $actualValue); + + }//end testRegistersWhenADeprecatedSniffIsLoaded() + + + /** + * Verify that the setting of properties on a sniff was not triggered when there are no properties being set. + * + * @return void + */ + public function testDoesntTriggerPropertySettingForNoProperties() + { + $sniffClass = 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff'; + + // Verify that our target sniff has been registered. + $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs, "Sniff class $sniffClass not listed in registered sniffs"); + + $sniffObject = self::$ruleset->sniffs[$sniffClass]; + $reflection = new ReflectionObject($sniffObject); + + // Just making sure there are no properties on the sniff object (which doesn't have declared properties). + $this->assertSame([], $reflection->getProperties(), "Unexpected properties found on sniff class $sniffClass"); + + }//end testDoesntTriggerPropertySettingForNoProperties() + + + /** + * Verify that the setting of properties on a sniff was triggered. + * + * @param string $sniffClass The FQN for the sniff class on which the property should be set. + * @param string $propertyName The property name. + * @param string $expected The expected property value. + * + * @dataProvider dataTriggersPropertySettingWhenPropertiesProvided + * + * @return void + */ + public function testTriggersPropertySettingWhenPropertiesProvided($sniffClass, $propertyName, $expected) + { + // Verify that our target sniff has been registered. + $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs, "Sniff class $sniffClass not listed in registered sniffs"); + + $sniffObject = self::$ruleset->sniffs[$sniffClass]; + + // Verify the property has been set. + $this->assertSame($expected, $sniffObject->$propertyName, "Property on sniff class $sniffClass set to unexpected value"); + + }//end testTriggersPropertySettingWhenPropertiesProvided() + + + /** + * Data provider. + * + * @see testTriggersPropertySettingWhenPropertiesProvided() + * + * @return array> + */ + public static function dataTriggersPropertySettingWhenPropertiesProvided() + { + return [ + 'Sniff with single property being set' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\PSR12\\Sniffs\\ControlStructures\\BooleanOperatorPlacementSniff', + 'propertyName' => 'allowOnly', + 'expected' => 'first', + ], + 'Sniff with multiple properties being set - first property' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\Squiz\\Sniffs\\ControlStructures\\ForEachLoopDeclarationSniff', + 'propertyName' => 'requiredSpacesAfterOpen', + 'expected' => '3', + ], + 'Sniff with multiple properties being set - second property' => [ + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\Squiz\\Sniffs\\ControlStructures\\ForEachLoopDeclarationSniff', + 'propertyName' => 'requiredSpacesBeforeClose', + 'expected' => '8', + ], + ]; + + }//end dataTriggersPropertySettingWhenPropertiesProvided() + + + /** + * Verifies that the "class" and "source" indexes get set. + * + * @return void + */ + public function testSetsClassAndSourceIndexes() + { + foreach (self::$ruleset->tokenListeners as $token => $listeners) { + $this->assertTrue(is_array($listeners), 'No listeners registered for token'.Tokens::tokenName($token)); + + foreach ($listeners as $className => $details) { + $this->assertArrayHasKey( + 'class', + $details, + sprintf('"tokenizers" key missing for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + + $this->assertSame( + $className, + $details['class'], + sprintf('Unexpected value for "class" key for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + + $this->assertArrayHasKey( + 'source', + $details, + sprintf('"source" key missing for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + + $this->assertTrue( + is_string($details['source']), + sprintf('Value for "source" key is not a string for token %s', Tokens::tokenName($token)) + ); + + $expected = '.'.substr($className, (strrpos($className, '\\') + 1), -5); + + $this->assertStringEndsWith( + $expected, + $details['source'], + sprintf('Unexpected value for "source" key for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + }//end foreach + }//end foreach + + }//end testSetsClassAndSourceIndexes() + + + /** + * Verifies that sniffs by default are listening for PHP files only. + * + * @return void + */ + public function testSetsSupportedTokenizersToPHPByDefault() + { + $exclude = 'Fixtures\\TestStandard\\Sniffs\\SupportedTokenizers\\ListensForPHPAndCSSAndJSSniff'; + $expected = ['PHP' => 'PHP']; + + foreach (self::$ruleset->tokenListeners as $token => $listeners) { + $this->assertTrue(is_array($listeners), 'No listeners registered for token'.Tokens::tokenName($token)); + + foreach ($listeners as $className => $details) { + if ($className === $exclude) { + // Skip this one as it is the one sniff for which things will be different. + continue; + } + + $this->assertArrayHasKey( + 'tokenizers', + $details, + sprintf('"tokenizers" key missing for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + + $this->assertSame( + $expected, + $details['tokenizers'], + sprintf('Unexpected value for "tokenizers" key for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + } + }//end foreach + + }//end testSetsSupportedTokenizersToPHPByDefault() + + + /** + * Test that if a sniff has the $supportedTokenizers property set, the tokenizers listed there + * will be registered in the listeners array. + * + * @param int $token The token constant for which the sniff should be registered. + * + * @dataProvider dataSetsSupportedTokenizersWhenProvidedBySniff + * + * @return void + */ + public function testSetsSupportedTokenizersWhenProvidedBySniff($token) + { + $sniffClass = 'Fixtures\\TestStandard\\Sniffs\\SupportedTokenizers\\ListensForPHPAndCSSAndJSSniff'; + $expected = [ + 'PHP' => 'PHP', + 'JS' => 'JS', + 'CSS' => 'CSS', + ]; + + $this->assertArrayHasKey( + $token, + self::$ruleset->tokenListeners, + sprintf('The token constant %s is not registered to the listeners array', Tokens::tokenName($token)) + ); + $this->assertArrayHasKey( + $sniffClass, + self::$ruleset->tokenListeners[$token], + sprintf('The sniff class %s is not registered for token %s', $sniffClass, Tokens::tokenName($token)) + ); + $this->assertArrayHasKey( + 'tokenizers', + self::$ruleset->tokenListeners[$token][$sniffClass], + sprintf('"tokenizers" key missing for sniff class %s for token %s', $sniffClass, Tokens::tokenName($token)) + ); + + $this->assertSame( + $expected, + self::$ruleset->tokenListeners[$token][$sniffClass]['tokenizers'], + sprintf('Unexpected value for "tokenizers" key for sniff class %s for token %s', $sniffClass, Tokens::tokenName($token)) + ); + + }//end testSetsSupportedTokenizersWhenProvidedBySniff() + + + /** + * Data provider. + * + * @see testSetsSupportedTokenizersWhenProvidedBySniff() + * + * @return array> + */ + public static function dataSetsSupportedTokenizersWhenProvidedBySniff() + { + return [ + 'T_OPEN_TAG' => [T_OPEN_TAG], + 'T_OPEN_TAG_WITH_ECHO' => [T_OPEN_TAG_WITH_ECHO], + ]; + + }//end dataSetsSupportedTokenizersWhenProvidedBySniff() + + + /** + * Verifies that by default no explicit include patterns are registered for sniffs. + * + * @return void + */ + public function testSetsIncludePatternsToEmptyArrayByDefault() + { + $exclude = 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff'; + + foreach (self::$ruleset->tokenListeners as $token => $listeners) { + $this->assertTrue(is_array($listeners), 'No listeners registered for token'.Tokens::tokenName($token)); + + foreach ($listeners as $className => $details) { + if ($className === $exclude) { + // Skip this one as it is the one sniff for which things will be different. + continue; + } + + $this->assertArrayHasKey( + 'include', + $details, + sprintf('"include" key missing for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + + $this->assertSame( + [], + $details['include'], + sprintf('Unexpected value for "include" key for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + } + }//end foreach + + }//end testSetsIncludePatternsToEmptyArrayByDefault() + + + /** + * Verifies that by default no explicit ignore patterns are registered for sniffs. + * + * @return void + */ + public function testSetsIgnorePatternsToEmptyArrayByDefault() + { + $exclude = 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Files\\SideEffectsSniff'; + + foreach (self::$ruleset->tokenListeners as $token => $listeners) { + $this->assertTrue(is_array($listeners), 'No listeners registered for token'.Tokens::tokenName($token)); + + foreach ($listeners as $className => $details) { + if ($className === $exclude) { + // Skip this one as it is the one sniff for which things will be different. + continue; + } + + $this->assertArrayHasKey( + 'ignore', + $details, + sprintf('"ignore" key missing for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + + $this->assertSame( + [], + $details['ignore'], + sprintf('Unexpected value for "ignore" key for sniff class %s for token %s', $className, Tokens::tokenName($token)) + ); + } + }//end foreach + + }//end testSetsIgnorePatternsToEmptyArrayByDefault() + + + /** + * Tests that if there are <[include|exclude]-pattern> directives set on a sniff, these are set for the relevant listeners. + * + * Includes verification that the transformation of "regex"-like patterns is handled correctly. + * + * @param int|string $token A token constant on which the sniff should be registered. + * @param string $sniffClass The FQN for the sniff class on which the patterns should be registered. + * @param string $patternType The type of patterns expected to be registered for the sniff. + * + * @dataProvider dataSetsIncludeAndIgnorePatterns + * + * @return void + */ + public function testSetsIncludeAndIgnorePatterns($token, $sniffClass, $patternType) + { + $expected = [ + '/no-transformation/', + '/simple.*transformation/.*', + '/escaped\\,comma/becomes/comma/to/allow/commas/in/filenames.css', + '/pat?tern(is|regex)\\.php$', + ]; + + $this->assertArrayHasKey( + $token, + self::$ruleset->tokenListeners, + sprintf('The token constant %s is not registered to the listeners array', Tokens::tokenName($token)) + ); + $this->assertArrayHasKey( + $sniffClass, + self::$ruleset->tokenListeners[$token], + sprintf('The sniff class %s is not registered for token %s', $sniffClass, Tokens::tokenName($token)) + ); + $this->assertArrayHasKey( + $patternType, + self::$ruleset->tokenListeners[$token][$sniffClass], + sprintf('"%s" key missing for sniff class %s for token %s', $patternType, $sniffClass, Tokens::tokenName($token)) + ); + + $this->assertSame( + $expected, + self::$ruleset->tokenListeners[$token][$sniffClass][$patternType], + sprintf('Unexpected value for "%s" key for sniff class %s for token %s', $patternType, $sniffClass, Tokens::tokenName($token)) + ); + + }//end testSetsIncludeAndIgnorePatterns() + + + /** + * Data provider. + * + * @see testSetsIncludeAndIgnorePatterns() + * + * @return array> + */ + public static function dataSetsIncludeAndIgnorePatterns() + { + return [ + 'Sniff with s in the ruleset - first token' => [ + 'token' => T_STRING, + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff', + 'patternType' => 'include', + ], + 'Sniff with s in the ruleset - second token' => [ + 'token' => T_CONST, + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff', + 'patternType' => 'include', + ], + 'Sniff with s in the ruleset' => [ + 'token' => T_OPEN_TAG, + 'sniffClass' => 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Files\\SideEffectsSniff', + 'patternType' => 'ignore', + ], + ]; + + }//end dataSetsIncludeAndIgnorePatterns() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersTest.xml new file mode 100644 index 000000000..1b6ed1a48 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PopulateTokenListenersTest.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /no-transformation/ + /simple*transformation/* + /escaped\\,comma/becomes/comma/to/allow/commas/in/filenames.css + /pat?tern(is|regex)\.php$ + + + + + /no-transformation/ + /simple*transformation/* + /escaped\\,comma/becomes/comma/to/allow/commas/in/filenames.css + /pat?tern(is|regex)\.php$ + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleInvalidTypeTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleInvalidTypeTest.php new file mode 100644 index 000000000..d43958c77 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleInvalidTypeTest.php @@ -0,0 +1,43 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test handling of invalid type elements. + * + * @covers \PHP_CodeSniffer\Ruleset::processRule + */ +final class ProcessRuleInvalidTypeTest extends AbstractRulesetTestCase +{ + + + /** + * Test displaying an error when an invalid type is given. + * + * @return void + */ + public function testInvalidTypeHandling() + { + $standard = __DIR__.'/ProcessRuleInvalidTypeTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $message = 'ERROR: Message type "notice" for "Generic.Files.ByteOrderMark" is invalid; must be "error" or "warning".'.PHP_EOL.PHP_EOL; + $this->expectRuntimeExceptionMessage($message); + + new Ruleset($config); + + }//end testInvalidTypeHandling() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleInvalidTypeTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleInvalidTypeTest.xml new file mode 100644 index 000000000..4883e9102 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleInvalidTypeTest.xml @@ -0,0 +1,9 @@ + + + + + + notice + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleShouldProcessElementTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleShouldProcessElementTest.php new file mode 100644 index 000000000..c6c9e2160 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleShouldProcessElementTest.php @@ -0,0 +1,666 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test handling of `phpc(cs|cbf)-only` instructions at rule level. + * + * @covers \PHP_CodeSniffer\Ruleset::processRule + * @covers \PHP_CodeSniffer\Ruleset::shouldProcessElement + */ +final class ProcessRuleShouldProcessElementTest extends AbstractRulesetTestCase +{ + + /** + * The Ruleset object. + * + * @var \PHP_CodeSniffer\Ruleset + */ + private static $ruleset; + + + /** + * Initialize the config and ruleset objects for this test. + * + * @before + * + * @return void + */ + protected function initializeConfigAndRuleset() + { + if (isset(self::$ruleset) === false) { + // Set up the ruleset. + $standard = __DIR__.'/ProcessRuleShouldProcessElementTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + self::$ruleset = new Ruleset($config); + } + + }//end initializeConfigAndRuleset() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessSeverityCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $key = 'severity'; + + // Verify that the non-selective severity directive IS applied. + $sniffCode = 'Internal.NoCodeFound'; + $this->assertRulesetPropertySame(0, $sniffCode, $key); + + $sniffCode = 'PSR1.Files.SideEffects'; + $this->assertRulesetPropertySame(3, $sniffCode, $key); + + // Verify that the CS-only severity directive IS applied. + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertRulesetPropertySame(2, $sniffCode, $key); + + // Verify that the CBF-only severity directive is NOT applied. + $sniffCode = 'PSR2.Namespaces.NamespaceDeclaration'; + $this->assertNotHasRulesetDirective($sniffCode, $key); + + }//end testShouldProcessSeverityCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessSeverityCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $key = 'severity'; + + // Verify that the non-selective severity directive IS applied. + $sniffCode = 'PSR1.Files.SideEffects'; + $this->assertRulesetPropertySame(3, $sniffCode, $key); + + // Verify that the CS-only severity directive is NOT applied. + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertNotHasRulesetDirective($sniffCode, $key); + + // Verify that the CBF-only severity directive IS applied. + $sniffCode = 'PSR2.Namespaces.NamespaceDeclaration'; + $this->assertRulesetPropertySame(4, $sniffCode, $key); + + }//end testShouldProcessSeverityCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessTypeCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $key = 'type'; + + // Verify that the non-selective type directive IS applied. + $sniffCode = 'PSR1.Files.SideEffects'; + $this->assertRulesetPropertySame('warning', $sniffCode, $key); + + // Verify that the CS-only type directive IS applied. + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertRulesetPropertySame('warning', $sniffCode, $key); + + // Verify that the CBF-only type directive is NOT applied. + $sniffCode = 'PSR2.Namespaces.NamespaceDeclaration'; + $this->assertNotHasRulesetDirective($sniffCode, $key); + + }//end testShouldProcessTypeCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessTypeCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $key = 'type'; + + // Verify that the non-selective type directive IS applied. + $sniffCode = 'PSR1.Files.SideEffects'; + $this->assertRulesetPropertySame('warning', $sniffCode, $key); + + // Verify that the CS-only type directive is NOT applied. + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertNotHasRulesetDirective($sniffCode, $key); + + // Verify that the CBF-only type directive IS applied. + $sniffCode = 'PSR2.Namespaces.NamespaceDeclaration'; + $this->assertRulesetPropertySame('error', $sniffCode, $key); + + }//end testShouldProcessTypeCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessMessageCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $key = 'message'; + + // Verify that the non-selective message directive IS applied. + $sniffCode = 'PSR1.Files.SideEffects'; + $this->assertRulesetPropertySame('A different warning message', $sniffCode, $key); + + // Verify that the CS-only message directive IS applied. + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertRulesetPropertySame('A different warning but only for phpcs', $sniffCode, $key); + + // Verify that the CBF-only message directive is NOT applied. + $sniffCode = 'PSR2.Namespaces.NamespaceDeclaration'; + $this->assertNotHasRulesetDirective($sniffCode, $key); + + }//end testShouldProcessMessageCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessMessageCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $key = 'message'; + + // Verify that the non-selective message directive IS applied. + $sniffCode = 'Internal.NoCodeFound'; + $this->assertRulesetPropertySame("We don't to be notified if files don't contain code", $sniffCode, $key); + + $sniffCode = 'PSR1.Files.SideEffects'; + $this->assertRulesetPropertySame('A different warning message', $sniffCode, $key); + + // Verify that the CS-only message directive is NOT applied. + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertNotHasRulesetDirective($sniffCode, $key); + + // Verify that the CBF-only message directive IS applied. + $sniffCode = 'PSR2.Namespaces.NamespaceDeclaration'; + $this->assertRulesetPropertySame('A different warning but only for phpcbf', $sniffCode, $key); + + }//end testShouldProcessMessageCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessIncludePatternCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $includedKey = './vendor/'; + + // Verify that the non-selective include-pattern directive IS applied. + $sniffCode = 'PSR1.Methods.CamelCapsMethodName'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->includePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($includedKey, self::$ruleset->includePatterns[$sniffCode], "Include pattern for sniff $sniffCode not registered"); + + // Verify that the CS-only include-pattern directive IS applied. + $sniffCode = 'Generic.Files.LineLength'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->includePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($includedKey, self::$ruleset->includePatterns[$sniffCode], "Include pattern for sniff $sniffCode not registered"); + + // Verify that the CBF-only include-pattern directive is NOT applied. + $sniffCode = 'PSR2.Files.ClosingTag'; + $this->assertArrayNotHasKey($sniffCode, self::$ruleset->includePatterns, "Sniff $sniffCode was registered"); + + }//end testShouldProcessIncludePatternCsonly() + + + /** + * Verify that in CS mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessIncludePatternCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $includedKey = './vendor/'; + + // Verify that the non-selective include-pattern directive IS applied. + $sniffCode = 'PSR1.Methods.CamelCapsMethodName'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->includePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($includedKey, self::$ruleset->includePatterns[$sniffCode], "Include pattern for sniff $sniffCode not registered"); + + // Verify that the CS-only include-pattern directive is NOT applied. + $sniffCode = 'Generic.Files.LineLength'; + $this->assertArrayNotHasKey($sniffCode, self::$ruleset->includePatterns, "Sniff $sniffCode was registered"); + + // Verify that the CBF-only include-pattern directive is IS applied. + $sniffCode = 'PSR2.Files.ClosingTag'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->includePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($includedKey, self::$ruleset->includePatterns[$sniffCode], "Include pattern for sniff $sniffCode not registered"); + + }//end testShouldProcessIncludePatternCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessExcludePatternCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $excludedKey = './tests/'; + + // Verify that the non-selective exclude-pattern directive IS applied. + $sniffCode = 'PSR1.Classes.ClassDeclaration'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->ignorePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($excludedKey, self::$ruleset->ignorePatterns[$sniffCode], "Ignore pattern for sniff $sniffCode not registered"); + + // Verify that the CS-only exclude-pattern directive IS applied. + $sniffCode = 'Generic.Formatting.SpaceAfterCast'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->ignorePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($excludedKey, self::$ruleset->ignorePatterns[$sniffCode], "Ignore pattern for sniff $sniffCode not registered"); + + // Verify that the CBF-only exclude-pattern directive is NOT applied. + $sniffCode = 'PSR2.Methods.FunctionClosingBrace'; + $this->assertArrayNotHasKey($sniffCode, self::$ruleset->ignorePatterns, "Sniff $sniffCode was registered"); + + }//end testShouldProcessExcludePatternCsonly() + + + /** + * Verify that in CS mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessExcludePatternCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $excludedKey = './tests/'; + + // Verify that the non-selective exclude-pattern directive IS applied. + $sniffCode = 'PSR1.Classes.ClassDeclaration'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->ignorePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($excludedKey, self::$ruleset->ignorePatterns[$sniffCode], "Ignore pattern for sniff $sniffCode not registered"); + + // Verify that the CS-only exclude-pattern directive is NOT applied. + $sniffCode = 'Generic.Formatting.SpaceAfterCast'; + $this->assertArrayNotHasKey($sniffCode, self::$ruleset->ignorePatterns, "Sniff $sniffCode was registered"); + + // Verify that the CBF-only exclude-pattern directive is IS applied. + $sniffCode = 'PSR2.Methods.FunctionClosingBrace'; + $this->assertArrayHasKey($sniffCode, self::$ruleset->ignorePatterns, "Sniff $sniffCode not registered"); + $this->assertArrayHasKey($excludedKey, self::$ruleset->ignorePatterns[$sniffCode], "Ignore pattern for sniff $sniffCode not registered"); + + }//end testShouldProcessExcludePatternCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessPropertiesCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $csSniffClass = 'PHP_CodeSniffer\Standards\Generic\Sniffs\Arrays\ArrayIndentSniff'; + $cbfSniffClass = 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Classes\ClassDeclarationSniff'; + + $propertyName = 'indent'; + $propertyDefault = 4; + $propertyChanged = '2'; + + // Verify that the CS-only property directive IS applied. + $this->assertArrayHasKey($csSniffClass, self::$ruleset->sniffs, "Sniff $csSniffClass not registered"); + $this->assertXObjectHasProperty($propertyName, self::$ruleset->sniffs[$csSniffClass]); + + $actualValue = self::$ruleset->sniffs[$csSniffClass]->$propertyName; + $this->assertSame($propertyChanged, $actualValue, 'cs-only property change directive not applied'); + + // Verify that the CBF-only property directive is NOT applied. + $this->assertArrayHasKey($cbfSniffClass, self::$ruleset->sniffs, "Sniff $cbfSniffClass not registered"); + $this->assertXObjectHasProperty($propertyName, self::$ruleset->sniffs[$cbfSniffClass]); + + $actualValue = self::$ruleset->sniffs[$cbfSniffClass]->$propertyName; + $this->assertSame($propertyDefault, $actualValue, 'cbf-only property change directive was applied'); + + }//end testShouldProcessPropertiesCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessPropertiesCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $csSniffClass = 'PHP_CodeSniffer\Standards\Generic\Sniffs\Arrays\ArrayIndentSniff'; + $cbfSniffClass = 'PHP_CodeSniffer\Standards\PSR2\Sniffs\Classes\ClassDeclarationSniff'; + + $propertyName = 'indent'; + $propertyDefault = 4; + $propertyChanged = '2'; + + // Verify that the CS-only property directive is NOT applied. + $this->assertArrayHasKey($csSniffClass, self::$ruleset->sniffs, "Sniff $csSniffClass not registered"); + $this->assertXObjectHasProperty($propertyName, self::$ruleset->sniffs[$csSniffClass]); + + $actualValue = self::$ruleset->sniffs[$csSniffClass]->$propertyName; + $this->assertSame($propertyDefault, $actualValue, 'cs-only property change directive was applied'); + + // Verify that the CBF-only property directive IS applied. + $this->assertArrayHasKey($cbfSniffClass, self::$ruleset->sniffs, "Sniff $cbfSniffClass not registered"); + $this->assertXObjectHasProperty($propertyName, self::$ruleset->sniffs[$cbfSniffClass]); + + $actualValue = self::$ruleset->sniffs[$cbfSniffClass]->$propertyName; + $this->assertSame($propertyChanged, $actualValue, 'cbf-only property change directive not applied'); + + }//end testShouldProcessPropertiesCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessPropertyCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + // Verify the sniff is registed. + $sniffClass = 'PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace\ScopeIndentSniff'; + $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs, "Sniff $sniffClass not registered"); + + $sniffObject = self::$ruleset->sniffs[$sniffClass]; + + // Verify that the non-selective property directive IS applied. + $propertyName = 'exact'; + $expected = true; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + $this->assertSame($expected, $sniffObject->$propertyName, 'Non-selective property change directive not applied'); + + // Verify that the CS-only property directive IS applied. + $propertyName = 'indent'; + $expected = '2'; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + $this->assertSame($expected, $sniffObject->$propertyName, 'cs-only property change directive not applied'); + + // Verify that the CBF-only property directive is NOT applied. + $propertyName = 'tabIndent'; + $expectedDefault = false; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + $this->assertSame($expectedDefault, $sniffObject->$propertyName, 'cbf-only property change directive was applied'); + + }//end testShouldProcessPropertyCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessPropertyCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + // Verify the sniff is registed. + $sniffClass = 'PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace\ScopeIndentSniff'; + $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs, "Sniff $sniffClass not registered"); + + $sniffObject = self::$ruleset->sniffs[$sniffClass]; + + // Verify that the non-selective property directive IS applied. + $propertyName = 'exact'; + $expected = true; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + $this->assertSame($expected, $sniffObject->$propertyName, 'Non-selective property change directive not applied'); + + // Verify that the CS-only property directive is NOT applied. + $propertyName = 'indent'; + $expectedDefault = 4; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + $this->assertSame($expectedDefault, $sniffObject->$propertyName, 'cs-only property change directive was applied'); + + // Verify that the CBF-only property directive IS applied. + $propertyName = 'tabIndent'; + $expected = true; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + $this->assertSame($expected, $sniffObject->$propertyName, 'cbf-only property change directive not applied'); + + }//end testShouldProcessPropertyCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are set and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessElementCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $expected = [ + // Non-selective element directive. + 'T_COMMENT', + // Phpcs-only element directive. + 'T_CLASS', + // Non-selective element directive via `extend`. + 'T_BACKTICK', + // Phpcs-only element directive via `extend`. + 'T_INTERFACE', + ]; + + $this->verifyShouldProcessElement($expected); + + }//end testShouldProcessElementCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are set and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessElementCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $expected = [ + // Non-selective element directive. + 'T_COMMENT', + // Phpcbf-only element directive. + 'T_ENUM', + // Non-selective element directive via `extend`. + 'T_BACKTICK', + // Phpcbf-only element directive via `extend`. + 'T_TRAIT', + ]; + + $this->verifyShouldProcessElement($expected); + + }//end testShouldProcessElementCbfonly() + + + /** + * Verify that directives are set correctly. + * + * @param array $expected Expected sniff property value. + * + * @return void + */ + private function verifyShouldProcessElement($expected) + { + // Verify the sniff is registed. + $sniffClass = 'PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace\ScopeIndentSniff'; + $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs, "Sniff $sniffClass not registered"); + + // Verify the target property exists. + $sniffObject = self::$ruleset->sniffs[$sniffClass]; + $propertyName = 'ignoreIndentationTokens'; + + $this->assertXObjectHasProperty($propertyName, $sniffObject); + + // Verify the value. + $actualValue = $sniffObject->$propertyName; + $this->assertSame($expected, $actualValue, 'Selective element directives not applied correctly'); + + }//end verifyShouldProcessElement() + + + /** + * Custom assertion to verify that a Ruleset `$ruleset` property has a certain directive set for a certain sniff code. + * + * @param string $sniffCode Sniff code. + * @param string $key Array key. + * + * @return void + */ + private function assertHasRulesetDirective($sniffCode, $key) + { + $this->assertArrayHasKey($sniffCode, self::$ruleset->ruleset, "Sniff $sniffCode not registered"); + $this->assertTrue(is_array(self::$ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array"); + $this->assertArrayHasKey($key, self::$ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode"); + + }//end assertHasRulesetDirective() + + + /** + * Custom assertion to verify that a Ruleset `$ruleset` property does NOT have a certain directive set for a certain sniff code. + * + * @param string $sniffCode Sniff code. + * @param string $key Array key. + * + * @return void + */ + private function assertNotHasRulesetDirective($sniffCode, $key) + { + if (isset(self::$ruleset->ruleset[$sniffCode]) === true + && is_array(self::$ruleset->ruleset[$sniffCode]) === true + && isset(self::$ruleset->ruleset[$sniffCode][$key]) === true + ) { + $this->fail("Directive $key is registered for sniff $sniffCode"); + } + + }//end assertNotHasRulesetDirective() + + + /** + * Custom assertion to verify that the value of a certain directive for a certain sniff code on the ruleset is correct. + * + * @param mixed $expected Expected value. + * @param string $sniffCode Sniff code. + * @param string $key Array key. + * + * @return void + */ + private function assertRulesetPropertySame($expected, $sniffCode, $key) + { + $this->assertHasRulesetDirective($sniffCode, $key); + + $actual = self::$ruleset->ruleset[$sniffCode][$key]; + $this->assertSame($expected, $actual, "Value for $key on sniff $sniffCode does not meet expectations"); + + }//end assertRulesetPropertySame() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleShouldProcessElementTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleShouldProcessElementTest.xml new file mode 100644 index 000000000..a8a6f4d7e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRuleShouldProcessElementTest.xml @@ -0,0 +1,105 @@ + + + + + + 0 + We don't to be notified if files don't contain code + + + + 3 + warning + A different warning message + + + + ./vendor/ + + + + ./tests/ + + + + + + + 2 + warning + A different warning but only for phpcs + + + + ./vendor/ + + + + ./tests/ + + + + + + + + + + + 4 + error + A different warning but only for phpcbf + + + + ./vendor/ + + + + ./tests/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoExpandSniffsDirectoryTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoExpandSniffsDirectoryTest.xml new file mode 100644 index 000000000..5290782d1 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoExpandSniffsDirectoryTest.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadFileNotFoundTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadFileNotFoundTest.xml new file mode 100644 index 000000000..6df4c63fa --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadFileNotFoundTest.xml @@ -0,0 +1,8 @@ + + + + ./tests/Core/Ruleset/Fixtures/ThisFileDoesNotExist.php + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadTest.php new file mode 100644 index 000000000..1f6e289e6 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadTest.php @@ -0,0 +1,164 @@ + instructions. + * + * @author Juliette Reinders Folmer + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test handling of instructions. + * + * Note: these tests need to run in separate processes as otherwise we cannot + * reliably determine whether or not the correct files were loaded as the + * underlying code uses `include_once`. + * + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + * + * @covers \PHP_CodeSniffer\Ruleset::processRuleset + */ +final class ProcessRulesetAutoloadTest extends AbstractRulesetTestCase +{ + + + /** + * Verify that in CS mode, phpcs-only directives are respected and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessAutoloadCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $originallyIncludes = get_included_files(); + + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetAutoloadTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + new Ruleset($config); + + $finalIncludes = get_included_files(); + $diff = array_diff($finalIncludes, $originallyIncludes); + + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.1.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.1.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.2.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.2.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.3.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.3.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.4.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.4.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadPhpcsOnly.php'), + $diff, + 'ProcessRulesetAutoloadLoadPhpcsOnly.php autoload file was not loaded' + ); + $this->assertNotContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadPhpcbfOnly.php'), + $diff, + 'ProcessRulesetAutoloadLoadPhpcbfOnly.php autoload file was loaded, while it shouldn\'t have been' + ); + + }//end testShouldProcessAutoloadCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are respected and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessAutoloadCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $originallyIncludes = get_included_files(); + + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetAutoloadTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + new Ruleset($config); + + $finalIncludes = get_included_files(); + $diff = array_diff($finalIncludes, $originallyIncludes); + + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.1.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.1.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.2.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.2.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.3.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.3.php autoload file was not loaded' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadAlways.4.php'), + $diff, + 'ProcessRulesetAutoloadLoadAlways.4.php autoload file was not loaded' + ); + $this->assertNotContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadPhpcsOnly.php'), + $diff, + 'ProcessRulesetAutoloadLoadPhpcsOnly.php autoload file was loaded, while it shouldn\'t have been' + ); + $this->assertContains( + __DIR__.str_replace('/', DIRECTORY_SEPARATOR, '/Fixtures/ProcessRulesetAutoloadLoadPhpcbfOnly.php'), + $diff, + 'ProcessRulesetAutoloadLoadPhpcbfOnly.php autoload file was not loaded' + ); + + }//end testShouldProcessAutoloadCbfonly() + + + /** + * Test an exception is thrown when the directive points to a file which doesn't exist. + * + * @return void + */ + public function testFileNotFoundException() + { + $exceptionMsg = 'ERROR: The specified autoload file "./tests/Core/Ruleset/Fixtures/ThisFileDoesNotExist.php" does not exist'; + $this->expectRuntimeExceptionMessage($exceptionMsg); + + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetAutoloadFileNotFoundTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + new Ruleset($config); + + }//end testFileNotFoundException() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadTest.xml new file mode 100644 index 000000000..f886288e8 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetAutoloadTest.xml @@ -0,0 +1,37 @@ + + + + . + + + + ./Fixtures/ProcessRulesetAutoloadLoadAlways.1.php + Fixtures/ProcessRulesetAutoloadLoadAlways.2.php + + + ./tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadAlways.3.php + tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadAlways.4.php + + + ./tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadPhpcsOnly.php + + + ./tests/Core/Ruleset/Fixtures/ProcessRulesetAutoloadLoadPhpcbfOnly.php + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetEmptyFileTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetEmptyFileTest.xml new file mode 100644 index 000000000..e69de29bb diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetMultiErrorTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetMultiErrorTest.xml new file mode 100644 index 000000000..211b5683e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetMultiErrorTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetSingleErrorTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetSingleErrorTest.xml new file mode 100644 index 000000000..37aeef6bb --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetSingleErrorTest.xml @@ -0,0 +1,2 @@ + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetTest.php new file mode 100644 index 000000000..2798c2fc6 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetBrokenRulesetTest.php @@ -0,0 +1,96 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Test handling of broken ruleset files. + * + * Note: these tests need to run in separate processes as otherwise they run into + * some weirdness with the libxml_get_errors()/libxml_clear_errors() functions + * (duplicate error messages). + * + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + * + * @group Windows + * + * @covers \PHP_CodeSniffer\Ruleset::processRuleset + */ +final class ProcessRulesetBrokenRulesetTest extends AbstractRulesetTestCase +{ + + + /** + * Test displaying an informative error message when an empty XML ruleset file is encountered. + * + * @return void + */ + public function testBrokenRulesetEmptyFile() + { + $standard = __DIR__.'/ProcessRulesetBrokenRulesetEmptyFileTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $regex = '`^ERROR: Ruleset \S+ProcessRulesetBrokenRulesetEmptyFileTest\.xml is not valid\R'; + $regex .= '(- On line 1, column 1: Document is empty\R)?$`'; + + $this->expectRuntimeExceptionRegex($regex); + + new Ruleset($config); + + }//end testBrokenRulesetEmptyFile() + + + /** + * Test displaying an informative error message for a broken XML ruleset with a single XML error. + * + * @return void + */ + public function testBrokenRulesetSingleError() + { + $standard = __DIR__.'/ProcessRulesetBrokenRulesetSingleErrorTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $regex = '`^ERROR: Ruleset \S+ProcessRulesetBrokenRulesetSingleErrorTest\.xml is not valid\R'; + $regex .= '- On line 3, column 1: (Premature end of data in tag ruleset line 2|EndTag: \'expectRuntimeExceptionRegex($regex); + + new Ruleset($config); + + }//end testBrokenRulesetSingleError() + + + /** + * Test displaying an informative error message for a broken XML ruleset with multiple XML errors. + * + * @return void + */ + public function testBrokenRulesetMultiError() + { + $standard = __DIR__.'/ProcessRulesetBrokenRulesetMultiErrorTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $regex = '`^ERROR: Ruleset \S+ProcessRulesetBrokenRulesetMultiErrorTest\.xml is not valid\R'; + $regex .= '- On line 8, column 12: Opening and ending tag mismatch: property line 7 and rule\R'; + $regex .= '- On line 10, column 11: Opening and ending tag mismatch: properties line [57] and ruleset\R'; + $regex .= '(- On line 11, column 1: (Premature end of data in tag rule(set)? line [24]|EndTag: \'expectRuntimeExceptionRegex($regex); + + new Ruleset($config); + + }//end testBrokenRulesetMultiError() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetExcludeSniffGroupTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetExcludeSniffGroupTest.xml new file mode 100644 index 000000000..5aa4aede2 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetExcludeSniffGroupTest.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetInvalidNoSniffsDirTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetInvalidNoSniffsDirTest.xml new file mode 100644 index 000000000..598743589 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetInvalidNoSniffsDirTest.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetMiscTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetMiscTest.xml new file mode 100644 index 000000000..7adef2287 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetMiscTest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetShouldProcessElementTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetShouldProcessElementTest.php new file mode 100644 index 000000000..59fce1b19 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetShouldProcessElementTest.php @@ -0,0 +1,391 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Config; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test handling of `phpc(cs|cbf)-only` instructions at ruleset level. + * + * @covers \PHP_CodeSniffer\Ruleset::processRuleset + * @covers \PHP_CodeSniffer\Ruleset::shouldProcessElement + */ +final class ProcessRulesetShouldProcessElementTest extends TestCase +{ + + /** + * Cache to store the original ini values for ini settings being changed in these tests. + * + * @var array + */ + private static $originalIniValues = [ + 'bcmath.scale' => null, + 'docref_root' => null, + 'user_agent' => null, + ]; + + /** + * The Config object. + * + * @var \PHP_CodeSniffer\Tests\ConfigDouble + */ + private static $config; + + /** + * The Ruleset object. + * + * @var \PHP_CodeSniffer\Ruleset + */ + private static $ruleset; + + + /** + * Store the original ini values to allow for restoring them after the tests. + * + * @beforeClass + * + * @return void + */ + public static function saveOriginalIniValues() + { + foreach (self::$originalIniValues as $name => $null) { + $value = ini_get($name); + if ($value !== false) { + self::$originalIniValues[$name] = $value; + } + } + + }//end saveOriginalIniValues() + + + /** + * Initialize the config and ruleset objects for this test only once (but do allow recording code coverage). + * + * @before + * + * @return void + */ + protected function initializeConfigAndRuleset() + { + if (isset(self::$ruleset) === false) { + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetShouldProcessElementTest.xml'; + self::$config = new ConfigDouble(["--standard=$standard"]); + self::$ruleset = new Ruleset(self::$config); + } + + }//end initializeConfigAndRuleset() + + + /** + * Destroy the Config object and restore the ini values after the tests. + * + * @afterClass + * + * @return void + */ + public static function restoreOriginalValues() + { + // Explicitly trigger __destruct() on the ConfigDouble to reset the Config statics. + // The explicit method call prevents potential stray test-local references to the $config object + // preventing the destructor from running the clean up (which without stray references would be + // automagically triggered when this object is destroyed, but we can't definitively rely on that). + if (isset(self::$config) === true) { + self::$config->__destruct(); + } + + foreach (self::$originalIniValues as $name => $value) { + if ($value === null) { + continue; + } + + ini_set($name, $value); + } + + }//end restoreOriginalValues() + + + /** + * Verify that in CS mode, phpcs-only directives are respected and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessConfigCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $this->assertSame('true', Config::getConfigData('neither'), 'Non-selective config directive was not applied.'); + $this->assertSame('true', Config::getConfigData('csOnly'), 'CS-only config directive was not applied.'); + $this->assertSame(null, Config::getConfigData('cbfOnly'), 'CBF-only config directive was applied, while it shouldn\'t have been.'); + + }//end testShouldProcessConfigCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are respected and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessConfigCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $this->assertSame('true', Config::getConfigData('neither'), 'Non-selective config directive was not applied.'); + $this->assertSame(null, Config::getConfigData('csOnly'), 'CS-only config directive was applied, while it shouldn\'t have been.'); + $this->assertSame('true', Config::getConfigData('cbfOnly'), 'CBF-only config directive was not applied.'); + + }//end testShouldProcessConfigCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are respected and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessArgCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $expectedExtensions = [ + 'php' => 'PHP', + 'phpt' => 'PHP', + ]; + $expectedReports = ['full' => null]; + + $this->assertSame($expectedExtensions, self::$config->extensions, 'Non-selective arg directive was not applied.'); + $this->assertTrue(self::$config->showProgress, 'Non-selective short arg directive was not applied [1].'); + $this->assertTrue(self::$config->showSources, 'Non-selective short arg directive was not applied [2].'); + $this->assertTrue(self::$config->colors, 'CS-only arg directive was not applied.'); + $this->assertSame($expectedReports, self::$config->reports, 'CBF-only arg directive was applied, while it shouldn\'t have been.'); + + }//end testShouldProcessArgCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are respected and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessArgCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $expectedExtensions = [ + 'php' => 'PHP', + 'phpt' => 'PHP', + ]; + $expectedReports = ['summary' => null]; + + $this->assertSame($expectedExtensions, self::$config->extensions, 'Non-selective arg directive was not applied.'); + $this->assertTrue(self::$config->showProgress, 'Non-selective short arg directive was not applied [1].'); + $this->assertTrue(self::$config->showSources, 'Non-selective short arg directive was not applied [2].'); + $this->assertFalse(self::$config->colors, 'CS-only arg directive was applied, while it shouldn\'t have been.'); + $this->assertSame($expectedReports, self::$config->reports, 'CBF-only arg directive was not applied.'); + + }//end testShouldProcessArgCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are respected and phpcbf-only + * directives are ignored. + * + * @requires extension bcmath + * + * @return void + */ + public function testShouldProcessIniCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $this->assertSame('2', ini_get('bcmath.scale'), 'Non-selective ini directive was not applied.'); + $this->assertSame('path/to/docs/', ini_get('docref_root'), 'CS-only ini directive was not applied.'); + $this->assertSame('', ini_get('user_agent'), 'CBF-only ini directive was applied, while it shouldn\'t have been.'); + + }//end testShouldProcessIniCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are respected and phpcs-only + * directives are ignored. + * + * @group CBF + * @requires extension bcmath + * + * @return void + */ + public function testShouldProcessIniCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $this->assertSame('2', ini_get('bcmath.scale'), 'Non-selective ini directive was not applied.'); + $this->assertSame('', ini_get('docref_root'), 'CS-only ini directive was applied, while it shouldn\'t have been..'); + $this->assertSame('Never mind', ini_get('user_agent'), 'CBF-only ini directive was not applied.'); + + }//end testShouldProcessIniCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are respected and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessExcludePatternCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $expected = [ + './tests/' => 'absolute', + './vendor/' => 'absolute', + ]; + + $this->assertSame($expected, self::$ruleset->ignorePatterns); + + }//end testShouldProcessExcludePatternCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are respected and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessExcludePatternCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $expected = [ + './tests/' => 'absolute', + './node-modules/' => 'absolute', + ]; + + $this->assertSame($expected, self::$ruleset->ignorePatterns); + + }//end testShouldProcessExcludePatternCbfonly() + + + /** + * Verify that in CS mode, phpcs-only directives are respected and phpcbf-only + * directives are ignored. + * + * @return void + */ + public function testShouldProcessRuleCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $this->assertArrayHasKey('PEAR.Formatting.MultiLineAssignment', self::$ruleset->sniffCodes); + $this->assertArrayHasKey('Generic.Arrays.ArrayIndent', self::$ruleset->sniffCodes); + $this->assertArrayNotHasKey('PSR2.Classes.ClassDeclaration', self::$ruleset->sniffCodes); + + }//end testShouldProcessRuleCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only directives are respected and phpcs-only + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessRuleCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $this->assertArrayHasKey('PEAR.Formatting.MultiLineAssignment', self::$ruleset->sniffCodes); + $this->assertArrayNotHasKey('Generic.Arrays.ArrayIndent', self::$ruleset->sniffCodes); + $this->assertArrayHasKey('PSR2.Classes.ClassDeclaration', self::$ruleset->sniffCodes); + + }//end testShouldProcessRuleCbfonly() + + + /** + * Verify that in CS mode, phpcs-only in directives are respected and phpcbf-only in + * directives are ignored. + * + * @return void + */ + public function testShouldProcessRuleExcludeCsonly() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $expected = [ + 'PEAR.Formatting.MultiLineAssignment.Indent' => [ + 'severity' => 0, + ], + ]; + + $this->assertSame($expected, self::$ruleset->ruleset); + + }//end testShouldProcessRuleExcludeCsonly() + + + /** + * Verify that in CBF mode, phpcbf-only in directives are respected and phpcs-only in + * directives are ignored. + * + * @group CBF + * + * @return void + */ + public function testShouldProcessRuleExcludeCbfonly() + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $expected = [ + 'PEAR.Formatting.MultiLineAssignment.EqualSignLine' => [ + 'severity' => 0, + ], + ]; + + $this->assertSame($expected, self::$ruleset->ruleset); + + }//end testShouldProcessRuleExcludeCbfonly() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetShouldProcessElementTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetShouldProcessElementTest.xml new file mode 100644 index 000000000..2a2566722 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetShouldProcessElementTest.xml @@ -0,0 +1,54 @@ + + + + . + + + + + + + + ./tests/ + + + + + + + + + ./vendor/ + + + + + + + + + + + + + ./node-modules/ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetTest.php new file mode 100644 index 000000000..d37c03102 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ProcessRulesetTest.php @@ -0,0 +1,266 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test various aspects of the Ruleset::processRuleset() method not covered via other tests. + * + * @covers \PHP_CodeSniffer\Ruleset::processRuleset + */ +final class ProcessRulesetTest extends TestCase +{ + + + /** + * Verify that a registered standard which doesn't have a "Sniffs" directory, but does have a file + * called "Sniffs" doesn't result in any errors being thrown. + * + * @return void + */ + public function testSniffsFileNotDirectory() + { + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetInvalidNoSniffsDirTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $expected = ['Generic.PHP.BacktickOperator' => 'PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\BacktickOperatorSniff']; + + $this->assertSame($expected, $ruleset->sniffCodes); + + }//end testSniffsFileNotDirectory() + + + /** + * Verify that all sniffs in a registered standard included in a ruleset automatically get added. + * + * @return void + */ + public function testAutoExpandSniffsDirectory() + { + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetAutoExpandSniffsDirectoryTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $std = 'TestStandard'; + $sniffDir = 'Fixtures\TestStandard\Sniffs'; + $expected = [ + "$std.Deprecated.WithLongReplacement" => "$sniffDir\Deprecated\WithLongReplacementSniff", + "$std.Deprecated.WithReplacement" => "$sniffDir\Deprecated\WithReplacementSniff", + "$std.Deprecated.WithReplacementContainingLinuxNewlines" => "$sniffDir\Deprecated\WithReplacementContainingLinuxNewlinesSniff", + "$std.Deprecated.WithReplacementContainingNewlines" => "$sniffDir\Deprecated\WithReplacementContainingNewlinesSniff", + "$std.Deprecated.WithoutReplacement" => "$sniffDir\Deprecated\WithoutReplacementSniff", + "$std.DeprecatedInvalid.EmptyDeprecationVersion" => "$sniffDir\DeprecatedInvalid\EmptyDeprecationVersionSniff", + "$std.DeprecatedInvalid.EmptyRemovalVersion" => "$sniffDir\DeprecatedInvalid\EmptyRemovalVersionSniff", + "$std.DeprecatedInvalid.InvalidDeprecationMessage" => "$sniffDir\DeprecatedInvalid\InvalidDeprecationMessageSniff", + "$std.DeprecatedInvalid.InvalidDeprecationVersion" => "$sniffDir\DeprecatedInvalid\InvalidDeprecationVersionSniff", + "$std.DeprecatedInvalid.InvalidRemovalVersion" => "$sniffDir\DeprecatedInvalid\InvalidRemovalVersionSniff", + "$std.MissingInterface.ValidImplements" => "$sniffDir\MissingInterface\ValidImplementsSniff", + "$std.MissingInterface.ValidImplementsViaAbstract" => "$sniffDir\MissingInterface\ValidImplementsViaAbstractSniff", + "$std.SetProperty.AllowedAsDeclared" => "$sniffDir\SetProperty\AllowedAsDeclaredSniff", + "$std.SetProperty.AllowedViaMagicMethod" => "$sniffDir\SetProperty\AllowedViaMagicMethodSniff", + "$std.SetProperty.AllowedViaStdClass" => "$sniffDir\SetProperty\AllowedViaStdClassSniff", + "$std.SetProperty.NotAllowedViaAttribute" => "$sniffDir\SetProperty\NotAllowedViaAttributeSniff", + "$std.SetProperty.PropertyTypeHandling" => "$sniffDir\SetProperty\PropertyTypeHandlingSniff", + "$std.ValidSniffs.RegisterEmptyArray" => "$sniffDir\ValidSniffs\RegisterEmptyArraySniff", + ]; + + // Sort the value to make the tests stable as different OSes will read directories + // in a different order and the order is not relevant for these tests. Just the values. + $actual = $ruleset->sniffCodes; + ksort($actual); + + $this->assertSame($expected, $actual); + + }//end testAutoExpandSniffsDirectory() + + + /** + * Verify handling of exclusions of groups of sniffs after inclusion via an even larger "group". + * + * @return void + */ + public function testExcludeSniffGroup() + { + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetExcludeSniffGroupTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + $expected = [ + 'PSR1.Classes.ClassDeclaration' => 'PHP_CodeSniffer\Standards\PSR1\Sniffs\Classes\ClassDeclarationSniff', + 'PSR1.Methods.CamelCapsMethodName' => 'PHP_CodeSniffer\Standards\PSR1\Sniffs\Methods\CamelCapsMethodNameSniff', + ]; + + // Sort the value to make the tests stable as different OSes will read directories + // in a different order and the order is not relevant for these tests. Just the values. + $actual = $ruleset->sniffCodes; + ksort($actual); + + $this->assertSame($expected, $actual); + + }//end testExcludeSniffGroup() + + + /* + * No test for without "name" as there is nothing we can assert to verify it's being ignored. + */ + + + /** + * Test that an `` directive without a "value" attribute will be set to the ini equivalent of `true`. + * + * @return void + */ + public function testIniWithoutValue() + { + $originalValue = ini_get('user_agent'); + + // Set up the ruleset. + $this->getMiscRuleset(); + + $actualValue = ini_get('user_agent'); + // Reset the ini to its original value before the assertion to ensure it's never left in an incorrect state. + if ($originalValue !== false) { + ini_set('user_agent', $originalValue); + } + + $this->assertSame('1', $actualValue); + + }//end testIniWithoutValue() + + + /** + * Verify that inclusion of a single error code: + * - Includes the sniff, but sets "severity" for the sniff to 0; + * - Sets "severity" for the specific error code included to 5.; + * + * @return void + */ + public function testIncludeSingleErrorCode() + { + // Set up the ruleset. + $ruleset = $this->getMiscRuleset(); + + $key = 'severity'; + + $sniffCode = 'Generic.PHP.RequireStrictTypes'; + $this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered"); + $this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array"); + $this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode"); + $this->assertSame(0, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode"); + + $sniffCode = 'Generic.PHP.RequireStrictTypes.MissingDeclaration'; + $this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered"); + $this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array"); + $this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode"); + $this->assertSame(5, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode"); + + }//end testIncludeSingleErrorCode() + + + /** + * Verify that if all error codes, save one, from a sniff were previously excluded, an include for an additional + * error code from that same sniff will be respected. + * + * @return void + */ + public function testErrorCodeIncludeAfterExclude() + { + // Set up the ruleset. + $ruleset = $this->getMiscRuleset(); + + $key = 'severity'; + + $sniffCode = 'PEAR.Files.IncludingFile'; + $this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered"); + $this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array"); + $this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode"); + $this->assertSame(0, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode"); + + $sniffCode = 'PEAR.Files.IncludingFile.BracketsNotRequired'; + $this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered"); + $this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array"); + $this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode"); + $this->assertSame(5, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode"); + + $sniffCode = 'PEAR.Files.IncludingFile.UseRequire'; + $this->assertArrayHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode not registered"); + $this->assertTrue(is_array($ruleset->ruleset[$sniffCode]), "Sniff $sniffCode is not an array"); + $this->assertArrayHasKey($key, $ruleset->ruleset[$sniffCode], "Directive $key not registered for sniff $sniffCode"); + $this->assertSame(5, $ruleset->ruleset[$sniffCode][$key], "$key has unexpected value for sniff $sniffCode"); + + }//end testErrorCodeIncludeAfterExclude() + + + /** + * Verify that a element without a "ref" is completely ignored. + * + * @return void + */ + public function testRuleWithoutRefIsIgnored() + { + // Set up the ruleset. + $ruleset = $this->getMiscRuleset(); + + $sniffCode = 'Generic.Metrics.CyclomaticComplexity'; + $this->assertArrayNotHasKey($sniffCode, $ruleset->sniffCodes, "Sniff $sniffCode registered"); + $this->assertArrayNotHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode adjusted"); + + }//end testRuleWithoutRefIsIgnored() + + + /** + * Verify that no "ruleset adjustments" are registered via an `` without a "name". + * + * @return void + */ + public function testRuleExcludeWithoutNameIsIgnored() + { + // Set up the ruleset. + $ruleset = $this->getMiscRuleset(); + + $sniffCode = 'Generic.PHP.BacktickOperator'; + $this->assertArrayHasKey($sniffCode, $ruleset->sniffCodes, "Sniff $sniffCode not registered"); + $this->assertArrayNotHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode adjusted"); + + $sniffCode = 'Generic.PHP.BacktickOperator.Found'; + $this->assertArrayNotHasKey($sniffCode, $ruleset->ruleset, "Sniff $sniffCode adjusted"); + + }//end testRuleExcludeWithoutNameIsIgnored() + + + /** + * Test Helper. + * + * @return \PHP_CodeSniffer\Ruleset + */ + private function getMiscRuleset() + { + static $ruleset; + + if (isset($ruleset) === false) { + // Set up the ruleset. + $standard = __DIR__.'/ProcessRulesetMiscTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + } + + return $ruleset; + + }//end getMiscRuleset() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingInlineTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingInlineTest.xml new file mode 100644 index 000000000..8f276f81e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingInlineTest.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingTest.php new file mode 100644 index 000000000..1db15aa5d --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingTest.php @@ -0,0 +1,333 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Files\LocalFile; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test the handling of property value types for properties set via the ruleset and inline. + * + * @covers \PHP_CodeSniffer\Ruleset::processRule + * @covers \PHP_CodeSniffer\Ruleset::setSniffProperty + */ +final class PropertyTypeHandlingTest extends TestCase +{ + + /** + * Sniff code for the sniff used in these tests. + * + * @var string + */ + const SNIFF_CODE = 'TestStandard.SetProperty.PropertyTypeHandling'; + + /** + * Class name of the sniff used in these tests. + * + * @var string + */ + const SNIFF_CLASS = 'Fixtures\\TestStandard\\Sniffs\\SetProperty\\PropertyTypeHandlingSniff'; + + + /** + * Verify a deprecation notice is shown when an array property is set from the ruleset using a comma-separated string. + * + * Support for this format was (soft) deprecated in PHPCS 3.3.0. + * + * @return void + */ + public function testUsingOldSchoolArrayFormatShowsDeprecationNotice() + { + $regex = '`^('; + $regex .= 'DEPRECATED: Passing an array of values to a property using a comma-separated string\R'; + $regex .= 'was deprecated in PHP_CodeSniffer 3\.3\.0\. Support will be removed in PHPCS 4\.0\.0\.\R'; + $regex .= 'The deprecated syntax was used for property "expectsOldSchool(?:EmptyArray|ArrayWith(?:Extended|Only)?(?:KeysAnd)?Values)"\R'; + $regex .= 'for sniff "'; + $regex .= '(?:\./tests/Core/Ruleset/Fixtures/TestStandard/Sniffs/SetProperty/PropertyTypeHandlingSniff\.php|TestStandard\.SetProperty\.PropertyTypeHandling)'; + $regex .= '"\.\R'; + $regex .= 'Pass array values via nodes instead\.\R'; + $regex .= '){14}\R$`'; + + $this->expectOutputRegex($regex); + + // Set up the ruleset. + $standard = __DIR__.'/PropertyTypeHandlingTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + new Ruleset($config); + + }//end testUsingOldSchoolArrayFormatShowsDeprecationNotice() + + + /** + * Test the value type handling for properties set via a ruleset. + * + * @param string $propertyName Property name. + * @param mixed $expected Expected property value. + * + * @dataProvider dataTypeHandling + * @dataProvider dataArrayPropertyExtending + * + * @return void + */ + public function testTypeHandlingWhenSetViaRuleset($propertyName, $expected) + { + $sniffObject = $this->getSniffObjectForRuleset(); + + $this->assertSame($expected, $sniffObject->$propertyName); + + }//end testTypeHandlingWhenSetViaRuleset() + + + /** + * Test the value type handling for properties set inline in a test case file. + * + * @param string $propertyName Property name. + * @param mixed $expected Expected property value. + * + * @dataProvider dataTypeHandling + * + * @return void + */ + public function testTypeHandlingWhenSetInline($propertyName, $expected) + { + $sniffObject = $this->getSniffObjectAfterProcessingFile(); + + $this->assertSame($expected, $sniffObject->$propertyName); + + }//end testTypeHandlingWhenSetInline() + + + /** + * Data provider. + * + * @see self::testTypeHandlingWhenSetViaRuleset() + * @see self::testTypeHandlingWhenSetInline() + * + * @return array> + */ + public static function dataTypeHandling() + { + $expectedArrayOnlyValues = [ + 'string', + '10', + '1.5', + 'null', + 'true', + 'false', + ]; + $expectedArrayKeysAndValues = [ + 'string' => 'string', + 10 => '10', + 'float' => '1.5', + 'null' => 'null', + 'true' => 'true', + 'false' => 'false', + ]; + + return [ + 'String value (default)' => [ + 'propertyName' => 'expectsString', + 'expected' => 'arbitraryvalue', + ], + 'String value with whitespace gets trimmed' => [ + 'propertyName' => 'expectsTrimmedString', + 'expected' => 'some value', + ], + 'String with whitespace only value becomes null' => [ + 'propertyName' => 'emptyStringBecomesNull', + 'expected' => null, + ], + 'Integer value gets set as string' => [ + 'propertyName' => 'expectsIntButAcceptsString', + 'expected' => '12345', + ], + 'Float value gets set as string' => [ + 'propertyName' => 'expectsFloatButAcceptsString', + 'expected' => '12.345', + ], + 'Null value gets set as string' => [ + 'propertyName' => 'expectsNull', + 'expected' => 'null', + ], + 'Null (uppercase) value gets set as string' => [ + 'propertyName' => 'expectsNullCase', + 'expected' => 'NULL', + ], + 'True value gets set as boolean' => [ + 'propertyName' => 'expectsBooleanTrue', + 'expected' => true, + ], + 'True (mixed case) value gets set as string' => [ + 'propertyName' => 'expectsBooleanTrueCase', + 'expected' => 'True', + ], + 'True (with spaces) value gets set as boolean' => [ + 'propertyName' => 'expectsBooleanTrueTrimmed', + 'expected' => true, + ], + 'False value gets set as boolean' => [ + 'propertyName' => 'expectsBooleanFalse', + 'expected' => false, + ], + 'False (mixed case) value gets set as string' => [ + 'propertyName' => 'expectsBooleanFalseCase', + 'expected' => 'fALSe', + ], + 'False (with spaces) value gets set as boolean' => [ + 'propertyName' => 'expectsBooleanFalseTrimmed', + 'expected' => false, + ], + 'Array with only values (new style)' => [ + 'propertyName' => 'expectsArrayWithOnlyValues', + 'expected' => $expectedArrayOnlyValues, + ], + 'Array with keys and values (new style)' => [ + 'propertyName' => 'expectsArrayWithKeysAndValues', + 'expected' => $expectedArrayKeysAndValues, + ], + 'Empty array (new style)' => [ + 'propertyName' => 'expectsEmptyArray', + 'expected' => [], + ], + 'Array with only values (old style)' => [ + 'propertyName' => 'expectsOldSchoolArrayWithOnlyValues', + 'expected' => $expectedArrayOnlyValues, + ], + 'Array with keys and values (old style)' => [ + 'propertyName' => 'expectsOldSchoolArrayWithKeysAndValues', + 'expected' => $expectedArrayKeysAndValues, + ], + 'Empty array (old style)' => [ + 'propertyName' => 'expectsOldSchoolEmptyArray', + 'expected' => [], + ], + ]; + + }//end dataTypeHandling() + + + /** + * Data provider. + * + * Array property extending is a feature which is only supported from a ruleset, not for inline property setting. + * + * @see self::testTypeHandlingWhenSetViaRuleset() + * + * @return array> + */ + public static function dataArrayPropertyExtending() + { + $expectedArrayOnlyValuesExtended = [ + 'string', + '15', + 'another string', + ]; + $expectedArrayKeysAndValuesExtended = [ + 10 => '10', + 'string' => 'string', + 15 => '15', + 'another string' => 'another string', + ]; + + return [ + 'Array with only values extended (new style)' => [ + 'propertyName' => 'expectsArrayWithExtendedValues', + 'expected' => $expectedArrayOnlyValuesExtended, + ], + 'Array with keys and values extended (new style)' => [ + 'propertyName' => 'expectsArrayWithExtendedKeysAndValues', + 'expected' => $expectedArrayKeysAndValuesExtended, + ], + 'Array with only values extended (old style)' => [ + 'propertyName' => 'expectsOldSchoolArrayWithExtendedValues', + 'expected' => $expectedArrayOnlyValuesExtended, + ], + 'Array with keys and values extended (old style)' => [ + 'propertyName' => 'expectsOldSchoolArrayWithExtendedKeysAndValues', + 'expected' => $expectedArrayKeysAndValuesExtended, + ], + ]; + + }//end dataArrayPropertyExtending() + + + /** + * Test Helper. + * + * Note: the deprecations for using comma-separated string to pass an array, are silenced in this helper + * as that's not what's being tested here. + * + * @see self::testTypeHandlingWhenSetViaRuleset() + * + * @return \PHP_CodeSniffer\Sniffs\Sniff + */ + private function getSniffObjectForRuleset() + { + static $sniffObject; + + if (isset($sniffObject) === false) { + // Set up the ruleset. + $standard = __DIR__.'/PropertyTypeHandlingTest.xml'; + $config = new ConfigDouble(["--standard=$standard", '-q']); + $ruleset = new Ruleset($config); + + // Verify that our target sniff has been registered. + $this->assertArrayHasKey(self::SNIFF_CODE, $ruleset->sniffCodes, 'Target sniff not registered'); + $this->assertSame(self::SNIFF_CLASS, $ruleset->sniffCodes[self::SNIFF_CODE], 'Target sniff not registered with the correct class'); + $this->assertArrayHasKey(self::SNIFF_CLASS, $ruleset->sniffs, 'Sniff class not listed in registered sniffs'); + + $sniffObject = $ruleset->sniffs[self::SNIFF_CLASS]; + } + + return $sniffObject; + + }//end getSniffObjectForRuleset() + + + /** + * Test Helper + * + * @see self::testTypeHandlingWhenSetInline() + * + * @return \PHP_CodeSniffer\Sniffs\Sniff + */ + private function getSniffObjectAfterProcessingFile() + { + static $sniffObject; + + if (isset($sniffObject) === false) { + // Set up the ruleset. + $standard = __DIR__.'/PropertyTypeHandlingInlineTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + $ruleset = new Ruleset($config); + + // Verify that our target sniff has been registered. + $this->assertArrayHasKey(self::SNIFF_CODE, $ruleset->sniffCodes, 'Target sniff not registered'); + $this->assertSame(self::SNIFF_CLASS, $ruleset->sniffCodes[self::SNIFF_CODE], 'Target sniff not registered with the correct class'); + $this->assertArrayHasKey(self::SNIFF_CLASS, $ruleset->sniffs, 'Sniff class not listed in registered sniffs'); + + $sniffObject = $ruleset->sniffs[self::SNIFF_CLASS]; + + // Process the file with inline phpcs:set annotations. + $testFile = realpath(__DIR__.'/Fixtures/PropertyTypeHandlingInline.inc'); + $this->assertNotFalse($testFile); + + $phpcsFile = new LocalFile($testFile, $ruleset, $config); + $phpcsFile->process(); + } + + return $sniffObject; + + }//end getSniffObjectAfterProcessingFile() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingTest.xml new file mode 100644 index 000000000..2e89a37b5 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/PropertyTypeHandlingTest.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsMissingInterfaceInvalidTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsMissingInterfaceInvalidTest.xml new file mode 100644 index 000000000..d3886c478 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsMissingInterfaceInvalidTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsMissingInterfaceTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsMissingInterfaceTest.php new file mode 100644 index 000000000..89c82c028 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsMissingInterfaceTest.php @@ -0,0 +1,65 @@ + + * @copyright 2025 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Tests deprecation of support for sniffs not implementing the PHPCS `Sniff` interface. + * + * @covers \PHP_CodeSniffer\Ruleset::registerSniffs + */ +final class RegisterSniffsMissingInterfaceTest extends TestCase +{ + + + /** + * Test that no deprecation is shown when sniffs implement the `PHP_CodeSniffer\Sniffs\Sniff` interface. + * + * @return void + */ + public function testNoNoticesForSniffsImplementingInterface() + { + // Set up the ruleset. + $standard = __DIR__.'/RegisterSniffsMissingInterfaceValidTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $this->expectOutputString(''); + + new Ruleset($config); + + }//end testNoNoticesForSniffsImplementingInterface() + + + /** + * Test that a deprecation notice is shown if a sniff doesn't implement the Sniff interface. + * + * @return void + */ + public function testDeprecationNoticeWhenSniffDoesntImplementInterface() + { + // Set up the ruleset. + $standard = __DIR__.'/RegisterSniffsMissingInterfaceInvalidTest.xml'; + $config = new ConfigDouble(["--standard=$standard"]); + + $expected = 'DEPRECATED: All sniffs must implement the PHP_CodeSniffer\\Sniffs\\Sniff interface.'.PHP_EOL; + $expected .= 'Interface not implemented for sniff Fixtures\\TestStandard\\Sniffs\\MissingInterface\\InvalidImplementsWithoutImplementSniff.'.PHP_EOL; + $expected .= 'Contact the sniff author to fix the sniff.'.PHP_EOL.PHP_EOL; + + $this->expectOutputString($expected); + + new Ruleset($config); + + }//end testDeprecationNoticeWhenSniffDoesntImplementInterface() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsMissingInterfaceValidTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsMissingInterfaceValidTest.xml new file mode 100644 index 000000000..ed5220ce8 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsMissingInterfaceValidTest.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoProcessTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoProcessTest.xml new file mode 100644 index 000000000..3a40aac05 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoProcessTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterOrProcessTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterOrProcessTest.xml new file mode 100644 index 000000000..8941342e0 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterOrProcessTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterTest.xml new file mode 100644 index 000000000..f0ab808fa --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterTest.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffTest.php new file mode 100644 index 000000000..1efe5cdba --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsRejectsInvalidSniffTest.php @@ -0,0 +1,80 @@ + + * @copyright 2025 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; + +/** + * Tests that invalid sniffs will be rejected with an informative error message. + * + * @covers \PHP_CodeSniffer\Ruleset::registerSniffs + */ +final class RegisterSniffsRejectsInvalidSniffTest extends AbstractRulesetTestCase +{ + + + /** + * Verify that an error is thrown if an invalid sniff class is loaded. + * + * @param string $standard The standard to use for the test. + * @param string $methodName The name of the missing method. + * + * @dataProvider dataExceptionIsThrownOnMissingInterfaceMethod + * + * @return void + */ + public function testExceptionIsThrownOnMissingInterfaceMethod($standard, $methodName) + { + // Set up the ruleset. + $standard = __DIR__.'/'.$standard; + $config = new ConfigDouble(["--standard=$standard"]); + + $regex = "`(^|\R)ERROR: Sniff class \S+Sniff is missing required method $methodName\(\)\.\R`"; + $this->expectRuntimeExceptionRegex($regex); + + new Ruleset($config); + + }//end testExceptionIsThrownOnMissingInterfaceMethod() + + + /** + * Data provider. + * + * @see testExceptionIsThrownOnMissingInterfaceMethod() + * + * @return array> + */ + public static function dataExceptionIsThrownOnMissingInterfaceMethod() + { + return [ + 'Missing register() method' => [ + 'standard' => 'RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterTest.xml', + 'methodName' => 'register', + ], + 'Missing process() method' => [ + 'standard' => 'RegisterSniffsRejectsInvalidSniffNoImplementsNoProcessTest.xml', + 'methodName' => 'process', + ], + 'Missing both, checking register() method' => [ + 'standard' => 'RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterOrProcessTest.xml', + 'methodName' => 'register', + ], + 'Missing both, checking process() method' => [ + 'standard' => 'RegisterSniffsRejectsInvalidSniffNoImplementsNoRegisterOrProcessTest.xml', + 'methodName' => 'process', + ], + ]; + + }//end dataExceptionIsThrownOnMissingInterfaceMethod() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsTest.php new file mode 100644 index 000000000..1ed3ee182 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RegisterSniffsTest.php @@ -0,0 +1,293 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Ruleset; + +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Test the Ruleset::registerSniffs() method. + * + * @covers \PHP_CodeSniffer\Ruleset::registerSniffs + */ +final class RegisterSniffsTest extends TestCase +{ + + /** + * The Ruleset object. + * + * @var \PHP_CodeSniffer\Ruleset + */ + private static $ruleset; + + /** + * Original value of the $sniffs property on the Ruleset. + * + * @var array + */ + private static $originalSniffs = []; + + /** + * List of Standards dir relative sniff files loaded for the PSR1 standard. + * + * @var array + */ + private static $psr1SniffFiles = [ + 'Generic/Sniffs/Files/ByteOrderMarkSniff.php', + 'Generic/Sniffs/NamingConventions/UpperCaseConstantNameSniff.php', + 'Generic/Sniffs/PHP/DisallowAlternativePHPTagsSniff.php', + 'Generic/Sniffs/PHP/DisallowShortOpenTagSniff.php', + 'PSR1/Sniffs/Classes/ClassDeclarationSniff.php', + 'PSR1/Sniffs/Files/SideEffectsSniff.php', + 'PSR1/Sniffs/Methods/CamelCapsMethodNameSniff.php', + 'Squiz/Sniffs/Classes/ValidClassNameSniff.php', + ]; + + /** + * Absolute paths to the sniff files loaded for the PSR1 standard. + * + * @var array + */ + private static $psr1SniffAbsolutePaths = []; + + + /** + * Initialize the config and ruleset objects which will be used for some of these tests. + * + * @beforeClass + * + * @return void + */ + public static function initializeConfigAndRuleset() + { + // Set up the ruleset. + $config = new ConfigDouble(['--standard=PSR1']); + self::$ruleset = new Ruleset($config); + + // Remember the original value of the Ruleset::$sniff property as the tests adjust it. + self::$originalSniffs = self::$ruleset->sniffs; + + // Sort the value to make the tests stable as different OSes will read directories + // in a different order and the order is not relevant for these tests. Just the values. + ksort(self::$originalSniffs); + + // Update the sniff file list. + $standardsDir = dirname(dirname(dirname(__DIR__))).DIRECTORY_SEPARATOR; + $standardsDir .= 'src'.DIRECTORY_SEPARATOR.'Standards'.DIRECTORY_SEPARATOR; + + self::$psr1SniffAbsolutePaths = self::relativeToAbsoluteSniffFiles($standardsDir, self::$psr1SniffFiles); + + }//end initializeConfigAndRuleset() + + + /** + * Convert relative paths to absolute paths and ensure the paths use the correct OS-specific directory separator. + * + * @param string $baseDir Directory to which these paths are relative to. Including trailing slash. + * @param array $relativePaths Relative paths. + * + * @return array + */ + public static function relativeToAbsoluteSniffFiles($baseDir, $relativePaths) + { + $fileList = []; + foreach ($relativePaths as $sniffName) { + $sniffFile = str_replace('/', DIRECTORY_SEPARATOR, $sniffName); + $sniffFile = $baseDir.$sniffFile; + $fileList[] = $sniffFile; + } + + return $fileList; + + }//end relativeToAbsoluteSniffFiles() + + + /** + * Clear out the Ruleset::$sniffs property. + * + * @before + * + * @return void + */ + protected function clearOutSniffs() + { + // Clear out the Ruleset::$sniffs property. + self::$ruleset->sniffs = []; + + }//end clearOutSniffs() + + + /** + * Test that registering sniffs works as expected (simple base test case). + * + * @return void + */ + public function testRegisteredSniffsShouldBeTheSame() + { + self::$ruleset->registerSniffs(self::$psr1SniffAbsolutePaths, [], []); + + // Make sure the same sniff list was recreated (but without the objects having been created yet). + $this->assertSame(array_keys(self::$originalSniffs), array_keys(self::$ruleset->sniffs)); + $this->assertSame(array_keys(self::$originalSniffs), array_values(self::$ruleset->sniffs)); + + }//end testRegisteredSniffsShouldBeTheSame() + + + /** + * Test that if only specific sniffs are requested, only those are registered. + * + * {@internal Can't test this via the CLI arguments due to some code in the Ruleset class + * related to sniff tests.} + * + * @return void + */ + public function testRegisteredSniffsWithRestrictions() + { + $restrictions = [ + 'psr1\\sniffs\\classes\\classdeclarationsniff' => true, + 'psr1\\sniffs\\files\\sideeffectssniff' => true, + 'psr1\\sniffs\\methods\\camelcapsmethodnamesniff' => true, + ]; + + $expected = [ + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Classes\\ClassDeclarationSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Files\\SideEffectsSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Methods\\CamelCapsMethodNameSniff', + ]; + + self::$ruleset->registerSniffs(self::$psr1SniffAbsolutePaths, $restrictions, []); + + $this->assertSame($expected, array_keys(self::$ruleset->sniffs)); + + }//end testRegisteredSniffsWithRestrictions() + + + /** + * Test that sniffs excluded via the CLI are not registered. + * + * @return void + */ + public function testRegisteredSniffsWithExclusions() + { + // Set up the ruleset. + $args = [ + '--standard=PSR1', + '--exclude=PSR1.Classes.ClassDeclaration,PSR1.Files.SideEffects,PSR1.Methods.CamelCapsMethodName', + ]; + $config = new ConfigDouble($args); + $ruleset = new Ruleset($config); + + $expected = [ + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Files\\ByteOrderMarkSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\NamingConventions\\UpperCaseConstantNameSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowAlternativePHPTagsSniff', + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowShortOpenTagSniff', + 'PHP_CodeSniffer\\Standards\\Squiz\\Sniffs\\Classes\\ValidClassNameSniff', + ]; + + $actual = array_keys($ruleset->sniffs); + sort($actual); + + $this->assertSame($expected, $actual); + + }//end testRegisteredSniffsWithExclusions() + + + /** + * Test combining requesting specific sniffs and excluding a subset of those. + * + * @return void + */ + public function testRegisteredSniffsBothRestrictionsAndExclusions() + { + $restrictions = [ + 'generic\\sniffs\\namingconventions\\uppercaseconstantnamesniff' => true, + 'generic\\sniffs\\php\\disallowalternativephptagssniff' => true, + 'generic\\sniffs\\php\\disallowshortopentagsniff' => true, + 'psr1\\sniffs\\classes\\classdeclarationsniff' => true, + 'squiz\\sniffs\\classes\\validclassnamesniff' => true, + ]; + + $exclusions = [ + 'squiz\\sniffs\\classes\\validclassnamesniff' => true, + 'generic\\sniffs\\php\\disallowalternativephptagssniff' => true, + 'generic\\sniffs\\namingconventions\\uppercaseconstantnamesniff' => true, + ]; + + $expected = [ + 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\PHP\\DisallowShortOpenTagSniff', + 'PHP_CodeSniffer\\Standards\\PSR1\\Sniffs\\Classes\\ClassDeclarationSniff', + ]; + + self::$ruleset->registerSniffs(self::$psr1SniffAbsolutePaths, $restrictions, $exclusions); + + $this->assertSame($expected, array_keys(self::$ruleset->sniffs)); + + }//end testRegisteredSniffsBothRestrictionsAndExclusions() + + + /** + * Verify that abstract sniffs are filtered out and not registered. + * + * @return void + */ + public function testRegisterSniffsFiltersOutAbstractClasses() + { + $extraPathsBaseDir = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR; + $extraPaths = [ + 'DirectoryExpansion/.hiddenAbove/src/MyStandard/Sniffs/AbstractSniff.php', + 'DirectoryExpansion/.hiddenAbove/src/MyStandard/Sniffs/CategoryB/AnotherAbstractSniff.php', + ]; + $extraPaths = self::relativeToAbsoluteSniffFiles($extraPathsBaseDir, $extraPaths); + + $fileList = self::$psr1SniffAbsolutePaths; + foreach ($extraPaths as $path) { + $fileList[] = $path; + } + + self::$ruleset->registerSniffs($fileList, [], []); + + // Make sure the same sniff list was recreated (but without the objects having been created yet). + $this->assertSame(array_keys(self::$originalSniffs), array_keys(self::$ruleset->sniffs)); + $this->assertSame(array_keys(self::$originalSniffs), array_values(self::$ruleset->sniffs)); + + }//end testRegisterSniffsFiltersOutAbstractClasses() + + + /** + * Test that sniff files not in a "/Sniffs/" directory are filtered out and not registered. + * + * @return void + */ + public function testRegisteredSniffsFiltersOutFilePathsWithoutSniffsDir() + { + $extraPathsBaseDir = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR; + $extraPaths = [ + 'DirectoryExpansion/.hiddenAbove/src/MyStandard/Utils/NotInSniffsDirSniff.php', + 'DirectoryExpansion/.hiddenAbove/src/MyStandard/Utils/SubDir/NotInSniffsDirSniff.php', + ]; + $extraPaths = self::relativeToAbsoluteSniffFiles($extraPathsBaseDir, $extraPaths); + + $fileList = self::$psr1SniffAbsolutePaths; + foreach ($extraPaths as $path) { + $fileList[] = $path; + } + + self::$ruleset->registerSniffs($fileList, [], []); + + // Make sure the same sniff list was recreated (but without the objects having been created yet). + $this->assertSame(array_keys(self::$originalSniffs), array_keys(self::$ruleset->sniffs)); + $this->assertSame(array_keys(self::$originalSniffs), array_values(self::$ruleset->sniffs)); + + }//end testRegisteredSniffsFiltersOutFilePathsWithoutSniffsDir() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteLinuxTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteLinuxTest.php index 1955ce2a4..6eb0d1a20 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteLinuxTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteLinuxTest.php @@ -50,7 +50,7 @@ final class RuleInclusionAbsoluteLinuxTest extends TestCase * * @return void */ - public function initializeConfigAndRuleset() + protected function initializeConfigAndRuleset() { $this->standard = __DIR__.'/'.basename(__FILE__, '.php').'.xml'; $repoRootDir = dirname(dirname(dirname(__DIR__))); @@ -84,7 +84,7 @@ public function initializeConfigAndRuleset() * * @return void */ - public function resetRuleset() + protected function resetRuleset() { file_put_contents($this->standard, $this->contents); diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteLinuxTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteLinuxTest.xml index 2978cef9f..d2cb7c3aa 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteLinuxTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteLinuxTest.xml @@ -1,5 +1,5 @@ - + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.php index cba45ee39..fc5d65488 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.php @@ -16,7 +16,9 @@ /** * Tests for the \PHP_CodeSniffer\Ruleset class using a Windows-style absolute path to include a sniff. * - * @covers \PHP_CodeSniffer\Ruleset + * @covers \PHP_CodeSniffer\Ruleset + * @requires OS ^WIN.*. + * @group Windows */ final class RuleInclusionAbsoluteWindowsTest extends TestCase { @@ -50,12 +52,8 @@ final class RuleInclusionAbsoluteWindowsTest extends TestCase * * @return void */ - public function initializeConfigAndRuleset() + protected function initializeConfigAndRuleset() { - if (DIRECTORY_SEPARATOR === '/') { - $this->markTestSkipped('Windows specific test'); - } - $this->standard = __DIR__.'/'.basename(__FILE__, '.php').'.xml'; $repoRootDir = dirname(dirname(dirname(__DIR__))); @@ -83,11 +81,9 @@ public function initializeConfigAndRuleset() * * @return void */ - public function resetRuleset() + protected function resetRuleset() { - if (DIRECTORY_SEPARATOR !== '/') { - file_put_contents($this->standard, $this->contents); - } + file_put_contents($this->standard, $this->contents); }//end resetRuleset() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.xml index e92c68842..8f22b147e 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionAbsoluteWindowsTest.xml @@ -1,5 +1,5 @@ - + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest-include.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest-include.xml index d95af20d9..e13f4b7c2 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest-include.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest-include.xml @@ -1,5 +1,5 @@ - + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest.php index 039c99748..d91a6c259 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest.php @@ -11,15 +11,14 @@ use PHP_CodeSniffer\Ruleset; use PHP_CodeSniffer\Tests\ConfigDouble; -use PHPUnit\Framework\TestCase; -use ReflectionObject; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; /** * Tests for the \PHP_CodeSniffer\Ruleset class. * * @covers \PHP_CodeSniffer\Ruleset */ -final class RuleInclusionTest extends TestCase +final class RuleInclusionTest extends AbstractRulesetTestCase { /** @@ -47,35 +46,37 @@ final class RuleInclusionTest extends TestCase /** * Initialize the config and ruleset objects based on the `RuleInclusionTest.xml` ruleset file. * - * @beforeClass + * @before * * @return void */ - public static function initializeConfigAndRuleset() + protected function initializeConfigAndRuleset() { - $standard = __DIR__.'/'.basename(__FILE__, '.php').'.xml'; - self::$standard = $standard; + if (self::$standard === '') { + $standard = __DIR__.'/'.basename(__FILE__, '.php').'.xml'; + self::$standard = $standard; - // On-the-fly adjust the ruleset test file to be able to test - // sniffs included with relative paths. - $contents = file_get_contents($standard); - self::$contents = $contents; + // On-the-fly adjust the ruleset test file to be able to test + // sniffs included with relative paths. + $contents = file_get_contents($standard); + self::$contents = $contents; - $repoRootDir = basename(dirname(dirname(dirname(__DIR__)))); + $repoRootDir = basename(dirname(dirname(dirname(__DIR__)))); - $newPath = $repoRootDir; - if (DIRECTORY_SEPARATOR === '\\') { - $newPath = str_replace('\\', '/', $repoRootDir); - } + $newPath = $repoRootDir; + if (DIRECTORY_SEPARATOR === '\\') { + $newPath = str_replace('\\', '/', $repoRootDir); + } - $adjusted = str_replace('%path_root_dir%', $newPath, $contents); + $adjusted = str_replace('%path_root_dir%', $newPath, $contents); - if (file_put_contents($standard, $adjusted) === false) { - self::markTestSkipped('On the fly ruleset adjustment failed'); - } + if (file_put_contents($standard, $adjusted) === false) { + self::markTestSkipped('On the fly ruleset adjustment failed'); + } - $config = new ConfigDouble(["--standard=$standard"]); - self::$ruleset = new Ruleset($config); + $config = new ConfigDouble(["--standard=$standard"]); + self::$ruleset = new Ruleset($config); + }//end if }//end initializeConfigAndRuleset() @@ -101,7 +102,7 @@ public function resetRuleset() */ public function testHasSniffCodes() { - $this->assertCount(48, self::$ruleset->sniffCodes); + $this->assertCount(49, self::$ruleset->sniffCodes); }//end testHasSniffCodes() @@ -318,6 +319,10 @@ public static function dataRegisteredSniffCodes() 'Generic.Metrics.CyclomaticComplexity', 'PHP_CodeSniffer\Standards\Generic\Sniffs\Metrics\CyclomaticComplexitySniff', ], + [ + 'Squiz.Files.FileExtension', + 'PHP_CodeSniffer\Standards\Squiz\Sniffs\Files\FileExtensionSniff', + ], [ 'Generic.NamingConventions.CamelCapsFunctionName', 'PHP_CodeSniffer\Standards\Generic\Sniffs\NamingConventions\CamelCapsFunctionNameSniff', @@ -346,10 +351,7 @@ public static function dataRegisteredSniffCodes() public function testSettingProperties($sniffClass, $propertyName, $expectedValue) { $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs); - - $hasProperty = (new ReflectionObject(self::$ruleset->sniffs[$sniffClass]))->hasProperty($propertyName); - $errorMsg = sprintf('Property %s does not exist on sniff class %s', $propertyName, $sniffClass); - $this->assertTrue($hasProperty, $errorMsg); + $this->assertXObjectHasProperty($propertyName, self::$ruleset->sniffs[$sniffClass]); $actualValue = self::$ruleset->sniffs[$sniffClass]->$propertyName; $this->assertSame($expectedValue, $actualValue); @@ -438,12 +440,7 @@ public static function dataSettingProperties() public function testSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFails($sniffClass, $propertyName) { $this->assertArrayHasKey($sniffClass, self::$ruleset->sniffs, 'Sniff class '.$sniffClass.' not listed in registered sniffs'); - - $sniffObject = self::$ruleset->sniffs[$sniffClass]; - - $hasProperty = (new ReflectionObject(self::$ruleset->sniffs[$sniffClass]))->hasProperty($propertyName); - $errorMsg = sprintf('Property %s registered for sniff %s which does not support it', $propertyName, $sniffClass); - $this->assertFalse($hasProperty, $errorMsg); + $this->assertXObjectNotHasProperty($propertyName, self::$ruleset->sniffs[$sniffClass]); }//end testSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFails() @@ -453,7 +450,7 @@ public function testSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFail * * @see self::testSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFails() * - * @return arraystring, string>> + * @return array> */ public static function dataSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFails() { @@ -470,6 +467,10 @@ public static function dataSettingInvalidPropertiesOnStandardsAndCategoriesSilen 'sniffClass' => 'PHP_CodeSniffer\Standards\PSR12\Sniffs\Operators\OperatorSpacingSniff', 'propertyName' => 'setforallincategory', ], + 'Set property for all sniffs in included category directory' => [ + 'sniffClass' => 'PHP_CodeSniffer\Standards\Squiz\Sniffs\Files\FileExtensionSniff', + 'propertyName' => 'setforsquizfilessniffs', + ], ]; }//end dataSettingInvalidPropertiesOnStandardsAndCategoriesSilentlyFails() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest.xml index e1812bbba..0cc4044f5 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/RuleInclusionTest.xml @@ -1,5 +1,5 @@ - + @@ -27,6 +27,14 @@ + + + + + + + + @@ -39,6 +47,7 @@ + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedAsDeclaredTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedAsDeclaredTest.xml index 5840d0c36..12a947dbb 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedAsDeclaredTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedAsDeclaredTest.xml @@ -1,7 +1,7 @@ - + - + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedViaMagicMethodTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedViaMagicMethodTest.xml index 7ff217824..26d556019 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedViaMagicMethodTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedViaMagicMethodTest.xml @@ -1,7 +1,7 @@ - + - + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedViaStdClassTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedViaStdClassTest.xml index 387f419e8..e5f407250 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedViaStdClassTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAllowedViaStdClassTest.xml @@ -1,7 +1,7 @@ - + - + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAppliesPropertyToMultipleSniffsInCategoryTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAppliesPropertyToMultipleSniffsInCategoryTest.xml index 7c4ca4fd3..4563c9c73 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAppliesPropertyToMultipleSniffsInCategoryTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyAppliesPropertyToMultipleSniffsInCategoryTest.xml @@ -1,5 +1,5 @@ - + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategoryTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategoryTest.xml index 979b48f52..c206a06de 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategoryTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategoryTest.xml @@ -1,5 +1,5 @@ - + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForStandardTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForStandardTest.xml index 48a36a831..179cdd461 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForStandardTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForStandardTest.xml @@ -1,7 +1,8 @@ - + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyNotAllowedViaAttributeTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyNotAllowedViaAttributeTest.xml index 7caae3d39..5ff0fd217 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyNotAllowedViaAttributeTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyNotAllowedViaAttributeTest.xml @@ -1,7 +1,7 @@ - + - + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyThrowsErrorOnInvalidPropertyTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyThrowsErrorOnInvalidPropertyTest.xml index 5dca1a010..3646d65d2 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyThrowsErrorOnInvalidPropertyTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetPropertyThrowsErrorOnInvalidPropertyTest.xml @@ -1,5 +1,5 @@ - + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetSniffPropertyTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetSniffPropertyTest.php index 5b0227874..b9d9ac1f2 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetSniffPropertyTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/SetSniffPropertyTest.php @@ -11,7 +11,7 @@ use PHP_CodeSniffer\Ruleset; use PHP_CodeSniffer\Tests\ConfigDouble; -use PHPUnit\Framework\TestCase; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; use ReflectionObject; /** @@ -19,7 +19,7 @@ * * @covers \PHP_CodeSniffer\Ruleset::setSniffProperty */ -final class SetSniffPropertyTest extends TestCase +final class SetSniffPropertyTest extends AbstractRulesetTestCase { @@ -34,8 +34,8 @@ final class SetSniffPropertyTest extends TestCase */ public function testSniffPropertiesGetSetWhenAllowed($name) { - $sniffCode = "Fixtures.SetProperty.{$name}"; - $sniffClass = 'Fixtures\Sniffs\SetProperty\\'.$name.'Sniff'; + $sniffCode = "TestStandard.SetProperty.{$name}"; + $sniffClass = 'Fixtures\TestStandard\Sniffs\SetProperty\\'.$name.'Sniff'; $properties = [ 'arbitrarystring' => 'arbitraryvalue', 'arbitraryarray' => [ @@ -135,20 +135,13 @@ public function testSetPropertyAppliesPropertyToMultipleSniffsInCategory() */ public function testSetPropertyThrowsErrorOnInvalidProperty() { - $exceptionClass = 'PHP_CodeSniffer\Exceptions\RuntimeException'; - $exceptionMsg = 'Ruleset invalid. Property "indentation" does not exist on sniff Generic.Arrays.ArrayIndent'; - if (method_exists($this, 'expectException') === true) { - $this->expectException($exceptionClass); - $this->expectExceptionMessage($exceptionMsg); - } else { - // PHPUnit < 5.2.0. - $this->setExpectedException($exceptionClass, $exceptionMsg); - } + $exceptionMsg = 'ERROR: Property "indentation" does not exist on sniff Generic.Arrays.ArrayIndent.'.PHP_EOL.PHP_EOL; + $this->expectRuntimeExceptionMessage($exceptionMsg); // Set up the ruleset. $standard = __DIR__.'/SetPropertyThrowsErrorOnInvalidPropertyTest.xml'; $config = new ConfigDouble(["--standard=$standard"]); - $ruleset = new Ruleset($config); + new Ruleset($config); }//end testSetPropertyThrowsErrorOnInvalidProperty() @@ -162,20 +155,13 @@ public function testSetPropertyThrowsErrorOnInvalidProperty() */ public function testSetPropertyThrowsErrorWhenPropertyOnlyAllowedViaAttribute() { - $exceptionClass = 'PHP_CodeSniffer\Exceptions\RuntimeException'; - $exceptionMsg = 'Ruleset invalid. Property "arbitrarystring" does not exist on sniff Fixtures.SetProperty.NotAllowedViaAttribute'; - if (method_exists($this, 'expectException') === true) { - $this->expectException($exceptionClass); - $this->expectExceptionMessage($exceptionMsg); - } else { - // PHPUnit < 5.2.0. - $this->setExpectedException($exceptionClass, $exceptionMsg); - } + $exceptionMsg = 'ERROR: Property "arbitrarystring" does not exist on sniff TestStandard.SetProperty.NotAllowedViaAttribute.'.PHP_EOL.PHP_EOL; + $this->expectRuntimeExceptionMessage($exceptionMsg); // Set up the ruleset. $standard = __DIR__.'/SetPropertyNotAllowedViaAttributeTest.xml'; $config = new ConfigDouble(["--standard=$standard"]); - $ruleset = new Ruleset($config); + new Ruleset($config); }//end testSetPropertyThrowsErrorWhenPropertyOnlyAllowedViaAttribute() @@ -193,7 +179,7 @@ public function testSetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForStand // Set up the ruleset. $standard = __DIR__.'/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForStandardTest.xml'; $config = new ConfigDouble(["--standard=$standard"]); - $ruleset = new Ruleset($config); + new Ruleset($config); }//end testSetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForStandard() @@ -211,11 +197,44 @@ public function testSetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCateg // Set up the ruleset. $standard = __DIR__.'/SetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategoryTest.xml'; $config = new ConfigDouble(["--standard=$standard"]); - $ruleset = new Ruleset($config); + new Ruleset($config); }//end testSetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCategory() + /** + * Test that attempting to set a property for a sniff which isn't registered will be ignored. + * + * @return void + */ + public function testDirectCallIgnoredPropertyForUnusedSniff() + { + $sniffCode = 'Generic.Formatting.SpaceAfterCast'; + $sniffClass = 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Formatting\\SpaceAfterCastSniff'; + + // Set up the ruleset. + $config = new ConfigDouble(['--standard=PSR1']); + $ruleset = new Ruleset($config); + + $ruleset->setSniffProperty( + $sniffClass, + 'ignoreNewlines', + [ + 'scope' => 'sniff', + 'value' => true, + ] + ); + + // Verify that there are sniffs registered. + $this->assertGreaterThan(0, count($ruleset->sniffCodes), 'No sniff codes registered'); + + // Verify that our target sniff has NOT been registered after attempting to set the property. + $this->assertArrayNotHasKey($sniffCode, $ruleset->sniffCodes, 'Unused sniff was registered in sniffCodes, but shouldn\'t have been'); + $this->assertArrayNotHasKey($sniffClass, $ruleset->sniffs, 'Unused sniff was registered in sniffs, but shouldn\'t have been'); + + }//end testDirectCallIgnoredPropertyForUnusedSniff() + + /** * Test that setting a property via a direct call to the Ruleset::setSniffProperty() method * sets the property correctly when using the new $settings array format. @@ -225,8 +244,8 @@ public function testSetPropertyDoesNotThrowErrorOnInvalidPropertyWhenSetForCateg public function testDirectCallWithNewArrayFormatSetsProperty() { $name = 'AllowedAsDeclared'; - $sniffCode = "Fixtures.SetProperty.{$name}"; - $sniffClass = 'Fixtures\Sniffs\SetProperty\\'.$name.'Sniff'; + $sniffCode = "TestStandard.SetProperty.{$name}"; + $sniffClass = 'Fixtures\TestStandard\Sniffs\SetProperty\\'.$name.'Sniff'; // Set up the ruleset. $standard = __DIR__."/SetProperty{$name}Test.xml"; @@ -276,8 +295,8 @@ public function testDirectCallWithNewArrayFormatSetsProperty() public function testDirectCallWithOldArrayFormatSetsProperty($propertyValue) { $name = 'AllowedAsDeclared'; - $sniffCode = "Fixtures.SetProperty.{$name}"; - $sniffClass = 'Fixtures\Sniffs\SetProperty\\'.$name.'Sniff'; + $sniffCode = "TestStandard.SetProperty.{$name}"; + $sniffClass = 'Fixtures\TestStandard\Sniffs\SetProperty\\'.$name.'Sniff'; // Set up the ruleset. $standard = __DIR__."/SetProperty{$name}Test.xml"; @@ -383,16 +402,13 @@ public function testDirectCallWithOldArrayFormatThrowsDeprecationNotice() } $name = 'AllowedAsDeclared'; - $sniffCode = "Fixtures.SetProperty.{$name}"; - $sniffClass = 'Fixtures\Sniffs\SetProperty\\'.$name.'Sniff'; + $sniffClass = 'Fixtures\TestStandard\Sniffs\SetProperty\\'.$name.'Sniff'; // Set up the ruleset. $standard = __DIR__."/SetProperty{$name}Test.xml"; $config = new ConfigDouble(["--standard=$standard"]); $ruleset = new Ruleset($config); - $propertyName = 'arbitrarystring'; - $ruleset->setSniffProperty( $sniffClass, 'arbitrarystring', diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsEmptyDeprecationVersionTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsEmptyDeprecationVersionTest.xml index 5e2480bf2..4b7b66608 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsEmptyDeprecationVersionTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsEmptyDeprecationVersionTest.xml @@ -1,8 +1,8 @@ - + - + - + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsEmptyRemovalVersionTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsEmptyRemovalVersionTest.xml index 6e667375a..d22ec24e6 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsEmptyRemovalVersionTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsEmptyRemovalVersionTest.xml @@ -1,8 +1,8 @@ - + - + - + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationMessageTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationMessageTest.xml index d32516799..fb80426f3 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationMessageTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationMessageTest.xml @@ -1,8 +1,8 @@ - + - + - + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationVersionTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationVersionTest.xml index 89d83ab52..2a8aedd74 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationVersionTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidDeprecationVersionTest.xml @@ -1,8 +1,8 @@ - + - + - + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidRemovalVersionTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidRemovalVersionTest.xml index c1eb062e1..6a16178b5 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidRemovalVersionTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsInvalidRemovalVersionTest.xml @@ -1,8 +1,8 @@ - + - + - + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsOrderTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsOrderTest.xml index 3ce96ce89..9c4ce1b6e 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsOrderTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsOrderTest.xml @@ -1,10 +1,10 @@ - + - + - - + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsReportWidthTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsReportWidthTest.xml index 9f1cc8515..c198d684d 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsReportWidthTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsReportWidthTest.xml @@ -1,8 +1,8 @@ - + - + - + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsTest.php index 8e81f96a2..db793fdeb 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsTest.php @@ -11,7 +11,7 @@ use PHP_CodeSniffer\Ruleset; use PHP_CodeSniffer\Tests\ConfigDouble; -use PHPUnit\Framework\TestCase; +use PHP_CodeSniffer\Tests\Core\Ruleset\AbstractRulesetTestCase; /** * Tests PHPCS native handling of sniff deprecations. @@ -19,7 +19,7 @@ * @covers \PHP_CodeSniffer\Ruleset::hasSniffDeprecations * @covers \PHP_CodeSniffer\Ruleset::showSniffDeprecations */ -final class ShowSniffDeprecationsTest extends TestCase +final class ShowSniffDeprecationsTest extends AbstractRulesetTestCase { @@ -67,7 +67,7 @@ public static function dataHasSniffDeprecations() /** - * Test that the listing with deprecated sniffs will not show when specific command-line options are being used. + * Test that the listing with deprecated sniffs will not show when specific command-line options are being used [1]. * * @param string $standard The standard to use for the test. * @param array $additionalArgs Optional. Additional arguments to pass. @@ -102,24 +102,62 @@ public function testDeprecatedSniffsListDoesNotShow($standard, $additionalArgs=[ public static function dataDeprecatedSniffsListDoesNotShow() { return [ - 'Standard not using deprecated sniffs: PSR1' => [ + 'Standard not using deprecated sniffs: PSR1' => [ 'standard' => 'PSR1', ], - 'Standard using deprecated sniffs; explain mode' => [ + 'Standard using deprecated sniffs; explain mode' => [ 'standard' => __DIR__.'/ShowSniffDeprecationsTest.xml', 'additionalArgs' => ['-e'], ], - 'Standard using deprecated sniffs; quiet mode' => [ + 'Standard using deprecated sniffs; quiet mode' => [ 'standard' => __DIR__.'/ShowSniffDeprecationsTest.xml', 'additionalArgs' => ['-q'], ], + ]; + + }//end dataDeprecatedSniffsListDoesNotShow() + + + /** + * Test that the listing with deprecated sniffs will not show when specific command-line options are being used [2]. + * + * {@internal Separate test method for the same thing as this test will only work in CS mode.} + * + * @param string $standard The standard to use for the test. + * @param array $additionalArgs Optional. Additional arguments to pass. + * + * @dataProvider dataDeprecatedSniffsListDoesNotShowNeedsCsMode + * + * @return void + */ + public function testDeprecatedSniffsListDoesNotShowNeedsCsMode($standard, $additionalArgs=[]) + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $this->testDeprecatedSniffsListDoesNotShow($standard, $additionalArgs); + + }//end testDeprecatedSniffsListDoesNotShowNeedsCsMode() + + + /** + * Data provider. + * + * @see testDeprecatedSniffsListDoesNotShowNeedsCsMode() + * + * @return array>> + */ + public static function dataDeprecatedSniffsListDoesNotShowNeedsCsMode() + { + return [ 'Standard using deprecated sniffs; documentation is requested' => [ 'standard' => __DIR__.'/ShowSniffDeprecationsTest.xml', 'additionalArgs' => ['--generator=text'], ], ]; - }//end dataDeprecatedSniffsListDoesNotShow() + }//end dataDeprecatedSniffsListDoesNotShowNeedsCsMode() /** @@ -141,12 +179,12 @@ public function testDeprecatedSniffsListDoesNotShowWhenSelectedSniffsAreNotDepre $restrictions = []; $sniffs = [ - 'Fixtures.SetProperty.AllowedAsDeclared', - 'Fixtures.SetProperty.AllowedViaStdClass', + 'TestStandard.SetProperty.AllowedAsDeclared', + 'TestStandard.SetProperty.AllowedViaStdClass', ]; foreach ($sniffs as $sniffCode) { $parts = explode('.', strtolower($sniffCode)); - $sniffName = $parts[0].'\sniffs\\'.$parts[1].'\\'.$parts[2].'sniff'; + $sniffName = $parts[0].'\\sniffs\\'.$parts[1].'\\'.$parts[2].'sniff'; $restrictions[strtolower($sniffName)] = true; } @@ -158,7 +196,7 @@ public function testDeprecatedSniffsListDoesNotShowWhenSelectedSniffsAreNotDepre $sniffFiles[] = $sniffFile; } - $ruleset->registerSniffs($allSniffs, $restrictions, []); + $ruleset->registerSniffs($sniffFiles, $restrictions, []); $ruleset->populateTokenListeners(); $this->expectOutputString(''); @@ -187,15 +225,15 @@ public function testDeprecatedSniffsListDoesNotShowWhenAllDeprecatedSniffsAreExc $exclusions = []; $exclude = [ - 'Fixtures.Deprecated.WithLongReplacement', - 'Fixtures.Deprecated.WithoutReplacement', - 'Fixtures.Deprecated.WithReplacement', - 'Fixtures.Deprecated.WithReplacementContainingLinuxNewlines', - 'Fixtures.Deprecated.WithReplacementContainingNewlines', + 'TestStandard.Deprecated.WithLongReplacement', + 'TestStandard.Deprecated.WithoutReplacement', + 'TestStandard.Deprecated.WithReplacement', + 'TestStandard.Deprecated.WithReplacementContainingLinuxNewlines', + 'TestStandard.Deprecated.WithReplacementContainingNewlines', ]; foreach ($exclude as $sniffCode) { $parts = explode('.', strtolower($sniffCode)); - $sniffName = $parts[0].'\sniffs\\'.$parts[1].'\\'.$parts[2].'sniff'; + $sniffName = $parts[0].'\\sniffs\\'.$parts[1].'\\'.$parts[2].'sniff'; $exclusions[strtolower($sniffName)] = true; } @@ -207,7 +245,7 @@ public function testDeprecatedSniffsListDoesNotShowWhenAllDeprecatedSniffsAreExc $sniffFiles[] = $sniffFile; } - $ruleset->registerSniffs($allSniffs, [], $exclusions); + $ruleset->registerSniffs($sniffFiles, [], $exclusions); $ruleset->populateTokenListeners(); $this->expectOutputString(''); @@ -218,7 +256,7 @@ public function testDeprecatedSniffsListDoesNotShowWhenAllDeprecatedSniffsAreExc /** - * Test deprecated sniffs are listed alphabetically in the deprecated sniffs warning. + * Test various aspects of the deprecated sniffs warning. * * This tests a number of different aspects: * 1. That the summary line uses the correct grammar when there is are multiple deprecated sniffs. @@ -234,9 +272,9 @@ public function testDeprecatedSniffsWarning() $config = new ConfigDouble(["--standard=$standard", '--no-colors']); $ruleset = new Ruleset($config); - $expected = 'WARNING: The SniffDeprecationTest standard uses 5 deprecated sniffs'.PHP_EOL; + $expected = 'WARNING: The ShowSniffDeprecationsTest standard uses 5 deprecated sniffs'.PHP_EOL; $expected .= '--------------------------------------------------------------------------------'.PHP_EOL; - $expected .= '- Fixtures.Deprecated.WithLongReplacement'.PHP_EOL; + $expected .= '- TestStandard.Deprecated.WithLongReplacement'.PHP_EOL; $expected .= ' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL; $expected .= ' Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vel'.PHP_EOL; $expected .= ' vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium sed.'.PHP_EOL; @@ -247,12 +285,12 @@ public function testDeprecatedSniffsWarning() $expected .= ' dictum. Suspendisse dictum egestas sapien, eget ullamcorper metus elementum'.PHP_EOL; $expected .= ' semper. Vestibulum sem justo, consectetur ac tincidunt et, finibus eget'.PHP_EOL; $expected .= ' libero.'.PHP_EOL; - $expected .= '- Fixtures.Deprecated.WithoutReplacement'.PHP_EOL; + $expected .= '- TestStandard.Deprecated.WithoutReplacement'.PHP_EOL; $expected .= ' This sniff has been deprecated since v3.4.0 and will be removed in v4.0.0.'.PHP_EOL; - $expected .= '- Fixtures.Deprecated.WithReplacement'.PHP_EOL; + $expected .= '- TestStandard.Deprecated.WithReplacement'.PHP_EOL; $expected .= ' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL; $expected .= ' Use the Stnd.Category.OtherSniff sniff instead.'.PHP_EOL; - $expected .= '- Fixtures.Deprecated.WithReplacementContainingLinuxNewlines'.PHP_EOL; + $expected .= '- TestStandard.Deprecated.WithReplacementContainingLinuxNewlines'.PHP_EOL; $expected .= ' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL; $expected .= ' Lorem ipsum dolor sit amet, consectetur adipiscing elit.'.PHP_EOL; $expected .= ' Fusce vel vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium'.PHP_EOL; @@ -262,7 +300,7 @@ public function testDeprecatedSniffsWarning() $expected .= ' eros sapien at sem.'.PHP_EOL; $expected .= ' Sed pulvinar aliquam malesuada. Aliquam erat volutpat. Mauris gravida rutrum'.PHP_EOL; $expected .= ' lectus at egestas.'.PHP_EOL; - $expected .= '- Fixtures.Deprecated.WithReplacementContainingNewlines'.PHP_EOL; + $expected .= '- TestStandard.Deprecated.WithReplacementContainingNewlines'.PHP_EOL; $expected .= ' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL; $expected .= ' Lorem ipsum dolor sit amet, consectetur adipiscing elit.'.PHP_EOL; $expected .= ' Fusce vel vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium'.PHP_EOL; @@ -283,7 +321,7 @@ public function testDeprecatedSniffsWarning() /** - * Test deprecated sniffs are listed alphabetically in the deprecated sniffs warning. + * Test the report width is respected when displaying the deprecated sniffs warning. * * This tests the following aspects: * 1. That the summary line uses the correct grammar when there is a single deprecated sniff. @@ -321,16 +359,16 @@ public function testReportWidthIsRespected($reportWidth, $expectedOutput) */ public static function dataReportWidthIsRespected() { - $summaryLine = 'WARNING: The SniffDeprecationTest standard uses 1 deprecated sniff'.PHP_EOL; + $summaryLine = 'WARNING: The ShowSniffDeprecationsTest standard uses 1 deprecated sniff'.PHP_EOL; // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Test readability is more important. return [ 'Report width small: 40; with truncated sniff name and wrapped header and footer lines' => [ 'reportWidth' => 40, - 'expectedOutput' => 'WARNING: The SniffDeprecationTest'.PHP_EOL + 'expectedOutput' => 'WARNING: The ShowSniffDeprecationsTest'.PHP_EOL .'standard uses 1 deprecated sniff'.PHP_EOL .'----------------------------------------'.PHP_EOL - .'- Fixtures.Deprecated.WithLongRepla...'.PHP_EOL + .'- TestStandard.Deprecated.WithLongR...'.PHP_EOL .' This sniff has been deprecated since'.PHP_EOL .' v3.8.0 and will be removed in'.PHP_EOL .' v4.0.0. Lorem ipsum dolor sit amet,'.PHP_EOL @@ -358,7 +396,7 @@ public static function dataReportWidthIsRespected() 'Report width default: 80' => [ 'reportWidth' => 80, 'expectedOutput' => $summaryLine.str_repeat('-', 80).PHP_EOL - .'- Fixtures.Deprecated.WithLongReplacement'.PHP_EOL + .'- TestStandard.Deprecated.WithLongReplacement'.PHP_EOL .' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL .' Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vel'.PHP_EOL .' vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium sed.'.PHP_EOL @@ -376,7 +414,7 @@ public static function dataReportWidthIsRespected() // Length = 4 padding + 75 base line + 587 custom message. 'reportWidth' => 666, 'expectedOutput' => $summaryLine.str_repeat('-', 666).PHP_EOL - .'- Fixtures.Deprecated.WithLongReplacement'.PHP_EOL + .'- TestStandard.Deprecated.WithLongReplacement'.PHP_EOL .' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vel vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium sed. Fusce egestas congue massa semper cursus. Donec quis pretium tellus. In lacinia, augue ut ornare porttitor, diam nunc faucibus purus, et accumsan eros sapien at sem. Sed pulvinar aliquam malesuada. Aliquam erat volutpat. Mauris gravida rutrum lectus at egestas. Fusce tempus elit in tincidunt dictum. Suspendisse dictum egestas sapien, eget ullamcorper metus elementum semper. Vestibulum sem justo, consectetur ac tincidunt et, finibus eget libero.' .PHP_EOL.PHP_EOL .'Deprecated sniffs are still run, but will stop working at some point in the future.'.PHP_EOL.PHP_EOL, @@ -384,7 +422,7 @@ public static function dataReportWidthIsRespected() 'Report width wide: 1000; delimiter line length should match longest line' => [ 'reportWidth' => 1000, 'expectedOutput' => $summaryLine.str_repeat('-', 666).PHP_EOL - .'- Fixtures.Deprecated.WithLongReplacement'.PHP_EOL + .'- TestStandard.Deprecated.WithLongReplacement'.PHP_EOL .' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vel vestibulum nunc. Sed luctus dolor tortor, eu euismod purus pretium sed. Fusce egestas congue massa semper cursus. Donec quis pretium tellus. In lacinia, augue ut ornare porttitor, diam nunc faucibus purus, et accumsan eros sapien at sem. Sed pulvinar aliquam malesuada. Aliquam erat volutpat. Mauris gravida rutrum lectus at egestas. Fusce tempus elit in tincidunt dictum. Suspendisse dictum egestas sapien, eget ullamcorper metus elementum semper. Vestibulum sem justo, consectetur ac tincidunt et, finibus eget libero.' .PHP_EOL.PHP_EOL .'Deprecated sniffs are still run, but will stop working at some point in the future.'.PHP_EOL.PHP_EOL, @@ -409,11 +447,11 @@ public function testDeprecatedSniffsAreListedAlphabetically() $config = new ConfigDouble(["--standard=$standard", '--no-colors']); $ruleset = new Ruleset($config); - $expected = 'WARNING: The SniffDeprecationTest standard uses 2 deprecated sniffs'.PHP_EOL; + $expected = 'WARNING: The ShowSniffDeprecationsTest standard uses 2 deprecated sniffs'.PHP_EOL; $expected .= '--------------------------------------------------------------------------------'.PHP_EOL; - $expected .= '- Fixtures.Deprecated.WithoutReplacement'.PHP_EOL; + $expected .= '- TestStandard.Deprecated.WithoutReplacement'.PHP_EOL; $expected .= ' This sniff has been deprecated since v3.4.0 and will be removed in v4.0.0.'.PHP_EOL; - $expected .= '- Fixtures.Deprecated.WithReplacement'.PHP_EOL; + $expected .= '- TestStandard.Deprecated.WithReplacement'.PHP_EOL; $expected .= ' This sniff has been deprecated since v3.8.0 and will be removed in v4.0.0.'.PHP_EOL; $expected .= ' Use the Stnd.Category.OtherSniff sniff instead.'.PHP_EOL.PHP_EOL; $expected .= 'Deprecated sniffs are still run, but will stop working at some point in the'.PHP_EOL; @@ -426,12 +464,12 @@ public function testDeprecatedSniffsAreListedAlphabetically() // Verify that the sniffs have been registered to run. $this->assertCount(2, $ruleset->sniffCodes, 'Incorrect number of sniff codes registered'); $this->assertArrayHasKey( - 'Fixtures.Deprecated.WithoutReplacement', + 'TestStandard.Deprecated.WithoutReplacement', $ruleset->sniffCodes, 'WithoutReplacement sniff not registered' ); $this->assertArrayHasKey( - 'Fixtures.Deprecated.WithReplacement', + 'TestStandard.Deprecated.WithReplacement', $ruleset->sniffCodes, 'WithReplacement sniff not registered' ); @@ -452,15 +490,7 @@ public function testDeprecatedSniffsAreListedAlphabetically() */ public function testExceptionIsThrownOnIncorrectlyImplementedInterface($standard, $exceptionMessage) { - $exception = 'PHP_CodeSniffer\Exceptions\RuntimeException'; - if (method_exists($this, 'expectException') === true) { - // PHPUnit 5+. - $this->expectException($exception); - $this->expectExceptionMessage($exceptionMessage); - } else { - // PHPUnit 4. - $this->setExpectedException($exception, $exceptionMessage); - } + $this->expectRuntimeExceptionMessage($exceptionMessage); // Set up the ruleset. $standard = __DIR__.'/'.$standard; @@ -484,23 +514,23 @@ public static function dataExceptionIsThrownOnIncorrectlyImplementedInterface() return [ 'getDeprecationVersion() does not return a string' => [ 'standard' => 'ShowSniffDeprecationsInvalidDeprecationVersionTest.xml', - 'exceptionMessage' => 'The Fixtures\Sniffs\DeprecatedInvalid\InvalidDeprecationVersionSniff::getDeprecationVersion() method must return a non-empty string, received double', + 'exceptionMessage' => 'ERROR: The Fixtures\TestStandard\Sniffs\DeprecatedInvalid\InvalidDeprecationVersionSniff::getDeprecationVersion() method must return a non-empty string, received double', ], 'getRemovalVersion() does not return a string' => [ 'standard' => 'ShowSniffDeprecationsInvalidRemovalVersionTest.xml', - 'exceptionMessage' => 'The Fixtures\Sniffs\DeprecatedInvalid\InvalidRemovalVersionSniff::getRemovalVersion() method must return a non-empty string, received array', + 'exceptionMessage' => 'ERROR: The Fixtures\TestStandard\Sniffs\DeprecatedInvalid\InvalidRemovalVersionSniff::getRemovalVersion() method must return a non-empty string, received array', ], 'getDeprecationMessage() does not return a string' => [ 'standard' => 'ShowSniffDeprecationsInvalidDeprecationMessageTest.xml', - 'exceptionMessage' => 'The Fixtures\Sniffs\DeprecatedInvalid\InvalidDeprecationMessageSniff::getDeprecationMessage() method must return a string, received object', + 'exceptionMessage' => 'ERROR: The Fixtures\TestStandard\Sniffs\DeprecatedInvalid\InvalidDeprecationMessageSniff::getDeprecationMessage() method must return a string, received object', ], 'getDeprecationVersion() returns an empty string' => [ 'standard' => 'ShowSniffDeprecationsEmptyDeprecationVersionTest.xml', - 'exceptionMessage' => 'The Fixtures\Sniffs\DeprecatedInvalid\EmptyDeprecationVersionSniff::getDeprecationVersion() method must return a non-empty string, received ""', + 'exceptionMessage' => 'ERROR: The Fixtures\TestStandard\Sniffs\DeprecatedInvalid\EmptyDeprecationVersionSniff::getDeprecationVersion() method must return a non-empty string, received ""', ], 'getRemovalVersion() returns an empty string' => [ 'standard' => 'ShowSniffDeprecationsEmptyRemovalVersionTest.xml', - 'exceptionMessage' => 'The Fixtures\Sniffs\DeprecatedInvalid\EmptyRemovalVersionSniff::getRemovalVersion() method must return a non-empty string, received ""', + 'exceptionMessage' => 'ERROR: The Fixtures\TestStandard\Sniffs\DeprecatedInvalid\EmptyRemovalVersionSniff::getRemovalVersion() method must return a non-empty string, received ""', ], ]; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsTest.xml b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsTest.xml index 4c1dec220..91bef9684 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsTest.xml +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Ruleset/ShowSniffDeprecationsTest.xml @@ -1,10 +1,14 @@ - + - + - - + + + + + + diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Runner/AbstractRunnerTestCase.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Runner/AbstractRunnerTestCase.php new file mode 100644 index 000000000..ae5905bc6 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Runner/AbstractRunnerTestCase.php @@ -0,0 +1,19 @@ +markTestSkipped('This test needs CS mode to run'); + } + + $this->checkProgressDot($colors, $code, $sniffs, $expected); + + }//end testProgressDotCs() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataProgressDotCs() + { + return [ + 'No colors: Dot: no errors, no warnings' => [ + 'colors' => false, + 'code' => ' 'Generic.PHP.LowerCaseConstant', + 'expected' => '.', + ], + 'No colors: E: has error' => [ + 'colors' => false, + 'code' => ' 'Generic.CodeAnalysis.RequireExplicitBooleanOperatorPrecedence', + 'expected' => 'E', + ], + 'No colors: W: has warning' => [ + 'colors' => false, + 'code' => ' 'Generic.Commenting.Todo', + 'expected' => 'W', + ], + + 'Colors: Dot: no errors, no warnings' => [ + 'colors' => true, + 'code' => ' 'Generic.PHP.LowerCaseConstant', + 'expected' => '.', + ], + 'Colors: E: has error (red)' => [ + 'colors' => true, + 'code' => ' 'Generic.CodeAnalysis.RequireExplicitBooleanOperatorPrecedence', + 'expected' => "\033[31m".'E'."\033[0m", + ], + 'Colors: E: has fixable error (green)' => [ + 'colors' => true, + 'code' => ' 'Generic.Arrays.DisallowLongArraySyntax', + 'expected' => "\033[32m".'E'."\033[0m", + ], + 'Colors: W: has warning (yellow)' => [ + 'colors' => true, + 'code' => ' 'Generic.Commenting.Todo', + 'expected' => "\033[33m".'W'."\033[0m", + ], + 'Colors: W: has fixable warning (green)' => [ + 'colors' => true, + 'code' => ' 'Generic.CodeAnalysis.EmptyPHPStatement', + 'expected' => "\033[32m".'W'."\033[0m", + ], + ]; + + }//end dataProgressDotCs() + + + /** + * Verify the correct progress indicator is used for a file in CBF mode. + * + * @param bool $colors Whether to enable colors or not. + * @param string $code Code snippet to process. + * @param string $sniffs Comma-separated list of sniff(s) to run against the code snippet. + * @param string $expected Expected output of the progress printer. + * + * @dataProvider dataProgressDotCbf + * + * @group CBF + * + * @return void + */ + public function testProgressDotCbf($colors, $code, $sniffs, $expected) + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $this->checkProgressDot($colors, $code, $sniffs, $expected, true); + + }//end testProgressDotCbf() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataProgressDotCbf() + { + return [ + 'No colors: Dot: no errors, no warnings' => [ + 'colors' => false, + 'code' => ' 'Generic.PHP.LowerCaseConstant', + 'expected' => '.', + ], + 'No colors: F: fixes made' => [ + 'colors' => false, + 'code' => ' 'Generic.Arrays.DisallowLongArraySyntax', + 'expected' => 'F', + ], + 'No colors: E: has fixer conflict' => [ + 'colors' => false, + 'code' => ' 'Generic.Arrays.DisallowLongArraySyntax,Generic.Arrays.DisallowShortArraySyntax', + 'expected' => 'E', + ], + + 'Colors: Dot: no errors, no warnings (no color)' => [ + 'colors' => true, + 'code' => ' 'Generic.PHP.LowerCaseConstant', + 'expected' => '.', + ], + 'Colors: F: fixes made (green)' => [ + 'colors' => true, + 'code' => ' 'Generic.Arrays.DisallowLongArraySyntax', + 'expected' => "\033[32m".'F'."\033[0m", + ], + 'Colors: E: has fixer conflict (red)' => [ + 'colors' => true, + 'code' => ' 'Generic.Arrays.DisallowLongArraySyntax,Generic.Arrays.DisallowShortArraySyntax', + 'expected' => "\033[31m".'E'."\033[0m", + ], + ]; + + }//end dataProgressDotCbf() + + + /** + * Verify the correct progress indicator is used for a file in CBF mode. + * + * @param bool $colors Whether to enable colors or not. + * @param string $code Code snippet to process. + * @param string $sniffs Comma-separated list of sniff(s) to run against the code snippet. + * @param string $expected Expected output of the progress printer. + * @param bool $enableFixer Whether to fix the code or not. + * + * @return void + */ + private function checkProgressDot($colors, $code, $sniffs, $expected, $enableFixer=false) + { + $this->expectOutputString($expected); + + $config = new ConfigDouble(['-p']); + $config->colors = $colors; + $config->standards = ['Generic']; + $config->sniffs = explode(',', $sniffs); + $ruleset = new Ruleset($config); + + $runner = new Runner(); + $runner->config = $config; + + $file = new DummyFile($code, $ruleset, $config); + $file->process(); + + if ($enableFixer === true) { + $file->fixer->fixFile(); + } + + $runner->printProgress($file, 2, 1); + + }//end checkProgressDot() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Runner/PrintProgressTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Runner/PrintProgressTest.php new file mode 100644 index 000000000..93535417e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Runner/PrintProgressTest.php @@ -0,0 +1,235 @@ +standards = ['Generic']; + self::$config->sniffs = ['Generic.PHP.LowerCaseConstant']; + self::$ruleset = new Ruleset(self::$config); + + self::$runner = new Runner(); + self::$runner->config = self::$config; + + // Simple file which won't have any errors against the above sniff. + $content = 'process(); + + }//end initializeConfigRulesetRunner() + + + /** + * Reset some flags between tests. + * + * @after + * + * @return void + */ + protected function resetObjectFlags() + { + self::$config->showProgress = true; + self::$fileWithoutErrorsOrWarnings->ignored = false; + + }//end resetObjectFlags() + + + /** + * Destroy the Config object after the test to reset statics. + * + * @afterClass + * + * @return void + */ + public static function reset() + { + // Explicitly trigger __destruct() on the ConfigDouble to reset the Config statics. + // The explicit method call prevents potential stray test-local references to the $config object + // preventing the destructor from running the clean up (which without stray references would be + // automagically triggered when this object is destroyed, but we can't definitively rely on that). + self::$config->__destruct(); + + }//end reset() + + + /** + * Verify that if progress reporting is disabled, no progress dots will show. + * + * @return void + */ + public function testNoProgressIsShownWhenDisabled() + { + $this->expectOutputString(''); + + self::$config->showProgress = false; + + for ($i = 1; $i <= 10; $i++) { + self::$runner->printProgress(self::$fileWithoutErrorsOrWarnings, 3, $i); + } + + }//end testNoProgressIsShownWhenDisabled() + + + /** + * Verify ignored files will be marked with an "S" for "skipped". + * + * @return void + */ + public function testProgressDotSkippedFiles() + { + $nrOfFiles = 10; + $this->expectOutputString('.S.S.S.S.S 10 / 10 (100%)'.PHP_EOL); + + for ($i = 1; $i <= $nrOfFiles; $i++) { + if (($i % 2) === 0) { + self::$fileWithoutErrorsOrWarnings->ignored = true; + } else { + self::$fileWithoutErrorsOrWarnings->ignored = false; + } + + self::$runner->printProgress(self::$fileWithoutErrorsOrWarnings, $nrOfFiles, $i); + } + + }//end testProgressDotSkippedFiles() + + + /** + * Verify the handling of the summary at the end of each line. + * + * @param int $nrOfFiles The number of files in the scan. + * @param string $expected The expected progress information output. + * + * @dataProvider dataEndOfLineSummary + * + * @return void + */ + public function testEndOfLineSummary($nrOfFiles, $expected) + { + $this->expectOutputString($expected); + + for ($i = 1; $i <= $nrOfFiles; $i++) { + self::$runner->printProgress(self::$fileWithoutErrorsOrWarnings, $nrOfFiles, $i); + } + + }//end testEndOfLineSummary() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataEndOfLineSummary() + { + $fullLineOfDots = str_repeat('.', 60); + + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Favour test readability. + return [ + 'Less than 60 files (23)' => [ + 'nrOfFiles' => 23, + 'expected' => str_repeat('.', 23).' 23 / 23 (100%)'.PHP_EOL, + ], + 'Exactly 60 files' => [ + 'nrOfFiles' => 60, + 'expected' => $fullLineOfDots.' 60 / 60 (100%)'.PHP_EOL, + ], + 'Between 60 and 120 files (71)' => [ + 'nrOfFiles' => 71, + 'expected' => $fullLineOfDots.' 60 / 71 (85%)'.PHP_EOL + .str_repeat('.', 11).str_repeat(' ', 49).' 71 / 71 (100%)'.PHP_EOL, + ], + 'More than 120 files (162)' => [ + 'nrOfFiles' => 162, + 'expected' => $fullLineOfDots.' 60 / 162 (37%)'.PHP_EOL + .$fullLineOfDots.' 120 / 162 (74%)'.PHP_EOL + .str_repeat('.', 42).str_repeat(' ', 18).' 162 / 162 (100%)'.PHP_EOL, + ], + // More than anything, this tests that the padding of the numbers is handled correctly. + 'More than 1000 files (1234)' => [ + 'nrOfFiles' => 1234, + 'expected' => $fullLineOfDots.' 60 / 1234 (5%)'.PHP_EOL + .$fullLineOfDots.' 120 / 1234 (10%)'.PHP_EOL + .$fullLineOfDots.' 180 / 1234 (15%)'.PHP_EOL + .$fullLineOfDots.' 240 / 1234 (19%)'.PHP_EOL + .$fullLineOfDots.' 300 / 1234 (24%)'.PHP_EOL + .$fullLineOfDots.' 360 / 1234 (29%)'.PHP_EOL + .$fullLineOfDots.' 420 / 1234 (34%)'.PHP_EOL + .$fullLineOfDots.' 480 / 1234 (39%)'.PHP_EOL + .$fullLineOfDots.' 540 / 1234 (44%)'.PHP_EOL + .$fullLineOfDots.' 600 / 1234 (49%)'.PHP_EOL + .$fullLineOfDots.' 660 / 1234 (53%)'.PHP_EOL + .$fullLineOfDots.' 720 / 1234 (58%)'.PHP_EOL + .$fullLineOfDots.' 780 / 1234 (63%)'.PHP_EOL + .$fullLineOfDots.' 840 / 1234 (68%)'.PHP_EOL + .$fullLineOfDots.' 900 / 1234 (73%)'.PHP_EOL + .$fullLineOfDots.' 960 / 1234 (78%)'.PHP_EOL + .$fullLineOfDots.' 1020 / 1234 (83%)'.PHP_EOL + .$fullLineOfDots.' 1080 / 1234 (88%)'.PHP_EOL + .$fullLineOfDots.' 1140 / 1234 (92%)'.PHP_EOL + .$fullLineOfDots.' 1200 / 1234 (97%)'.PHP_EOL + .str_repeat('.', 34).str_repeat(' ', 26).' 1234 / 1234 (100%)'.PHP_EOL, + ], + ]; + // phpcs:enable + + }//end dataEndOfLineSummary() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Runner/RunPHPCSExplainTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Runner/RunPHPCSExplainTest.php new file mode 100644 index 000000000..479fe5ce9 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Runner/RunPHPCSExplainTest.php @@ -0,0 +1,73 @@ + + * @copyright 2023 Juliette Reinders Folmer. All rights reserved. + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Runner; + +use PHP_CodeSniffer\Runner; +use PHP_CodeSniffer\Tests\Core\Runner\AbstractRunnerTestCase; + +/** + * Tests the wiring in of the explain functionality in the Runner class. + * + * @covers \PHP_CodeSniffer\Runner::runPHPCS + */ +final class RunPHPCSExplainTest extends AbstractRunnerTestCase +{ + + + /** + * Test that each standard passed on the command-line is explained separately. + * + * @return void + */ + public function testExplainWillExplainEachStandardSeparately() + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $standard = dirname(__DIR__).'/Ruleset/ExplainSingleSniffTest.xml'; + $_SERVER['argv'] = [ + 'phpcs', + '-e', + "--standard=PSR1,$standard", + '--report-width=80', + ]; + + $expected = PHP_EOL; + $expected .= 'The PSR1 standard contains 8 sniffs'.PHP_EOL.PHP_EOL; + $expected .= 'Generic (4 sniffs)'.PHP_EOL; + $expected .= '------------------'.PHP_EOL; + $expected .= ' Generic.Files.ByteOrderMark'.PHP_EOL; + $expected .= ' Generic.NamingConventions.UpperCaseConstantName'.PHP_EOL; + $expected .= ' Generic.PHP.DisallowAlternativePHPTags'.PHP_EOL; + $expected .= ' Generic.PHP.DisallowShortOpenTag'.PHP_EOL.PHP_EOL; + $expected .= 'PSR1 (3 sniffs)'.PHP_EOL; + $expected .= '---------------'.PHP_EOL; + $expected .= ' PSR1.Classes.ClassDeclaration'.PHP_EOL; + $expected .= ' PSR1.Files.SideEffects'.PHP_EOL; + $expected .= ' PSR1.Methods.CamelCapsMethodName'.PHP_EOL.PHP_EOL; + $expected .= 'Squiz (1 sniff)'.PHP_EOL; + $expected .= '---------------'.PHP_EOL; + $expected .= ' Squiz.Classes.ValidClassName'.PHP_EOL.PHP_EOL; + + $expected .= 'The ExplainSingleSniffTest standard contains 1 sniff'.PHP_EOL.PHP_EOL; + $expected .= 'Squiz (1 sniff)'.PHP_EOL; + $expected .= '---------------'.PHP_EOL; + $expected .= ' Squiz.Scope.MethodScope'.PHP_EOL; + + $this->expectOutputString($expected); + + $runner = new Runner(); + $runner->runPHPCS(); + + }//end testExplainWillExplainEachStandardSeparately() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Runner/RunPHPCSGeneratorTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Runner/RunPHPCSGeneratorTest.php new file mode 100644 index 000000000..0bc89f220 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Runner/RunPHPCSGeneratorTest.php @@ -0,0 +1,72 @@ +markTestSkipped('This test needs CS mode to run'); + } + + $standard = dirname(__DIR__).'/Generators/OneDocTest.xml'; + $_SERVER['argv'] = [ + 'phpcs', + '--generator=Text', + "--standard=$standard,PSR1", + '--report-width=80', + ]; + + $regex = '`^ + \R* # Optional blank line at the start. + (?: + (?P-++\R) # Line with dashes. + \|[ ]GENERATORTEST[ ]CODING[ ]STANDARD:[ ][^\|]+\|\R # Doc title line with prefix expected for first standard. + (?P>delimiter) # Line with dashes. + \R(?:[^\r\n]+\R)+\R{2} # Standard description. + ) # Only expect this group once. + (?: + (?P>delimiter) # Line with dashes. + \|[ ]PSR1[ ]CODING[ ]STANDARD:[ ][^\|]+\|\R # Doc title line with prefix expected for second standard. + (?P>delimiter) # Line with dashes. + \R(?:[^\r\n]+\R)+\R # Standard description. + (?: + -+[ ]CODE[ ]COMPARISON[ ]-+\R # Code Comparison starter line with dashes. + (?:(?:[^\r\n]+\R)+(?P>delimiter)){2} # Arbitrary text followed by a delimiter line. + )* # Code comparison is optional and can exist multiple times. + \R+ + ){3,} # This complete group should occur at least three times. + `x'; + + $this->expectOutputRegex($regex); + + $runner = new Runner(); + $runner->runPHPCS(); + + }//end testGeneratorWillShowEachStandardSeparately() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Sniffs/AbstractArraySniffTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Sniffs/AbstractArraySniffTest.php index f074d9500..993603a53 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Sniffs/AbstractArraySniffTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Sniffs/AbstractArraySniffTest.php @@ -25,7 +25,7 @@ final class AbstractArraySniffTest extends AbstractMethodUnitTest * This extends the \PHP_CodeSniffer\Sniffs\AbstractArraySniff class to make the * internal workings of the sniff observable. * - * @var \PHP_CodeSniffer\Sniffs\AbstractArraySniffTestable + * @var \PHP_CodeSniffer\Tests\Core\Sniffs\AbstractArraySniffTestable */ protected static $sniff; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Standards/StandardRulesetsQATest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Standards/StandardRulesetsQATest.php new file mode 100644 index 000000000..baba45743 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Standards/StandardRulesetsQATest.php @@ -0,0 +1,82 @@ +assertSame('', $seenOutput); + + // Make sure sniffs were registered. + $this->assertGreaterThanOrEqual(1, count($ruleset->sniffCodes)); + + }//end testBuildInStandardsDoNotContainErrors() + + + /** + * Data provider. + * + * @see self::testBuildInStandardsDoNotContainErrors() + * + * @return array> + */ + public static function dataBuildInStandards() + { + // Get a list of all build-in, PHPCS native standards. + $sep = DIRECTORY_SEPARATOR; + $targetDir = dirname(dirname(dirname(__DIR__))).$sep.'src'.$sep.'Standards'.$sep; + $rulesetFiles = glob($targetDir.'*'.$sep.'ruleset.xml'); + + $data = []; + foreach ($rulesetFiles as $file) { + $standardName = basename(dirname($file)); + $data[$standardName] = [ + 'standard' => $standardName, + ]; + } + + return $data; + + }//end dataBuildInStandards() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/OtherContextSensitiveKeywordsTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/OtherContextSensitiveKeywordsTest.inc deleted file mode 100644 index 50b2c2ee2..000000000 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/OtherContextSensitiveKeywordsTest.inc +++ /dev/null @@ -1,67 +0,0 @@ - - * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) - * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence - */ - -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; - -/** - * Tests the conversion of PHPCS native context sensitive keyword tokens to T_STRING. - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * @covers PHP_CodeSniffer\Tokenizers\PHP::standardiseToken - */ -final class OtherContextSensitiveKeywordsTest extends AbstractTokenizerTestCase -{ - - - /** - * Clear the "resolved tokens" cache before running this test as otherwise the code - * under test may not be run during the test. - * - * @beforeClass - * - * @return void - */ - public static function clearTokenCache() - { - parent::clearResolvedTokensCache(); - - }//end clearTokenCache() - - - /** - * Test that context sensitive keyword is tokenized as string when it should be string. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * - * @dataProvider dataStrings - * - * @return void - */ - public function testStrings($testMarker) - { - $tokens = $this->phpcsFile->getTokens(); - $target = $this->getTargetToken($testMarker, [T_STRING, T_NULL, T_FALSE, T_TRUE, T_PARENT, T_SELF]); - $tokenArray = $tokens[$target]; - - $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); - $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); - - }//end testStrings() - - - /** - * Data provider. - * - * @see testStrings() - * - * @return array> - */ - public static function dataStrings() - { - return [ - 'constant declaration: parent' => ['/* testParent */'], - 'constant declaration: self' => ['/* testSelf */'], - 'constant declaration: false' => ['/* testFalse */'], - 'constant declaration: true' => ['/* testTrue */'], - 'constant declaration: null' => ['/* testNull */'], - - 'function declaration with return by ref: self' => ['/* testKeywordSelfAfterFunctionByRefShouldBeString */'], - 'function declaration with return by ref: parent' => ['/* testKeywordParentAfterFunctionByRefShouldBeString */'], - 'function declaration with return by ref: false' => ['/* testKeywordFalseAfterFunctionByRefShouldBeString */'], - 'function declaration with return by ref: true' => ['/* testKeywordTrueAfterFunctionByRefShouldBeString */'], - 'function declaration with return by ref: null' => ['/* testKeywordNullAfterFunctionByRefShouldBeString */'], - - 'function call: self' => ['/* testKeywordAsFunctionCallNameShouldBeStringSelf */'], - 'function call: parent' => ['/* testKeywordAsFunctionCallNameShouldBeStringParent */'], - 'function call: false' => ['/* testKeywordAsFunctionCallNameShouldBeStringFalse */'], - 'function call: true' => ['/* testKeywordAsFunctionCallNameShouldBeStringTrue */'], - 'function call: null; with comment between keyword and parentheses' => ['/* testKeywordAsFunctionCallNameShouldBeStringNull */'], - - 'class instantiation: false' => ['/* testClassInstantiationFalseIsString */'], - 'class instantiation: true' => ['/* testClassInstantiationTrueIsString */'], - 'class instantiation: null' => ['/* testClassInstantiationNullIsString */'], - - 'constant declaration: false as name after type' => ['/* testFalseIsNameForTypedConstant */'], - 'constant declaration: true as name after type' => ['/* testTrueIsNameForTypedConstant */'], - 'constant declaration: null as name after type' => ['/* testNullIsNameForTypedConstant */'], - 'constant declaration: self as name after type' => ['/* testSelfIsNameForTypedConstant */'], - 'constant declaration: parent as name after type' => ['/* testParentIsNameForTypedConstant */'], - ]; - - }//end dataStrings() - - - /** - * Test that context sensitive keyword is tokenized as keyword when it should be keyword. - * - * @param string $testMarker The comment which prefaces the target token in the test file. - * @param string $expectedTokenType The expected token type. - * - * @dataProvider dataKeywords - * - * @return void - */ - public function testKeywords($testMarker, $expectedTokenType) - { - $tokens = $this->phpcsFile->getTokens(); - $target = $this->getTargetToken($testMarker, [T_STRING, T_NULL, T_FALSE, T_TRUE, T_PARENT, T_SELF]); - $tokenArray = $tokens[$target]; - - $this->assertSame( - constant($expectedTokenType), - $tokenArray['code'], - 'Token tokenized as '.$tokenArray['type'].', not '.$expectedTokenType.' (code)' - ); - $this->assertSame( - $expectedTokenType, - $tokenArray['type'], - 'Token tokenized as '.$tokenArray['type'].', not '.$expectedTokenType.' (type)' - ); - - }//end testKeywords() - - - /** - * Data provider. - * - * @see testKeywords() - * - * @return array - */ - public static function dataKeywords() - { - return [ - 'self: param type declaration' => [ - 'testMarker' => '/* testSelfIsKeyword */', - 'expectedTokenType' => 'T_SELF', - ], - 'parent: param type declaration' => [ - 'testMarker' => '/* testParentIsKeyword */', - 'expectedTokenType' => 'T_PARENT', - ], - - 'parent: class instantiation' => [ - 'testMarker' => '/* testClassInstantiationParentIsKeyword */', - 'expectedTokenType' => 'T_PARENT', - ], - 'self: class instantiation' => [ - 'testMarker' => '/* testClassInstantiationSelfIsKeyword */', - 'expectedTokenType' => 'T_SELF', - ], - - 'false: param type declaration' => [ - 'testMarker' => '/* testFalseIsKeywordAsParamType */', - 'expectedTokenType' => 'T_FALSE', - ], - 'true: param type declaration' => [ - 'testMarker' => '/* testTrueIsKeywordAsParamType */', - 'expectedTokenType' => 'T_TRUE', - ], - 'null: param type declaration' => [ - 'testMarker' => '/* testNullIsKeywordAsParamType */', - 'expectedTokenType' => 'T_NULL', - ], - 'false: return type declaration in union' => [ - 'testMarker' => '/* testFalseIsKeywordAsReturnType */', - 'expectedTokenType' => 'T_FALSE', - ], - 'true: return type declaration in union' => [ - 'testMarker' => '/* testTrueIsKeywordAsReturnType */', - 'expectedTokenType' => 'T_TRUE', - ], - 'null: return type declaration in union' => [ - 'testMarker' => '/* testNullIsKeywordAsReturnType */', - 'expectedTokenType' => 'T_NULL', - ], - 'false: in comparison' => [ - 'testMarker' => '/* testFalseIsKeywordInComparison */', - 'expectedTokenType' => 'T_FALSE', - ], - 'true: in comparison' => [ - 'testMarker' => '/* testTrueIsKeywordInComparison */', - 'expectedTokenType' => 'T_TRUE', - ], - 'null: in comparison' => [ - 'testMarker' => '/* testNullIsKeywordInComparison */', - 'expectedTokenType' => 'T_NULL', - ], - - 'false: type in OO constant declaration' => [ - 'testMarker' => '/* testFalseIsKeywordAsConstType */', - 'expectedTokenType' => 'T_FALSE', - ], - 'true: type in OO constant declaration' => [ - 'testMarker' => '/* testTrueIsKeywordAsConstType */', - 'expectedTokenType' => 'T_TRUE', - ], - 'null: type in OO constant declaration' => [ - 'testMarker' => '/* testNullIsKeywordAsConstType */', - 'expectedTokenType' => 'T_NULL', - ], - 'self: type in OO constant declaration' => [ - 'testMarker' => '/* testSelfIsKeywordAsConstType */', - 'expectedTokenType' => 'T_SELF', - ], - 'parent: type in OO constant declaration' => [ - 'testMarker' => '/* testParentIsKeywordAsConstType */', - 'expectedTokenType' => 'T_PARENT', - ], - - 'false: value in constant declaration' => [ - 'testMarker' => '/* testFalseIsKeywordAsConstDefault */', - 'expectedTokenType' => 'T_FALSE', - ], - 'true: value in constant declaration' => [ - 'testMarker' => '/* testTrueIsKeywordAsConstDefault */', - 'expectedTokenType' => 'T_TRUE', - ], - 'null: value in constant declaration' => [ - 'testMarker' => '/* testNullIsKeywordAsConstDefault */', - 'expectedTokenType' => 'T_NULL', - ], - 'self: value in constant declaration' => [ - 'testMarker' => '/* testSelfIsKeywordAsConstDefault */', - 'expectedTokenType' => 'T_SELF', - ], - 'parent: value in constant declaration' => [ - 'testMarker' => '/* testParentIsKeywordAsConstDefault */', - 'expectedTokenType' => 'T_PARENT', - ], - - 'false: type in property declaration' => [ - 'testMarker' => '/* testFalseIsKeywordAsPropertyType */', - 'expectedTokenType' => 'T_FALSE', - ], - 'true: type in property declaration' => [ - 'testMarker' => '/* testTrueIsKeywordAsPropertyType */', - 'expectedTokenType' => 'T_TRUE', - ], - 'null: type in property declaration' => [ - 'testMarker' => '/* testNullIsKeywordAsPropertyType */', - 'expectedTokenType' => 'T_NULL', - ], - 'self: type in property declaration' => [ - 'testMarker' => '/* testSelfIsKeywordAsPropertyType */', - 'expectedTokenType' => 'T_SELF', - ], - 'parent: type in property declaration' => [ - 'testMarker' => '/* testParentIsKeywordAsPropertyType */', - 'expectedTokenType' => 'T_PARENT', - ], - - 'false: value in property declaration' => [ - 'testMarker' => '/* testFalseIsKeywordAsPropertyDefault */', - 'expectedTokenType' => 'T_FALSE', - ], - 'true: value in property declaration' => [ - 'testMarker' => '/* testTrueIsKeywordAsPropertyDefault */', - 'expectedTokenType' => 'T_TRUE', - ], - 'null: value in property declaration' => [ - 'testMarker' => '/* testNullIsKeywordAsPropertyDefault */', - 'expectedTokenType' => 'T_NULL', - ], - 'self: value in property declaration' => [ - 'testMarker' => '/* testSelfIsKeywordAsPropertyDefault */', - 'expectedTokenType' => 'T_SELF', - ], - 'parent: value in property declaration' => [ - 'testMarker' => '/* testParentIsKeywordAsPropertyDefault */', - 'expectedTokenType' => 'T_PARENT', - ], - ]; - - }//end dataKeywords() - - -}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AbstractTokenizerTestCase.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/AbstractTokenizerTestCase.php similarity index 76% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AbstractTokenizerTestCase.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/AbstractTokenizerTestCase.php index 3225fe6fa..f3daf2bf2 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AbstractTokenizerTestCase.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/AbstractTokenizerTestCase.php @@ -10,10 +10,10 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers; -use PHP_CodeSniffer\Ruleset; use PHP_CodeSniffer\Files\DummyFile; +use PHP_CodeSniffer\Ruleset; use PHP_CodeSniffer\Tests\ConfigDouble; use PHP_CodeSniffer\Tests\Core\AbstractMethodUnitTest; use PHPUnit\Framework\TestCase; @@ -62,7 +62,9 @@ abstract class AbstractTokenizerTestCase extends TestCase protected function initializeFile() { if (isset($this->phpcsFile) === false) { - $config = new ConfigDouble(); + $_SERVER['argv'] = []; + $config = new ConfigDouble(); + // Also set a tab-width to enable testing tab-replaced vs `orig_content`. $config->tabWidth = $this->tabWidth; @@ -78,21 +80,42 @@ protected function initializeFile() $contents .= file_get_contents($pathToTestFile); $this->phpcsFile = new DummyFile($contents, $ruleset, $config); - $this->phpcsFile->process(); - } + $this->phpcsFile->parse(); + }//end if }//end initializeFile() + /** + * Test QA: verify that a test case file does not contain any duplicate test markers. + * + * When a test case file contains a lot of test cases, it is easy to overlook that a test marker name + * is already in use. + * A test wouldn't necessarily fail on this, but would not be testing what is intended to be tested as + * it would be verifying token properties for the wrong token. + * + * This test safeguards against this. + * + * @coversNothing + * + * @return void + */ + public function testTestMarkersAreUnique() + { + AbstractMethodUnitTest::assertTestMarkersAreUnique($this->phpcsFile); + + }//end testTestMarkersAreUnique() + + /** * Get the token pointer for a target token based on a specific comment found on the line before. * * Note: the test delimiter comment MUST start with "/* test" to allow this function to * distinguish between comments used *in* a test and test delimiters. * - * @param string $commentString The delimiter comment to look for. - * @param int|string|array $tokenType The type of token(s) to look for. - * @param string $tokenContent Optional. The token content for the target token. + * @param string $commentString The delimiter comment to look for. + * @param int|string|array $tokenType The type of token(s) to look for. + * @param string $tokenContent Optional. The token content for the target token. * * @return int */ diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/CommentTestCase.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/CommentTestCase.php new file mode 100644 index 000000000..625029db1 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/CommentTestCase.php @@ -0,0 +1,117 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Comment; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +/** + * Base class for testing DocBlock comment tokenization. + * + * @covers PHP_CodeSniffer\Tokenizers\Comment + */ +abstract class CommentTestCase extends AbstractTokenizerTestCase +{ + + + /** + * Test whether the docblock opener and closer have the expected extra keys. + * + * @param string $marker The comment prefacing the target token. + * @param int $closerOffset The offset of the closer from the opener. + * @param array $expectedTags The expected tags offsets array. + * + * @dataProvider dataDocblockOpenerCloser + * + * @return void + */ + public function testDocblockOpenerCloser($marker, $closerOffset, $expectedTags) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($marker, [T_DOC_COMMENT_OPEN_TAG]); + + $opener = $tokens[$target]; + + $this->assertArrayHasKey('comment_closer', $opener, 'Comment opener: comment_closer index is not set'); + $this->assertArrayHasKey('comment_tags', $opener, 'Comment opener: comment_tags index is not set'); + + $expectedCloser = ($target + $closerOffset); + $this->assertSame($expectedCloser, $opener['comment_closer'], 'Comment opener: comment_closer not set to the expected stack pointer'); + + // Update the tags expectations. + foreach ($expectedTags as $i => $ptr) { + $expectedTags[$i] += $target; + } + + $this->assertSame($expectedTags, $opener['comment_tags'], 'Comment opener: recorded tags do not match expected tags'); + + $closer = $tokens[$opener['comment_closer']]; + + $this->assertArrayHasKey('comment_opener', $closer, 'Comment closer: comment_opener index is not set'); + $this->assertSame($target, $closer['comment_opener'], 'Comment closer: comment_opener not set to the expected stack pointer'); + + }//end testDocblockOpenerCloser() + + + /** + * Data provider. + * + * @see testDocblockOpenerCloser() + * + * @return array>> + */ + abstract public static function dataDocblockOpenerCloser(); + + + /** + * Test helper. Check a token sequence complies with an expected token sequence. + * + * @param int $startPtr The position in the file to start checking from. + * @param array> $expectedSequence The consecutive token constants and their contents to expect. + * + * @return void + */ + protected function checkTokenSequence($startPtr, array $expectedSequence) + { + $tokens = $this->phpcsFile->getTokens(); + + $sequenceKey = 0; + $sequenceCount = count($expectedSequence); + + for ($i = $startPtr; $sequenceKey < $sequenceCount; $i++, $sequenceKey++) { + $currentItem = $expectedSequence[$sequenceKey]; + $expectedCode = key($currentItem); + $expectedType = Tokens::tokenName($expectedCode); + $expectedContent = current($currentItem); + $errorMsgSuffix = PHP_EOL.'(StackPtr: '.$i.' | Position in sequence: '.$sequenceKey.' | Expected: '.$expectedType.')'; + + $this->assertSame( + $expectedCode, + $tokens[$i]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$i]['code']).', not '.$expectedType.' (code)'.$errorMsgSuffix + ); + + $this->assertSame( + $expectedType, + $tokens[$i]['type'], + 'Token tokenized as '.$tokens[$i]['type'].', not '.$expectedType.' (type)'.$errorMsgSuffix + ); + + $this->assertSame( + $expectedContent, + $tokens[$i]['content'], + 'Token content did not match expectations'.$errorMsgSuffix + ); + }//end for + + }//end checkTokenSequence() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding1Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding1Test.inc new file mode 100644 index 000000000..a43c7d9b2 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding1Test.inc @@ -0,0 +1,6 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Comment; + +/** + * Tests that unclosed docblocks during live coding are handled correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\Comment + */ +final class LiveCoding1Test extends CommentTestCase +{ + + + /** + * Data provider. + * + * @see testDocblockOpenerCloser() + * + * @return array>> + */ + public static function dataDocblockOpenerCloser() + { + return [ + 'live coding: unclosed docblock, no blank line at end of file' => [ + 'marker' => '/* testLiveCoding */', + 'closerOffset' => 8, + 'expectedTags' => [], + ], + ]; + + }//end dataDocblockOpenerCloser() + + + /** + * Verify tokenization of the DocBlock. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testLiveCoding() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Unclosed docblock, live coding.... with no blank line at end of file.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testLiveCoding() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding2Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding2Test.inc new file mode 100644 index 000000000..b113645b5 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding2Test.inc @@ -0,0 +1,5 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Comment; + +/** + * Tests that unclosed docblocks during live coding are handled correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\Comment + */ +final class LiveCoding2Test extends CommentTestCase +{ + + + /** + * Data provider. + * + * @see testDocblockOpenerCloser() + * + * @return array>> + */ + public static function dataDocblockOpenerCloser() + { + return [ + 'live coding: unclosed docblock with blank line at end of file' => [ + 'marker' => '/* testLiveCoding */', + 'closerOffset' => 7, + 'expectedTags' => [], + ], + ]; + + }//end dataDocblockOpenerCloser() + + + /** + * Verify tokenization of the DocBlock. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testLiveCoding() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Unclosed docblock, live coding.... with a blank line at end of file.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_CLOSE_TAG => ''], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testLiveCoding() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding3Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding3Test.inc new file mode 100644 index 000000000..9b81a434d --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding3Test.inc @@ -0,0 +1,4 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Comment; + +/** + * Tests that unclosed docblocks during live coding are handled correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\Comment + */ +final class LiveCoding3Test extends CommentTestCase +{ + + + /** + * Data provider. + * + * @see testDocblockOpenerCloser() + * + * @return array>> + */ + public static function dataDocblockOpenerCloser() + { + return [ + 'live coding: unclosed docblock, no contents, no blank line at end of file' => [ + 'marker' => '/* testLiveCoding */', + 'closerOffset' => 1, + 'expectedTags' => [], + ], + ]; + + }//end dataDocblockOpenerCloser() + + + /** + * Verify tokenization of the DocBlock. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testLiveCoding() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_CLOSE_TAG => ''], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testLiveCoding() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding4Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding4Test.inc new file mode 100644 index 000000000..1561e7156 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/LiveCoding4Test.inc @@ -0,0 +1,7 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Comment; + +/** + * Tests that unclosed docblocks during live coding are handled correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\Comment + */ +final class LiveCoding4Test extends CommentTestCase +{ + + + /** + * Data provider. + * + * @see testDocblockOpenerCloser() + * + * @return array>> + */ + public static function dataDocblockOpenerCloser() + { + return [ + 'live coding: unclosed docblock, trailing whitespace on last line, no blank line at end of file' => [ + 'marker' => '/* testLiveCoding */', + 'closerOffset' => 15, + 'expectedTags' => [], + ], + ]; + + }//end dataDocblockOpenerCloser() + + + /** + * Verify tokenization of the DocBlock. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testLiveCoding() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'The last line of this test must have trailing whitespace.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'So, be careful when saving this file!'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => ''], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testLiveCoding() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/MultiLineDocBlockTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/MultiLineDocBlockTest.inc new file mode 100644 index 000000000..f33afcd6a --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/MultiLineDocBlockTest.inc @@ -0,0 +1,81 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Comment; + +/** + * Tests that multiline docblocks are tokenized correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\Comment + */ +final class MultiLineDocBlockTest extends CommentTestCase +{ + + + /** + * Data provider. + * + * @see testDocblockOpenerCloser() + * + * @return array>> + */ + public static function dataDocblockOpenerCloser() + { + return [ + 'Multi line docblock: no contents' => [ + 'marker' => '/* testEmptyDocblock */', + 'closerOffset' => 3, + 'expectedTags' => [], + ], + 'Multi line docblock: variety of text and tags' => [ + 'marker' => '/* testMultilineDocblock */', + 'closerOffset' => 95, + // phpcs:ignore Squiz.Arrays.ArrayDeclaration.SingleLineNotAllowed + 'expectedTags' => [21, 29, 36, 46, 56, 63, 73, 80, 90], + ], + 'Multi line docblock: no leading stars' => [ + 'marker' => '/* testMultilineDocblockNoStars */', + 'closerOffset' => 32, + // phpcs:ignore Squiz.Arrays.ArrayDeclaration.SingleLineNotAllowed + 'expectedTags' => [10, 16, 21, 27], + ], + 'Multi line docblock: indented' => [ + 'marker' => '/* testMultilineDocblockIndented */', + 'closerOffset' => 60, + // phpcs:ignore Squiz.Arrays.ArrayDeclaration.SingleLineNotAllowed + 'expectedTags' => [21, 28, 38, 45, 55], + ], + 'Multi line docblock: opener not on own line' => [ + 'marker' => '/* testMultilineDocblockOpenerNotOnOwnLine */', + 'closerOffset' => 10, + 'expectedTags' => [], + ], + 'Multi line docblock: closer not on own line' => [ + 'marker' => '/* testMultilineDocblockCloserNotOnOwnLine */', + 'closerOffset' => 11, + 'expectedTags' => [], + ], + 'Multi line docblock: stars not aligned' => [ + 'marker' => '/* testMultilineDocblockStarsNotAligned */', + 'closerOffset' => 26, + 'expectedTags' => [], + ], + ]; + + }//end dataDocblockOpenerCloser() + + + /** + * Verify tokenization of an empty, multi-line DocBlock. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testEmptyDocblock() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testEmptyDocblock() + + + /** + * Verify tokenization of a multi-line DocBlock containing all possible tokens. + * + * @return void + */ + public function testMultilineDocblock() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'This is a multi-line docblock.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'With blank lines, stars, tags, and tag descriptions.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tagWithoutDescription'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@since'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => '10.3'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@deprecated'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => '11.5'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@requires'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'PHP 7.1 -- PHPUnit tag.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tag-with-dashes-is-suppported'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Description.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tag_with_underscores'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Description.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@param'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'string $p1 Description 1.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@param'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'int|false $p2 Description 2.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@return'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'void'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultilineDocblock() + + + /** + * Verify tokenization of a multi-line DocBlock with extra starts for the opener/closer and no stars on the lines between. + * + * @return void + */ + public function testMultilineDocblockNoStars() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/****'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'This is a multi-line docblock, but the lines are not marked with stars.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Then again, the opener and closer have an abundance of stars.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@since'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => '10.3'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@param'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'string $p1 Description 1.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@param'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'int|false $p2 Description 2.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@return'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'void'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '**/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultilineDocblockNoStars() + + + /** + * Verify tokenization of a multi-line, indented DocBlock. + * + * @return void + */ + public function testMultilineDocblockIndented() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'This is a multi-line indented docblock.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'With blank lines, stars, tags, and tag descriptions.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@since'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => '10.3'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@deprecated'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => '11.5'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@param'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'string $p1 Description 1.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@param'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'int|false $p2 Description 2.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@return'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'void'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultilineDocblockIndented() + + + /** + * Verify tokenization of a multi-line DocBlock, where the opener is not on its own line. + * + * @return void + */ + public function testMultilineDocblockOpenerNotOnOwnLine() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Start of description'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'description continued.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultilineDocblockOpenerNotOnOwnLine() + + + /** + * Verify tokenization of a multi-line DocBlock, where the closer is not on its own line. + * + * @return void + */ + public function testMultilineDocblockCloserNotOnOwnLine() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Start of description'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'description continued. '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultilineDocblockCloserNotOnOwnLine() + + + /** + * Verify tokenization of a multi-line DocBlock with inconsistent indentation. + * + * @return void + */ + public function testMultilineDocblockStarsNotAligned() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Start of description.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Line below this is missing a star.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Text'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Star indented.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Closer indented.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultilineDocblockStarsNotAligned() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/PhpcsAnnotationsInDocBlockTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/PhpcsAnnotationsInDocBlockTest.inc new file mode 100644 index 000000000..d74f68d24 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/PhpcsAnnotationsInDocBlockTest.inc @@ -0,0 +1,116 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Comment; + +/** + * Tests that PHPCS native annotations in docblocks are tokenized correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\Comment + */ +final class PhpcsAnnotationsInDocBlockTest extends CommentTestCase +{ + + + /** + * Data provider. + * + * @see testDocblockOpenerCloser() + * + * @return array>> + */ + public static function dataDocblockOpenerCloser() + { + return [ + 'Single-line: @phpcs:ignoreFile annotation' => [ + 'marker' => '/* testSingleLineDocIgnoreFileAnnotation */', + 'closerOffset' => 3, + 'expectedTags' => [], + ], + 'Single-line: @phpcs:ignore annotation' => [ + 'marker' => '/* testSingleLineDocIgnoreAnnotation */', + 'closerOffset' => 3, + 'expectedTags' => [], + ], + 'Single-line: @phpcs:disable annotation' => [ + 'marker' => '/* testSingleLineDocDisableAnnotation */', + 'closerOffset' => 3, + 'expectedTags' => [], + ], + 'Single-line: @phpcs:enable annotation; no whitespace' => [ + 'marker' => '/* testSingleLineDocEnableAnnotationNoWhitespace */', + 'closerOffset' => 2, + 'expectedTags' => [], + ], + + 'Multi-line: @phpcs:ignoreFile at the start' => [ + 'marker' => '/* testMultiLineDocIgnoreFileAnnotationAtStart */', + 'closerOffset' => 13, + 'expectedTags' => [], + ], + 'Multi-line: @phpcs:ignore at the start' => [ + 'marker' => '/* testMultiLineDocIgnoreAnnotationAtStart */', + 'closerOffset' => 13, + 'expectedTags' => [10], + ], + 'Multi-line: @phpcs:disable at the start' => [ + 'marker' => '/* testMultiLineDocDisableAnnotationAtStart */', + 'closerOffset' => 13, + 'expectedTags' => [], + ], + 'Multi-line: @phpcs:enable at the start' => [ + 'marker' => '/* testMultiLineDocEnableAnnotationAtStart */', + 'closerOffset' => 18, + 'expectedTags' => [13], + ], + + 'Multi-line: @phpcs:ignoreFile in the middle' => [ + 'marker' => '/* testMultiLineDocIgnoreFileAnnotationInMiddle */', + 'closerOffset' => 21, + 'expectedTags' => [], + ], + 'Multi-line: @phpcs:ignore in the middle' => [ + 'marker' => '/* testMultiLineDocIgnoreAnnotationInMiddle */', + 'closerOffset' => 23, + 'expectedTags' => [5], + ], + 'Multi-line: @phpcs:disable in the middle' => [ + 'marker' => '/* testMultiLineDocDisableAnnotationInMiddle */', + 'closerOffset' => 26, + 'expectedTags' => [21], + ], + 'Multi-line: @phpcs:enable in the middle' => [ + 'marker' => '/* testMultiLineDocEnableAnnotationInMiddle */', + 'closerOffset' => 24, + 'expectedTags' => [21], + ], + + 'Multi-line: @phpcs:ignoreFile at the end' => [ + 'marker' => '/* testMultiLineDocIgnoreFileAnnotationAtEnd */', + 'closerOffset' => 16, + 'expectedTags' => [5], + ], + 'Multi-line: @phpcs:ignore at the end' => [ + 'marker' => '/* testMultiLineDocIgnoreAnnotationAtEnd */', + 'closerOffset' => 16, + 'expectedTags' => [], + ], + 'Multi-line: @phpcs:disable at the end' => [ + 'marker' => '/* testMultiLineDocDisableAnnotationAtEnd */', + 'closerOffset' => 18, + 'expectedTags' => [5], + ], + 'Multi-line: @phpcs:enable at the end' => [ + 'marker' => '/* testMultiLineDocEnableAnnotationAtEnd */', + 'closerOffset' => 16, + 'expectedTags' => [], + ], + ]; + + }//end dataDocblockOpenerCloser() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS ignoreFile annotation. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testSingleLineDocIgnoreFileAnnotation() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_IGNORE_FILE => '@phpcs:ignoreFile '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testSingleLineDocIgnoreFileAnnotation() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS ignore annotation. + * + * @return void + */ + public function testSingleLineDocIgnoreAnnotation() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_IGNORE => '@phpcs:ignore Stnd.Cat.SniffName -- With reason '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testSingleLineDocIgnoreAnnotation() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS disable annotation. + * + * @return void + */ + public function testSingleLineDocDisableAnnotation() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_DISABLE => '@phpcs:disable Stnd.Cat.SniffName,Stnd.Other '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testSingleLineDocDisableAnnotation() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS enable annotation. + * + * @return void + */ + public function testSingleLineDocEnableAnnotationNoWhitespace() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_PHPCS_ENABLE => '@phpcs:enable Stnd.Cat.SniffName'], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testSingleLineDocEnableAnnotationNoWhitespace() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS ignoreFile annotation at the start. + * + * @return void + */ + public function testMultiLineDocIgnoreFileAnnotationAtStart() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_IGNORE_FILE => '@phpcs:ignoreFile'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Something.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocIgnoreFileAnnotationAtStart() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS ignore annotation at the start. + * + * @return void + */ + public function testMultiLineDocIgnoreAnnotationAtStart() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_IGNORE => '@phpcs:ignore Stnd.Cat.SniffName'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tag'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocIgnoreAnnotationAtStart() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS disable annotation at the start. + * + * @return void + */ + public function testMultiLineDocDisableAnnotationAtStart() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_DISABLE => '@phpcs:disable Stnd.Cat.SniffName -- Ensure PHPCS annotations are also retokenized correctly.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Something.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocDisableAnnotationAtStart() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS enable annotation at the start. + * + * @return void + */ + public function testMultiLineDocEnableAnnotationAtStart() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_ENABLE => '@phpcs:enable Stnd.Cat,Stnd.Other'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tag'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'With description.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocEnableAnnotationAtStart() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS ignoreFile annotation in the middle. + * + * @return void + */ + public function testMultiLineDocIgnoreFileAnnotationInMiddle() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Check tokenization of PHPCS annotations within docblocks.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_IGNORE_FILE => '@phpcs:ignoreFile'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Something.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocIgnoreFileAnnotationInMiddle() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS ignore annotation in the middle. + * + * @return void + */ + public function testMultiLineDocIgnoreAnnotationInMiddle() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tagBefore'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'With Description'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_IGNORE => '@phpcs:ignore Stnd.Cat.SniffName'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Something.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocIgnoreAnnotationInMiddle() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS disable annotation in the middle. + * + * @return void + */ + public function testMultiLineDocDisableAnnotationInMiddle() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Check tokenization of PHPCS annotations within docblocks.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_DISABLE => '@phpcs:disable Stnd.Cat.SniffName -- Ensure PHPCS annotations are also retokenized correctly.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tagAfter'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'With Description'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocDisableAnnotationInMiddle() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS enable annotation in the middle. + * + * @return void + */ + public function testMultiLineDocEnableAnnotationInMiddle() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Check tokenization of PHPCS annotations within docblocks.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_ENABLE => '@phpcs:enable Stnd.Cat,Stnd.Other'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tagAfter'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocEnableAnnotationInMiddle() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS ignoreFile annotation at the end. + * + * @return void + */ + public function testMultiLineDocIgnoreFileAnnotationAtEnd() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tagBefore'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_IGNORE_FILE => '@phpcs:ignoreFile'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocIgnoreFileAnnotationAtEnd() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS ignore annotation at the end. + * + * @return void + */ + public function testMultiLineDocIgnoreAnnotationAtEnd() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Check tokenization of PHPCS annotations within docblocks.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_IGNORE => '@phpcs:ignore Stnd.Cat.SniffName'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocIgnoreAnnotationAtEnd() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS disable annotation at the end. + * + * @return void + */ + public function testMultiLineDocDisableAnnotationAtEnd() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@tagBefore'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'With Description.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_DISABLE => '@phpcs:disable Stnd.Cat.SniffName -- Ensure PHPCS annotations are also retokenized correctly.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocDisableAnnotationAtEnd() + + + /** + * Verify tokenization of a single line DocBlock containing a PHPCS enable annotation at the end. + * + * @return void + */ + public function testMultiLineDocEnableAnnotationAtEnd() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Check tokenization of PHPCS annotations within docblocks.'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STAR => '*'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_PHPCS_ENABLE => '@phpcs:enable Stnd.Cat,Stnd.Other'], + [T_DOC_COMMENT_WHITESPACE => "\n"], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testMultiLineDocEnableAnnotationAtEnd() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/SingleLineDocBlockTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/SingleLineDocBlockTest.inc new file mode 100644 index 000000000..88b05ea43 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Comment/SingleLineDocBlockTest.inc @@ -0,0 +1,26 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Comment; + +/** + * Tests that single line docblocks are tokenized correctly. + * + * @covers PHP_CodeSniffer\Tokenizers\Comment + */ +final class SingleLineDocBlockTest extends CommentTestCase +{ + + + /** + * Data provider. + * + * @see testDocblockOpenerCloser() + * + * @return array>> + */ + public static function dataDocblockOpenerCloser() + { + return [ + 'Single line docblock: empty, no whitespace' => [ + 'marker' => '/* testEmptyDocblockNoWhiteSpace */', + 'closerOffset' => 1, + 'expectedTags' => [], + ], + 'Single line docblock: only whitespace' => [ + 'marker' => '/* testEmptyDocblockWithWhiteSpace */', + 'closerOffset' => 2, + 'expectedTags' => [], + ], + 'Single line docblock: just text' => [ + 'marker' => '/* testSingleLineDocblockNoTag */', + 'closerOffset' => 3, + 'expectedTags' => [], + ], + 'Single line docblock: @var type before name' => [ + 'marker' => '/* testSingleLineDocblockWithTag1 */', + 'closerOffset' => 5, + 'expectedTags' => [2], + ], + 'Single line docblock: @var name before type' => [ + 'marker' => '/* testSingleLineDocblockWithTag2 */', + 'closerOffset' => 5, + 'expectedTags' => [2], + ], + 'Single line docblock: @see with description' => [ + 'marker' => '/* testSingleLineDocblockWithTag3 */', + 'closerOffset' => 5, + 'expectedTags' => [2], + ], + ]; + + }//end dataDocblockOpenerCloser() + + + /** + * Verify an empty block comment is tokenized as T_COMMENT, not as a docblock. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * + * @return void + */ + public function testEmptyBlockCommentNoWhiteSpace() + { + $expectedSequence = [ + [T_COMMENT => '/**/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', [T_COMMENT, T_DOC_COMMENT_OPEN_TAG]); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testEmptyBlockCommentNoWhiteSpace() + + + /** + * Verify tokenization of an empty, single line DocBlock without whitespace between the opener and closer. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testEmptyDocblockNoWhiteSpace() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testEmptyDocblockNoWhiteSpace() + + + /** + * Verify tokenization of an empty, single line DocBlock. + * + * @return void + */ + public function testEmptyDocblockWithWhiteSpace() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testEmptyDocblockWithWhiteSpace() + + + /** + * Verify tokenization of a single line DocBlock. + * + * @return void + */ + public function testSingleLineDocblockNoTag() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Just some text '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testSingleLineDocblockNoTag() + + + /** + * Verify tokenization of a single line DocBlock with a tag. + * + * @return void + */ + public function testSingleLineDocblockWithTag1() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@var'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => '\SomeClass[] $var '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testSingleLineDocblockWithTag1() + + + /** + * Verify tokenization of a single line DocBlock with a tag. + * + * @return void + */ + public function testSingleLineDocblockWithTag2() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@var'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => '$var \SomeClass[] '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testSingleLineDocblockWithTag2() + + + /** + * Verify tokenization of a single line DocBlock with a tag. + * + * @return void + */ + public function testSingleLineDocblockWithTag3() + { + $expectedSequence = [ + [T_DOC_COMMENT_OPEN_TAG => '/**'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_TAG => '@see'], + [T_DOC_COMMENT_WHITESPACE => ' '], + [T_DOC_COMMENT_STRING => 'Something::Else '], + [T_DOC_COMMENT_CLOSE_TAG => '*/'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_DOC_COMMENT_OPEN_TAG); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testSingleLineDocblockWithTag3() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AnonClassParenthesisOwnerTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AnonClassParenthesisOwnerTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AnonClassParenthesisOwnerTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AnonClassParenthesisOwnerTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AnonClassParenthesisOwnerTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AnonClassParenthesisOwnerTest.php similarity index 80% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AnonClassParenthesisOwnerTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AnonClassParenthesisOwnerTest.php index 79eb742e1..c93ce8510 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AnonClassParenthesisOwnerTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AnonClassParenthesisOwnerTest.php @@ -7,7 +7,9 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; final class AnonClassParenthesisOwnerTest extends AbstractTokenizerTestCase { @@ -28,9 +30,9 @@ public function testAnonClassNoParentheses($testMarker) $tokens = $this->phpcsFile->getTokens(); $anonClass = $this->getTargetToken($testMarker, T_ANON_CLASS); - $this->assertFalse(array_key_exists('parenthesis_owner', $tokens[$anonClass])); - $this->assertFalse(array_key_exists('parenthesis_opener', $tokens[$anonClass])); - $this->assertFalse(array_key_exists('parenthesis_closer', $tokens[$anonClass])); + $this->assertArrayNotHasKey('parenthesis_owner', $tokens[$anonClass]); + $this->assertArrayNotHasKey('parenthesis_opener', $tokens[$anonClass]); + $this->assertArrayNotHasKey('parenthesis_closer', $tokens[$anonClass]); }//end testAnonClassNoParentheses() @@ -52,11 +54,11 @@ public function testAnonClassNoParenthesesNextOpenClose($testMarker) $function = $this->getTargetToken($testMarker, T_FUNCTION); $opener = $this->getTargetToken($testMarker, T_OPEN_PARENTHESIS); - $this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$opener])); + $this->assertArrayHasKey('parenthesis_owner', $tokens[$opener]); $this->assertSame($function, $tokens[$opener]['parenthesis_owner']); $closer = $this->getTargetToken($testMarker, T_CLOSE_PARENTHESIS); - $this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$closer])); + $this->assertArrayHasKey('parenthesis_owner', $tokens[$closer]); $this->assertSame($function, $tokens[$closer]['parenthesis_owner']); }//end testAnonClassNoParenthesesNextOpenClose() @@ -105,23 +107,23 @@ public function testAnonClassWithParentheses($testMarker) $opener = $this->getTargetToken($testMarker, T_OPEN_PARENTHESIS); $closer = $this->getTargetToken($testMarker, T_CLOSE_PARENTHESIS); - $this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$anonClass])); - $this->assertTrue(array_key_exists('parenthesis_opener', $tokens[$anonClass])); - $this->assertTrue(array_key_exists('parenthesis_closer', $tokens[$anonClass])); + $this->assertArrayHasKey('parenthesis_owner', $tokens[$anonClass]); + $this->assertArrayHasKey('parenthesis_opener', $tokens[$anonClass]); + $this->assertArrayHasKey('parenthesis_closer', $tokens[$anonClass]); $this->assertSame($anonClass, $tokens[$anonClass]['parenthesis_owner']); $this->assertSame($opener, $tokens[$anonClass]['parenthesis_opener']); $this->assertSame($closer, $tokens[$anonClass]['parenthesis_closer']); - $this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$opener])); - $this->assertTrue(array_key_exists('parenthesis_opener', $tokens[$opener])); - $this->assertTrue(array_key_exists('parenthesis_closer', $tokens[$opener])); + $this->assertArrayHasKey('parenthesis_owner', $tokens[$opener]); + $this->assertArrayHasKey('parenthesis_opener', $tokens[$opener]); + $this->assertArrayHasKey('parenthesis_closer', $tokens[$opener]); $this->assertSame($anonClass, $tokens[$opener]['parenthesis_owner']); $this->assertSame($opener, $tokens[$opener]['parenthesis_opener']); $this->assertSame($closer, $tokens[$opener]['parenthesis_closer']); - $this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$closer])); - $this->assertTrue(array_key_exists('parenthesis_opener', $tokens[$closer])); - $this->assertTrue(array_key_exists('parenthesis_closer', $tokens[$closer])); + $this->assertArrayHasKey('parenthesis_owner', $tokens[$closer]); + $this->assertArrayHasKey('parenthesis_opener', $tokens[$closer]); + $this->assertArrayHasKey('parenthesis_closer', $tokens[$closer]); $this->assertSame($anonClass, $tokens[$closer]['parenthesis_owner']); $this->assertSame($opener, $tokens[$closer]['parenthesis_opener']); $this->assertSame($closer, $tokens[$closer]['parenthesis_closer']); diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ArrayKeywordTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ArrayKeywordTest.inc similarity index 63% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ArrayKeywordTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ArrayKeywordTest.inc index ce211bda2..6d8adfcba 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ArrayKeywordTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ArrayKeywordTest.inc @@ -39,3 +39,20 @@ class Bar { /* testOOPropertyType */ protected array $property; } + +class DNFTypes { + /* testOOConstDNFType */ + const (A&B)|array|(C&D) NAME = []; + + /* testOOPropertyDNFType */ + protected (A&B)|ARRAY|null $property; + + /* testFunctionDeclarationParamDNFType */ + public function name(null|array|(A&B) $param) { + /* testClosureDeclarationParamDNFType */ + $cl = function ( array|(A&B) $param) {}; + + /* testArrowDeclarationReturnDNFType */ + $arrow = fn($a): (A&B)|Array => new $a; + } +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ArrayKeywordTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ArrayKeywordTest.php similarity index 83% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ArrayKeywordTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ArrayKeywordTest.php index f81706c33..f94971d9d 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ArrayKeywordTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ArrayKeywordTest.php @@ -7,7 +7,9 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; final class ArrayKeywordTest extends AbstractTokenizerTestCase { @@ -21,7 +23,6 @@ final class ArrayKeywordTest extends AbstractTokenizerTestCase * * @dataProvider dataArrayKeyword * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createTokenMap * * @return void */ @@ -35,10 +36,6 @@ public function testArrayKeyword($testMarker, $testContent='array') $this->assertSame(T_ARRAY, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_ARRAY (code)'); $this->assertSame('T_ARRAY', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_ARRAY (type)'); - $this->assertArrayHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is not set'); - $this->assertArrayHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is not set'); - $this->assertArrayHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is not set'); - }//end testArrayKeyword() @@ -84,7 +81,6 @@ public static function dataArrayKeyword() * * @dataProvider dataArrayType * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createTokenMap * * @return void */ @@ -98,10 +94,6 @@ public function testArrayType($testMarker, $testContent='array') $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); - $this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set'); - $this->assertArrayNotHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is set'); - $this->assertArrayNotHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is set'); - }//end testArrayType() @@ -131,6 +123,24 @@ public static function dataArrayType() 'OO property type' => [ 'testMarker' => '/* testOOPropertyType */', ], + + 'OO constant DNF type' => [ + 'testMarker' => '/* testOOConstDNFType */', + ], + 'OO property DNF type' => [ + 'testMarker' => '/* testOOPropertyDNFType */', + 'testContent' => 'ARRAY', + ], + 'function param DNF type' => [ + 'testMarker' => '/* testFunctionDeclarationParamDNFType */', + ], + 'closure param DNF type' => [ + 'testMarker' => '/* testClosureDeclarationParamDNFType */', + ], + 'arrow return DNF type' => [ + 'testMarker' => '/* testArrowDeclarationReturnDNFType */', + 'testContent' => 'Array', + ], ]; }//end dataArrayType() @@ -145,7 +155,6 @@ public static function dataArrayType() * * @dataProvider dataNotArrayKeyword * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createTokenMap * * @return void */ @@ -159,10 +168,6 @@ public function testNotArrayKeyword($testMarker, $testContent='array') $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); - $this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set'); - $this->assertArrayNotHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is set'); - $this->assertArrayNotHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is set'); - }//end testNotArrayKeyword() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AttributesTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AttributesTest.inc similarity index 98% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AttributesTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AttributesTest.inc index e539adf8a..9d56c0952 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AttributesTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AttributesTest.inc @@ -62,7 +62,7 @@ function multiple_attributes_on_parameter_test(#[ParamAttribute, AttributeWithPa /* testFqcnAttribute */ #[Boo\QualifiedName, \Foo\FullyQualifiedName('foo')] -function fqcn_attrebute_test() {} +function fqcn_attribute_test() {} /* testNestedAttributes */ #[Boo\QualifiedName(fn (#[AttributeOne('boo')] $value) => (string) $value)] diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AttributesTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AttributesTest.php similarity index 91% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AttributesTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AttributesTest.php index 764a9bef4..bc15a1930 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/AttributesTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/AttributesTest.php @@ -7,7 +7,9 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; final class AttributesTest extends AbstractTokenizerTestCase { @@ -17,7 +19,6 @@ final class AttributesTest extends AbstractTokenizerTestCase * Test that attributes are parsed correctly. * * @param string $testMarker The comment which prefaces the target token in the test file. - * @param int $length The number of tokens between opener and closer. * @param array $tokenCodes The codes of tokens inside the attributes. * * @dataProvider dataAttribute @@ -27,10 +28,13 @@ final class AttributesTest extends AbstractTokenizerTestCase * * @return void */ - public function testAttribute($testMarker, $length, $tokenCodes) + public function testAttribute($testMarker, $tokenCodes) { $tokens = $this->phpcsFile->getTokens(); + // Calculate the number of tokens between opener and closer (excluding the opener, including the closer). + $length = (count($tokenCodes) + 1); + $attribute = $this->getTargetToken($testMarker, T_ATTRIBUTE); $this->assertArrayHasKey('attribute_closer', $tokens[$attribute]); @@ -69,14 +73,12 @@ public static function dataAttribute() return [ 'class attribute' => [ 'testMarker' => '/* testAttribute */', - 'length' => 2, 'tokenCodes' => [ - T_STRING + T_STRING, ], ], 'class attribute with param' => [ 'testMarker' => '/* testAttributeWithParams */', - 'length' => 7, 'tokenCodes' => [ T_STRING, T_OPEN_PARENTHESIS, @@ -88,7 +90,6 @@ public static function dataAttribute() ], 'class attribute with named param' => [ 'testMarker' => '/* testAttributeWithNamedParam */', - 'length' => 10, 'tokenCodes' => [ T_STRING, T_OPEN_PARENTHESIS, @@ -103,14 +104,12 @@ public static function dataAttribute() ], 'function attribute' => [ 'testMarker' => '/* testAttributeOnFunction */', - 'length' => 2, 'tokenCodes' => [ - T_STRING + T_STRING, ], ], 'function attribute with params' => [ 'testMarker' => '/* testAttributeOnFunctionWithParams */', - 'length' => 17, 'tokenCodes' => [ T_STRING, T_OPEN_PARENTHESIS, @@ -132,7 +131,6 @@ public static function dataAttribute() ], 'function attribute with arrow function as param' => [ 'testMarker' => '/* testAttributeWithShortClosureParameter */', - 'length' => 17, 'tokenCodes' => [ T_STRING, T_OPEN_PARENTHESIS, @@ -154,7 +152,6 @@ public static function dataAttribute() ], 'function attribute; multiple comma separated classes' => [ 'testMarker' => '/* testAttributeGrouping */', - 'length' => 26, 'tokenCodes' => [ T_STRING, T_COMMA, @@ -185,7 +182,6 @@ public static function dataAttribute() ], 'function attribute; multiple comma separated classes, one per line' => [ 'testMarker' => '/* testAttributeMultiline */', - 'length' => 31, 'tokenCodes' => [ T_WHITESPACE, T_WHITESPACE, @@ -221,7 +217,6 @@ public static function dataAttribute() ], 'function attribute; multiple comma separated classes, one per line, with comments' => [ 'testMarker' => '/* testAttributeMultilineWithComment */', - 'length' => 34, 'tokenCodes' => [ T_WHITESPACE, T_WHITESPACE, @@ -260,7 +255,6 @@ public static function dataAttribute() ], 'function attribute; using partially qualified and fully qualified class names' => [ 'testMarker' => '/* testFqcnAttribute */', - 'length' => 13, 'tokenCodes' => [ T_STRING, T_NS_SEPARATOR, @@ -333,7 +327,6 @@ public function testAttributeAndLineComment() * * @param string $testMarker The comment which prefaces the target token in the test file. * @param int $position The token position (starting from T_FUNCTION) of T_ATTRIBUTE token. - * @param int $length The number of tokens between opener and closer. * @param array $tokenCodes The codes of tokens inside the attributes. * * @dataProvider dataAttributeOnParameters @@ -344,10 +337,13 @@ public function testAttributeAndLineComment() * * @return void */ - public function testAttributeOnParameters($testMarker, $position, $length, array $tokenCodes) + public function testAttributeOnParameters($testMarker, $position, array $tokenCodes) { $tokens = $this->phpcsFile->getTokens(); + // Calculate the number of tokens between opener and closer (excluding the opener, including the closer). + $length = (count($tokenCodes) + 1); + $function = $this->getTargetToken($testMarker, T_FUNCTION); $attribute = ($function + $position); @@ -392,15 +388,13 @@ public static function dataAttributeOnParameters() 'parameter attribute; single, inline' => [ 'testMarker' => '/* testSingleAttributeOnParameter */', 'position' => 4, - 'length' => 2, 'tokenCodes' => [ - T_STRING + T_STRING, ], ], 'parameter attribute; multiple comma separated, inline' => [ 'testMarker' => '/* testMultipleAttributesOnParameter */', 'position' => 4, - 'length' => 10, 'tokenCodes' => [ T_STRING, T_COMMA, @@ -416,7 +410,6 @@ public static function dataAttributeOnParameters() 'parameter attribute; single, multiline' => [ 'testMarker' => '/* testMultilineAttributesOnParameter */', 'position' => 4, - 'length' => 13, 'tokenCodes' => [ T_WHITESPACE, T_WHITESPACE, @@ -441,7 +434,6 @@ public static function dataAttributeOnParameters() * Test that an attribute containing text which looks like a PHP close tag is tokenized correctly. * * @param string $testMarker The comment which prefaces the target token in the test file. - * @param int $length The number of tokens between opener and closer. * @param array> $expectedTokensAttribute The codes of tokens inside the attributes. * @param array $expectedTokensAfter The codes of tokens after the attributes. * @@ -451,10 +443,13 @@ public static function dataAttributeOnParameters() * * @return void */ - public function testAttributeContainingTextLookingLikeCloseTag($testMarker, $length, array $expectedTokensAttribute, array $expectedTokensAfter) + public function testAttributeContainingTextLookingLikeCloseTag($testMarker, array $expectedTokensAttribute, array $expectedTokensAfter) { $tokens = $this->phpcsFile->getTokens(); + // Calculate the number of tokens between opener and closer (excluding the opener, including the closer). + $length = count($expectedTokensAttribute); + $attribute = $this->getTargetToken($testMarker, T_ATTRIBUTE); $this->assertSame('T_ATTRIBUTE', $tokens[$attribute]['type']); @@ -499,7 +494,6 @@ public static function dataAttributeOnTextLookingLikeCloseTag() return [ 'function attribute; string param with "?>"' => [ 'testMarker' => '/* testAttributeContainingTextLookingLikeCloseTag */', - 'length' => 5, 'expectedTokensAttribute' => [ [ 'T_STRING', @@ -536,7 +530,6 @@ public static function dataAttributeOnTextLookingLikeCloseTag() ], 'function attribute; string param with "?>"; multiline' => [ 'testMarker' => '/* testAttributeContainingMultilineTextLookingLikeCloseTag */', - 'length' => 8, 'expectedTokensAttribute' => [ [ 'T_STRING', @@ -648,11 +641,14 @@ public function testNestedAttributes() T_CLOSE_PARENTHESIS, ]; + // Calculate the number of tokens between opener and closer (excluding the opener, including the closer). + $outerAttributeLength = (count($tokenCodes) + 1); + $attribute = $this->getTargetToken('/* testNestedAttributes */', T_ATTRIBUTE); $this->assertArrayHasKey('attribute_closer', $tokens[$attribute]); $closer = $tokens[$attribute]['attribute_closer']; - $this->assertSame(($attribute + 24), $closer); + $this->assertSame(($attribute + $outerAttributeLength), $closer); $this->assertSame(T_ATTRIBUTE_END, $tokens[$closer]['code']); @@ -661,37 +657,39 @@ public function testNestedAttributes() $this->assertArrayNotHasKey('nested_attributes', $tokens[$attribute]); $this->assertArrayHasKey('nested_attributes', $tokens[($attribute + 8)]); - $this->assertSame([$attribute => ($attribute + 24)], $tokens[($attribute + 8)]['nested_attributes']); + $this->assertSame([$attribute => ($attribute + $outerAttributeLength)], $tokens[($attribute + 8)]['nested_attributes']); - $test = function (array $tokens, $length, $nestedMap) use ($attribute) { + $test = function (array $tokens, $outerAttributeLength, $nestedMap) use ($attribute) { foreach ($tokens as $token) { $this->assertArrayHasKey('attribute_closer', $token); - $this->assertSame(($attribute + $length), $token['attribute_closer']); + $this->assertSame(($attribute + $outerAttributeLength), $token['attribute_closer']); $this->assertSame($nestedMap, $token['nested_attributes']); } }; - $test(array_slice($tokens, ($attribute + 1), 7), 24, [$attribute => $attribute + 24]); - $test(array_slice($tokens, ($attribute + 8), 1), 8 + 5, [$attribute => $attribute + 24]); - // Length here is 8 (nested attribute offset) + 5 (real length). + $innerAttributeLength = (8 + 5); + + $test(array_slice($tokens, ($attribute + 1), 7), $outerAttributeLength, [$attribute => $attribute + $outerAttributeLength]); + $test(array_slice($tokens, ($attribute + 8), 1), $innerAttributeLength, [$attribute => $attribute + $outerAttributeLength]); + $test( array_slice($tokens, ($attribute + 9), 4), - 8 + 5, + $innerAttributeLength, [ - $attribute => $attribute + 24, + $attribute => $attribute + $outerAttributeLength, $attribute + 8 => $attribute + 13, ] ); - $test(array_slice($tokens, ($attribute + 13), 1), 8 + 5, [$attribute => $attribute + 24]); - $test(array_slice($tokens, ($attribute + 14), 10), 24, [$attribute => $attribute + 24]); + $test(array_slice($tokens, ($attribute + 13), 1), $innerAttributeLength, [$attribute => $attribute + $outerAttributeLength]); + $test(array_slice($tokens, ($attribute + 14), 10), $outerAttributeLength, [$attribute => $attribute + $outerAttributeLength]); $map = array_map( static function ($token) { return $token['code']; }, - array_slice($tokens, ($attribute + 1), 23) + array_slice($tokens, ($attribute + 1), ($outerAttributeLength - 1)) ); $this->assertSame($tokenCodes, $map); diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillAsymmetricVisibilityTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillAsymmetricVisibilityTest.inc new file mode 100644 index 000000000..aaf050ad5 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillAsymmetricVisibilityTest.inc @@ -0,0 +1,60 @@ + + * @copyright 2025 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +/** + * Tests the support of PHP 8.4 asymmetric visibility. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + */ +final class BackfillAsymmetricVisibilityTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that the asymmetric visibility keywords are tokenized as such. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $testType The expected token type + * @param string $testContent The token content to look for + * + * @dataProvider dataAsymmetricVisibility + * + * @return void + */ + public function testAsymmetricVisibility($testMarker, $testType, $testContent) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken( + $testMarker, + [ + T_PUBLIC_SET, + T_PROTECTED_SET, + T_PRIVATE_SET, + ] + ); + $tokenArray = $tokens[$target]; + + $this->assertSame( + $testType, + $tokenArray['type'], + 'Token tokenized as '.$tokenArray['type'].' (type)' + ); + $this->assertSame( + constant($testType), + $tokenArray['code'], + 'Token tokenized as '.$tokenArray['type'].' (code)' + ); + $this->assertSame( + $testContent, + $tokenArray['content'], + 'Token tokenized as '.$tokenArray['type'].' (content)' + ); + + }//end testAsymmetricVisibility() + + + /** + * Data provider. + * + * @see testAsymmetricVisibility() + * + * @return array> + */ + public static function dataAsymmetricVisibility() + { + return [ + // Normal property declarations. + 'property, public set, no read visibility, lowercase' => [ + 'testMarker' => '/* testPublicSetProperty */', + 'testType' => 'T_PUBLIC_SET', + 'testContent' => 'public(set)', + ], + 'property, public set, no read visibility, uppercase' => [ + 'testMarker' => '/* testPublicSetPropertyUC */', + 'testType' => 'T_PUBLIC_SET', + 'testContent' => 'PUBLIC(SET)', + ], + 'property, public set, has read visibility, lowercase' => [ + 'testMarker' => '/* testPublicPublicSetProperty */', + 'testType' => 'T_PUBLIC_SET', + 'testContent' => 'public(set)', + ], + 'property, public set, has read visibility, uppercase' => [ + 'testMarker' => '/* testPublicPublicSetPropertyUC */', + 'testType' => 'T_PUBLIC_SET', + 'testContent' => 'PUBLIC(SET)', + ], + 'property, protected set, no read visibility, lowercase' => [ + 'testMarker' => '/* testProtectedSetProperty */', + 'testType' => 'T_PROTECTED_SET', + 'testContent' => 'protected(set)', + ], + 'property, protected set, no read visibility, uppercase' => [ + 'testMarker' => '/* testProtectedSetPropertyUC */', + 'testType' => 'T_PROTECTED_SET', + 'testContent' => 'PROTECTED(SET)', + ], + 'property, protected set, has read visibility, lowercase' => [ + 'testMarker' => '/* testPublicProtectedSetProperty */', + 'testType' => 'T_PROTECTED_SET', + 'testContent' => 'protected(set)', + ], + 'property, protected set, has read visibility, uppercase' => [ + 'testMarker' => '/* testPublicProtectedSetPropertyUC */', + 'testType' => 'T_PROTECTED_SET', + 'testContent' => 'PROTECTED(SET)', + ], + 'property, private set, no read visibility, lowercase' => [ + 'testMarker' => '/* testPrivateSetProperty */', + 'testType' => 'T_PRIVATE_SET', + 'testContent' => 'private(set)', + ], + 'property, private set, no read visibility, uppercase' => [ + 'testMarker' => '/* testPrivateSetPropertyUC */', + 'testType' => 'T_PRIVATE_SET', + 'testContent' => 'PRIVATE(SET)', + ], + 'property, private set, has read visibility, lowercase' => [ + 'testMarker' => '/* testPublicPrivateSetProperty */', + 'testType' => 'T_PRIVATE_SET', + 'testContent' => 'private(set)', + ], + 'property, private set, has read visibility, uppercase' => [ + 'testMarker' => '/* testPublicPrivateSetPropertyUC */', + 'testType' => 'T_PRIVATE_SET', + 'testContent' => 'PRIVATE(SET)', + ], + + // Constructor property promotion. + 'promotion, public set, no read visibility, lowercase' => [ + 'testMarker' => '/* testPublicSetCPP */', + 'testType' => 'T_PUBLIC_SET', + 'testContent' => 'public(set)', + ], + 'promotion, public set, no read visibility, uppercase' => [ + 'testMarker' => '/* testPublicSetCPPUC */', + 'testType' => 'T_PUBLIC_SET', + 'testContent' => 'PUBLIC(SET)', + ], + 'promotion, public set, has read visibility, lowercase' => [ + 'testMarker' => '/* testPublicPublicSetCPP */', + 'testType' => 'T_PUBLIC_SET', + 'testContent' => 'public(set)', + ], + 'promotion, public set, has read visibility, uppercase' => [ + 'testMarker' => '/* testPublicPublicSetCPPUC */', + 'testType' => 'T_PUBLIC_SET', + 'testContent' => 'PUBLIC(SET)', + ], + 'promotion, protected set, no read visibility, lowercase' => [ + 'testMarker' => '/* testProtectedSetCPP */', + 'testType' => 'T_PROTECTED_SET', + 'testContent' => 'protected(set)', + ], + 'promotion, protected set, no read visibility, uppercase' => [ + 'testMarker' => '/* testProtectedSetCPPUC */', + 'testType' => 'T_PROTECTED_SET', + 'testContent' => 'PROTECTED(SET)', + ], + 'promotion, protected set, has read visibility, lowercase' => [ + 'testMarker' => '/* testPublicProtectedSetCPP */', + 'testType' => 'T_PROTECTED_SET', + 'testContent' => 'protected(set)', + ], + 'promotion, protected set, has read visibility, uppercase' => [ + 'testMarker' => '/* testPublicProtectedSetCPPUC */', + 'testType' => 'T_PROTECTED_SET', + 'testContent' => 'PROTECTED(SET)', + ], + 'promotion, private set, no read visibility, lowercase' => [ + 'testMarker' => '/* testPrivateSetCPP */', + 'testType' => 'T_PRIVATE_SET', + 'testContent' => 'private(set)', + ], + 'promotion, private set, no read visibility, uppercase' => [ + 'testMarker' => '/* testPrivateSetCPPUC */', + 'testType' => 'T_PRIVATE_SET', + 'testContent' => 'PRIVATE(SET)', + ], + 'promotion, private set, has read visibility, lowercase' => [ + 'testMarker' => '/* testPublicPrivateSetCPP */', + 'testType' => 'T_PRIVATE_SET', + 'testContent' => 'private(set)', + ], + 'promotion, private set, has read visibility, uppercase' => [ + 'testMarker' => '/* testPublicPrivateSetCPPUC */', + 'testType' => 'T_PRIVATE_SET', + 'testContent' => 'PRIVATE(SET)', + ], + ]; + + }//end dataAsymmetricVisibility() + + + /** + * Test that things that are not asymmetric visibility keywords are not + * tokenized as such. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $testType The expected token type + * @param string $testContent The token content to look for + * + * @dataProvider dataNotAsymmetricVisibility + * + * @return void + */ + public function testNotAsymmetricVisibility($testMarker, $testType, $testContent) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken( + $testMarker, + [constant($testType)], + $testContent + ); + $tokenArray = $tokens[$target]; + + $this->assertSame( + $testType, + $tokenArray['type'], + 'Token tokenized as '.$tokenArray['type'].' (type)' + ); + $this->assertSame( + constant($testType), + $tokenArray['code'], + 'Token tokenized as '.$tokenArray['type'].' (code)' + ); + + }//end testNotAsymmetricVisibility() + + + /** + * Data provider. + * + * @see testNotAsymmetricVisibility() + * + * @return array> + */ + public static function dataNotAsymmetricVisibility() + { + return [ + 'property, invalid case 1' => [ + 'testMarker' => '/* testInvalidUnsetProperty */', + 'testType' => 'T_PUBLIC', + 'testContent' => 'public', + ], + 'property, invalid case 2' => [ + 'testMarker' => '/* testInvalidSpaceProperty */', + 'testType' => 'T_PUBLIC', + 'testContent' => 'public', + ], + 'property, invalid case 3' => [ + 'testMarker' => '/* testInvalidCommentProperty */', + 'testType' => 'T_PROTECTED', + 'testContent' => 'protected', + ], + 'property, invalid case 4' => [ + 'testMarker' => '/* testInvalidGetProperty */', + 'testType' => 'T_PRIVATE', + 'testContent' => 'private', + ], + 'property, invalid case 5' => [ + 'testMarker' => '/* testInvalidNoParenProperty */', + 'testType' => 'T_PRIVATE', + 'testContent' => 'private', + ], + + // Constructor property promotion. + 'promotion, invalid case 1' => [ + 'testMarker' => '/* testInvalidUnsetCPP */', + 'testType' => 'T_PUBLIC', + 'testContent' => 'public', + ], + 'promotion, invalid case 2' => [ + 'testMarker' => '/* testInvalidSpaceCPP */', + 'testType' => 'T_PUBLIC', + 'testContent' => 'public', + ], + 'promotion, invalid case 3' => [ + 'testMarker' => '/* testInvalidCommentCPP */', + 'testType' => 'T_PROTECTED', + 'testContent' => 'protected', + ], + 'promotion, invalid case 4' => [ + 'testMarker' => '/* testInvalidGetCPP */', + 'testType' => 'T_PRIVATE', + 'testContent' => 'private', + ], + 'promotion, invalid case 5' => [ + 'testMarker' => '/* testInvalidNoParenCPP */', + 'testType' => 'T_PRIVATE', + 'testContent' => 'private', + ], + + // Context sensitivitiy. + 'protected as function name' => [ + 'testMarker' => '/* testProtectedFunctionName */', + 'testType' => 'T_STRING', + 'testContent' => 'protected', + ], + 'public as function name' => [ + 'testMarker' => '/* testPublicFunctionName */', + 'testType' => 'T_STRING', + 'testContent' => 'public', + ], + 'set as parameter type' => [ + 'testMarker' => '/* testSetParameterType */', + 'testType' => 'T_STRING', + 'testContent' => 'Set', + ], + + // Live coding. + 'live coding' => [ + 'testMarker' => '/* testLiveCoding */', + 'testType' => 'T_PRIVATE', + 'testContent' => 'private', + ], + ]; + + }//end dataNotAsymmetricVisibility() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillEnumTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillEnumTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillEnumTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillEnumTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillEnumTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillEnumTest.php similarity index 98% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillEnumTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillEnumTest.php index 3ce48f655..9b313ca69 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillEnumTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillEnumTest.php @@ -7,7 +7,9 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; final class BackfillEnumTest extends AbstractTokenizerTestCase { diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillExplicitOctalNotationTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillExplicitOctalNotationTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillExplicitOctalNotationTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillExplicitOctalNotationTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillExplicitOctalNotationTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillExplicitOctalNotationTest.php similarity index 97% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillExplicitOctalNotationTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillExplicitOctalNotationTest.php index 609a54c00..7dc3e1392 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillExplicitOctalNotationTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillExplicitOctalNotationTest.php @@ -7,7 +7,9 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; final class BackfillExplicitOctalNotationTest extends AbstractTokenizerTestCase { @@ -17,7 +19,7 @@ final class BackfillExplicitOctalNotationTest extends AbstractTokenizerTestCase * Test that explicitly-defined octal values are tokenized as a single number and not as a number and a string. * * @param string $marker The comment which prefaces the target token in the test file. - * @param string $value The expected content of the token + * @param string $value The expected content of the token. * @param int|string $nextToken The expected next token. * @param string $nextContent The expected content of the next token. * diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenParseErrorTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenParseErrorTest.inc new file mode 100644 index 000000000..ce247e991 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenParseErrorTest.inc @@ -0,0 +1,5 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class BackfillFnTokenParseErrorTest extends AbstractTokenizerTestCase +{ + + + /** + * Verify that un unfinished arrow function during live coding doesn't cause a "Undefined array key "parenthesis_closer"" error. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testUnfinishedArrowFunction() + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken('/* testLiveCoding */', [T_STRING, T_FN], 'fn'); + $tokenArray = $tokens[$token]; + + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING'); + + $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); + $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); + $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); + $this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set'); + $this->assertArrayNotHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is set'); + $this->assertArrayNotHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is set'); + + }//end testUnfinishedArrowFunction() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillFnTokenTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenTest.inc similarity index 79% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillFnTokenTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenTest.inc index 13f165b77..8930d4fbf 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillFnTokenTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenTest.inc @@ -71,10 +71,10 @@ $a = [ /* testYield */ $a = fn($x) => yield 'k' => $x; -/* testNullableNamespace */ +/* testNullableUnqualifiedClassName */ $a = fn(?\DateTime $x) : ?\DateTime => $x; -/* testNamespaceOperatorInTypes */ +/* testNamespaceRelativeClassNameInTypes */ $fn = fn(namespace\Foo $a) : ?namespace\Foo => $a; /* testSelfReturnType */ @@ -92,12 +92,42 @@ fn(array $a) : array => $a; /* testStaticReturnType */ fn(array $a) : static => $a; +/* testFalseReturnType */ +fn(array $a) : false => $a; + +/* testTrueReturnType */ +fn(array $a) : True => $a; + +/* testNullReturnType */ +fn(array $a) : null => $a; + /* testUnionParamType */ $arrowWithUnionParam = fn(int|float $param) : SomeClass => new SomeClass($param); /* testUnionReturnType */ $arrowWithUnionReturn = fn($param) : int|float => $param | 10; +/* testUnionReturnTypeWithTrue */ +$arrowWithUnionReturn = fn($param) : int|true => $param | 10; + +/* testUnionReturnTypeWithFalse */ +$arrowWithUnionReturn = fn($param) : string|FALSE => $param | 10; + +/* testIntersectionParamType */ +$arrowWithIntersectionParam = fn(Traversable&Countable $param) : int => (new SomeClass($param))->getValue(); + +/* testIntersectionReturnType */ +$arrowWithIntersectionReturn = fn($param) : \MyFoo&SomeInterface => new SomeClass($param); + +/* testDNFParamType */ +$arrowWithDNFParam = fn((Traversable&Countable)|null $param) : SomeClass => new SomeClass($param) ?? null; + +/* testDNFReturnType */ +$arrowWithDNFReturn = fn($param) : false|(\MyFoo&SomeInterface) => new \MyFoo($param) ?? false; + +/* testDNFParamTypeWithReturnByRef */ +$arrowWithDNFParamReturnByRef = fn &((A&B)|null $param) => $param * 10; + /* testTernary */ $fn = fn($a) => $a ? /* testTernaryThen */ fn() : string => 'a' : /* testTernaryElse */ fn() : string => 'b'; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillFnTokenTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenTest.php similarity index 78% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillFnTokenTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenTest.php index 8245b1875..e265650ff 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillFnTokenTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillFnTokenTest.php @@ -7,7 +7,9 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; final class BackfillFnTokenTest extends AbstractTokenizerTestCase { @@ -16,21 +18,43 @@ final class BackfillFnTokenTest extends AbstractTokenizerTestCase /** * Test simple arrow functions. * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataSimple + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional * * @return void */ - public function testSimple() + public function testSimple($testMarker) { - foreach (['/* testStandard */', '/* testMixedCase */'] as $comment) { - $token = $this->getTargetToken($comment, T_FN); - $this->backfillHelper($token); - $this->scopePositionTestHelper($token, 5, 12); - } + $token = $this->getTargetToken($testMarker, T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 5, 12); }//end testSimple() + /** + * Data provider. + * + * @see testSimple() + * + * @return array> + */ + public static function dataSimple() + { + return [ + 'standard' => [ + 'testMarker' => '/* testStandard */', + ], + 'mixed case' => [ + 'testMarker' => '/* testMixedCase */', + ], + ]; + + }//end dataSimple() + + /** * Test whitespace inside arrow function definitions. * @@ -338,76 +362,93 @@ public function testYield() /** - * Test arrow functions that use nullable namespace types. + * Test arrow functions that use nullable type with unqualified class name. * * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional * * @return void */ - public function testNullableNamespace() + public function testNullableUnqualifiedClassName() { - $token = $this->getTargetToken('/* testNullableNamespace */', T_FN); + $token = $this->getTargetToken('/* testNullableUnqualifiedClassName */', T_FN); $this->backfillHelper($token); $this->scopePositionTestHelper($token, 15, 18); - }//end testNullableNamespace() + }//end testNullableUnqualifiedClassName() /** - * Test arrow functions that use the namespace operator in the return type. + * Test arrow functions that use namespace relative class name in the return type. * * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional * * @return void */ - public function testNamespaceOperatorInTypes() + public function testNamespaceRelativeClassNameInTypes() { - $token = $this->getTargetToken('/* testNamespaceOperatorInTypes */', T_FN); + $token = $this->getTargetToken('/* testNamespaceRelativeClassNameInTypes */', T_FN); $this->backfillHelper($token); $this->scopePositionTestHelper($token, 16, 19); - }//end testNamespaceOperatorInTypes() + }//end testNamespaceRelativeClassNameInTypes() /** - * Test arrow functions that use self/parent/callable/array/static return types. + * Test arrow functions that use keyword return types. * - * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataKeywordReturnTypes + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional * * @return void */ - public function testKeywordReturnTypes() + public function testKeywordReturnTypes($testMarker) { - $tokens = $this->phpcsFile->getTokens(); - - $testMarkers = [ - 'Self', - 'Parent', - 'Callable', - 'Array', - 'Static', - ]; - - foreach ($testMarkers as $marker) { - $token = $this->getTargetToken('/* test'.$marker.'ReturnType */', T_FN); - $this->backfillHelper($token); - - $expectedScopeOpener = ($token + 11); - $expectedScopeCloser = ($token + 14); + $token = $this->getTargetToken($testMarker, T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 11, 14); - $this->assertSame($expectedScopeOpener, $tokens[$token]['scope_opener'], "Scope opener is not the arrow token (for $marker)"); - $this->assertSame($expectedScopeCloser, $tokens[$token]['scope_closer'], "Scope closer is not the semicolon token(for $marker)"); + }//end testKeywordReturnTypes() - $opener = $tokens[$token]['scope_opener']; - $this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], "Opener scope opener is not the arrow token(for $marker)"); - $this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], "Opener scope closer is not the semicolon token(for $marker)"); - $closer = $tokens[$token]['scope_closer']; - $this->assertSame($expectedScopeOpener, $tokens[$closer]['scope_opener'], "Closer scope opener is not the arrow token(for $marker)"); - $this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], "Closer scope closer is not the semicolon token(for $marker)"); - } + /** + * Data provider. + * + * @see testKeywordReturnTypes() + * + * @return array> + */ + public static function dataKeywordReturnTypes() + { + return [ + 'self' => [ + 'testMarker' => '/* testSelfReturnType */', + ], + 'parent' => [ + 'testMarker' => '/* testParentReturnType */', + ], + 'callable' => [ + 'testMarker' => '/* testCallableReturnType */', + ], + 'array' => [ + 'testMarker' => '/* testArrayReturnType */', + ], + 'static' => [ + 'testMarker' => '/* testStaticReturnType */', + ], + 'false' => [ + 'testMarker' => '/* testFalseReturnType */', + ], + 'true' => [ + 'testMarker' => '/* testTrueReturnType */', + ], + 'null' => [ + 'testMarker' => '/* testNullReturnType */', + ], + ]; - }//end testKeywordReturnTypes() + }//end dataKeywordReturnTypes() /** @@ -442,6 +483,118 @@ public function testUnionReturnType() }//end testUnionReturnType() + /** + * Test arrow function with a union return type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testUnionReturnTypeWithTrue() + { + $token = $this->getTargetToken('/* testUnionReturnTypeWithTrue */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 11, 18); + + }//end testUnionReturnTypeWithTrue() + + + /** + * Test arrow function with a union return type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testUnionReturnTypeWithFalse() + { + $token = $this->getTargetToken('/* testUnionReturnTypeWithFalse */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 11, 18); + + }//end testUnionReturnTypeWithFalse() + + + /** + * Test arrow function with an intersection parameter type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testIntersectionParamType() + { + $token = $this->getTargetToken('/* testIntersectionParamType */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 13, 27); + + }//end testIntersectionParamType() + + + /** + * Test arrow function with an intersection return type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testIntersectionReturnType() + { + $token = $this->getTargetToken('/* testIntersectionReturnType */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 12, 20); + + }//end testIntersectionReturnType() + + + /** + * Test arrow function with a DNF parameter type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testDNFParamType() + { + $token = $this->getTargetToken('/* testDNFParamType */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 17, 29); + + }//end testDNFParamType() + + + /** + * Test arrow function with a DNF return type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testDNFReturnType() + { + $token = $this->getTargetToken('/* testDNFReturnType */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 16, 29); + + }//end testDNFReturnType() + + + /** + * Test arrow function which returns by reference with a DNF parameter type. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testDNFParamTypeWithReturnByRef() + { + $token = $this->getTargetToken('/* testDNFParamTypeWithReturnByRef */', T_FN); + $this->backfillHelper($token); + $this->scopePositionTestHelper($token, 15, 22); + + }//end testDNFParamTypeWithReturnByRef() + + /** * Test arrow functions used in ternary operators. * @@ -503,8 +656,6 @@ public function testTernary() */ public function testTernaryWithTypes() { - $tokens = $this->phpcsFile->getTokens(); - $token = $this->getTargetToken('/* testTernaryWithTypes */', T_FN); $this->backfillHelper($token); $this->scopePositionTestHelper($token, 15, 27); @@ -745,37 +896,37 @@ private function backfillHelper($token, $skipScopeCloserCheck=false) { $tokens = $this->phpcsFile->getTokens(); - $this->assertTrue(array_key_exists('scope_condition', $tokens[$token]), 'Scope condition is not set'); - $this->assertTrue(array_key_exists('scope_opener', $tokens[$token]), 'Scope opener is not set'); - $this->assertTrue(array_key_exists('scope_closer', $tokens[$token]), 'Scope closer is not set'); + $this->assertArrayHasKey('scope_condition', $tokens[$token], 'Scope condition is not set'); + $this->assertArrayHasKey('scope_opener', $tokens[$token], 'Scope opener is not set'); + $this->assertArrayHasKey('scope_closer', $tokens[$token], 'Scope closer is not set'); $this->assertSame($tokens[$token]['scope_condition'], $token, 'Scope condition is not the T_FN token'); - $this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$token]), 'Parenthesis owner is not set'); - $this->assertTrue(array_key_exists('parenthesis_opener', $tokens[$token]), 'Parenthesis opener is not set'); - $this->assertTrue(array_key_exists('parenthesis_closer', $tokens[$token]), 'Parenthesis closer is not set'); + $this->assertArrayHasKey('parenthesis_owner', $tokens[$token], 'Parenthesis owner is not set'); + $this->assertArrayHasKey('parenthesis_opener', $tokens[$token], 'Parenthesis opener is not set'); + $this->assertArrayHasKey('parenthesis_closer', $tokens[$token], 'Parenthesis closer is not set'); $this->assertSame($tokens[$token]['parenthesis_owner'], $token, 'Parenthesis owner is not the T_FN token'); $opener = $tokens[$token]['scope_opener']; - $this->assertTrue(array_key_exists('scope_condition', $tokens[$opener]), 'Opener scope condition is not set'); - $this->assertTrue(array_key_exists('scope_opener', $tokens[$opener]), 'Opener scope opener is not set'); - $this->assertTrue(array_key_exists('scope_closer', $tokens[$opener]), 'Opener scope closer is not set'); + $this->assertArrayHasKey('scope_condition', $tokens[$opener], 'Opener scope condition is not set'); + $this->assertArrayHasKey('scope_opener', $tokens[$opener], 'Opener scope opener is not set'); + $this->assertArrayHasKey('scope_closer', $tokens[$opener], 'Opener scope closer is not set'); $this->assertSame($tokens[$opener]['scope_condition'], $token, 'Opener scope condition is not the T_FN token'); $this->assertSame(T_FN_ARROW, $tokens[$opener]['code'], 'Arrow scope opener not tokenized as T_FN_ARROW (code)'); $this->assertSame('T_FN_ARROW', $tokens[$opener]['type'], 'Arrow scope opener not tokenized as T_FN_ARROW (type)'); $closer = $tokens[$token]['scope_closer']; - $this->assertTrue(array_key_exists('scope_condition', $tokens[$closer]), 'Closer scope condition is not set'); - $this->assertTrue(array_key_exists('scope_opener', $tokens[$closer]), 'Closer scope opener is not set'); - $this->assertTrue(array_key_exists('scope_closer', $tokens[$closer]), 'Closer scope closer is not set'); + $this->assertArrayHasKey('scope_condition', $tokens[$closer], 'Closer scope condition is not set'); + $this->assertArrayHasKey('scope_opener', $tokens[$closer], 'Closer scope opener is not set'); + $this->assertArrayHasKey('scope_closer', $tokens[$closer], 'Closer scope closer is not set'); if ($skipScopeCloserCheck === false) { $this->assertSame($tokens[$closer]['scope_condition'], $token, 'Closer scope condition is not the T_FN token'); } $opener = $tokens[$token]['parenthesis_opener']; - $this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$opener]), 'Opening parenthesis owner is not set'); + $this->assertArrayHasKey('parenthesis_owner', $tokens[$opener], 'Opening parenthesis owner is not set'); $this->assertSame($tokens[$opener]['parenthesis_owner'], $token, 'Opening parenthesis owner is not the T_FN token'); $closer = $tokens[$token]['parenthesis_closer']; - $this->assertTrue(array_key_exists('parenthesis_owner', $tokens[$closer]), 'Closing parenthesis owner is not set'); + $this->assertArrayHasKey('parenthesis_owner', $tokens[$closer], 'Closing parenthesis owner is not set'); $this->assertSame($tokens[$closer]['parenthesis_owner'], $token, 'Closing parenthesis owner is not the T_FN token'); }//end backfillHelper() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillMatchTokenTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillMatchTokenTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillMatchTokenTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillMatchTokenTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillMatchTokenTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillMatchTokenTest.php similarity index 95% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillMatchTokenTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillMatchTokenTest.php index 9f7df3540..8214ea1a9 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillMatchTokenTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillMatchTokenTest.php @@ -8,8 +8,9 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; use PHP_CodeSniffer\Util\Tokens; final class BackfillMatchTokenTest extends AbstractTokenizerTestCase @@ -461,16 +462,16 @@ public static function dataSwitchCaseVersusMatch() * Helper function to verify that all scope related array indexes for a control structure * are set correctly. * - * @param string $token The control structure token to check. - * @param int $openerOffset The expected offset of the scope opener in relation to - * the control structure token. - * @param int $closerOffset The expected offset of the scope closer in relation to - * the control structure token. - * @param bool $skipScopeCloserCheck Whether to skip the scope closer check. - * This should be set to "true" when testing nested arrow functions, - * where the "inner" arrow function shares a scope closer with the - * "outer" arrow function, as the 'scope_condition' for the scope closer - * of the "inner" arrow function will point to the "outer" arrow function. + * @param int $token The control structure token to check. + * @param int $openerOffset The expected offset of the scope opener in relation to + * the control structure token. + * @param int $closerOffset The expected offset of the scope closer in relation to + * the control structure token. + * @param bool $skipScopeCloserCheck Whether to skip the scope closer check. + * This should be set to "true" when testing nested arrow functions, + * where the "inner" arrow function shares a scope closer with the + * "outer" arrow function, as the 'scope_condition' for the scope closer + * of the "inner" arrow function will point to the "outer" arrow function. * * @return void */ diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillNumericSeparatorTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillNumericSeparatorTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillNumericSeparatorTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillNumericSeparatorTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillNumericSeparatorTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillNumericSeparatorTest.php similarity index 99% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillNumericSeparatorTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillNumericSeparatorTest.php index b27dd8a05..92bc59bcc 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillNumericSeparatorTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillNumericSeparatorTest.php @@ -7,8 +7,9 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; use PHP_CodeSniffer\Util\Tokens; final class BackfillNumericSeparatorTest extends AbstractTokenizerTestCase diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillReadonlyTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillReadonlyTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillReadonlyTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillReadonlyTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillReadonlyTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillReadonlyTest.php similarity index 99% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillReadonlyTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillReadonlyTest.php index 0befb47b7..89dc3e19d 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BackfillReadonlyTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BackfillReadonlyTest.php @@ -7,7 +7,9 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; final class BackfillReadonlyTest extends AbstractTokenizerTestCase { diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BitwiseOrTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BitwiseOrTest.inc similarity index 82% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BitwiseOrTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BitwiseOrTest.inc index 5afc1e5bd..822b4413c 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BitwiseOrTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BitwiseOrTest.inc @@ -75,6 +75,27 @@ class TypeUnion /* testTypeUnionPropertyWithOnlyStaticKeyword */ static Foo|Bar $obj; + /* testTypeUnionWithPHP84FinalKeyword */ + final int|string $finalKeywordA; + + /* testTypeUnionWithPHP84FinalKeywordFirst */ + final private float|null $finalKeywordB; + + /* testTypeUnionWithPHP84FinalKeywordAndFQN */ + final \MyClass|false $finalKeywordC; + + /* testTypeUnionPropertyPrivateSet */ + private(set) Foo|Bar $asym1; + + /* testTypeUnionPropertyPublicPrivateSet */ + public private(set) Foo|Bar $asym2; + + /* testTypeUnionPropertyProtected */ + protected(set) Foo|Bar $asym3; + + /* testTypeUnionPropertyPublicProtected */ + public protected(set) Foo|Bar $asym4; + public function paramTypes( /* testTypeUnionParam1 */ int|float $paramA /* testBitwiseOrParamDefaultValue */ = CONSTANT_A | CONSTANT_B, @@ -121,6 +142,19 @@ function globalFunctionWithSpreadAndReference( string|int ...$paramB ) {} +$dnfTypes = new class { + /* testTypeUnionConstantTypeUnionBeforeDNF */ + const Foo|(A&B) UNION_BEFORE = /* testBitwiseOrOOConstDefaultValueDNF */ Foo|(A&B); + + /* testTypeUnionPropertyTypeUnionAfterDNF */ + protected (\FQN&namespace\Relative)|Partially\Qualified $union_after = /* testBitwiseOrPropertyDefaultValueDNF */ (A&B)|Foo; + + public function unionBeforeAndAfter( + /* testTypeUnionParamUnionBeforeAndAfterDNF */ + string|(Stringable&\Countable)|int $param = /* testBitwiseOrParamDefaultValueDNF */ ( CONST_A & CONST_B) | CONST_C + ): /* testTypeUnionReturnTypeUnionAfterDNF */ (A&B)|null {} +}; + /* testTypeUnionClosureParamIllegalNullable */ $closureWithParamType = function (?string|null $string) {}; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BitwiseOrTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BitwiseOrTest.php similarity index 69% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BitwiseOrTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BitwiseOrTest.php index 8e3e264f5..bfe409aed 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/BitwiseOrTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/BitwiseOrTest.php @@ -7,7 +7,9 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; final class BitwiseOrTest extends AbstractTokenizerTestCase { @@ -45,22 +47,25 @@ public function testBitwiseOr($testMarker) public static function dataBitwiseOr() { return [ - 'in simple assignment 1' => ['/* testBitwiseOr1 */'], - 'in simple assignment 2' => ['/* testBitwiseOr2 */'], - 'in OO constant default value' => ['/* testBitwiseOrOOConstDefaultValue */'], - 'in property default value' => ['/* testBitwiseOrPropertyDefaultValue */'], - 'in method parameter default value' => ['/* testBitwiseOrParamDefaultValue */'], - 'in return statement' => ['/* testBitwiseOr3 */'], - 'in closure parameter default value' => ['/* testBitwiseOrClosureParamDefault */'], - 'in arrow function parameter default value' => ['/* testBitwiseOrArrowParamDefault */'], - 'in arrow function return expression' => ['/* testBitwiseOrArrowExpression */'], - 'in long array key' => ['/* testBitwiseOrInArrayKey */'], - 'in long array value' => ['/* testBitwiseOrInArrayValue */'], - 'in short array key' => ['/* testBitwiseOrInShortArrayKey */'], - 'in short array value' => ['/* testBitwiseOrInShortArrayValue */'], - 'in catch condition' => ['/* testBitwiseOrTryCatch */'], - 'in parameter in function call' => ['/* testBitwiseOrNonArrowFnFunctionCall */'], - 'live coding / undetermined' => ['/* testLiveCoding */'], + 'in simple assignment 1' => ['/* testBitwiseOr1 */'], + 'in simple assignment 2' => ['/* testBitwiseOr2 */'], + 'in OO constant default value' => ['/* testBitwiseOrOOConstDefaultValue */'], + 'in property default value' => ['/* testBitwiseOrPropertyDefaultValue */'], + 'in method parameter default value' => ['/* testBitwiseOrParamDefaultValue */'], + 'in return statement' => ['/* testBitwiseOr3 */'], + 'in closure parameter default value' => ['/* testBitwiseOrClosureParamDefault */'], + 'in OO constant default value DNF-like' => ['/* testBitwiseOrOOConstDefaultValueDNF */'], + 'in property default value DNF-like' => ['/* testBitwiseOrPropertyDefaultValueDNF */'], + 'in method parameter default value DNF-like' => ['/* testBitwiseOrParamDefaultValueDNF */'], + 'in arrow function parameter default value' => ['/* testBitwiseOrArrowParamDefault */'], + 'in arrow function return expression' => ['/* testBitwiseOrArrowExpression */'], + 'in long array key' => ['/* testBitwiseOrInArrayKey */'], + 'in long array value' => ['/* testBitwiseOrInArrayValue */'], + 'in short array key' => ['/* testBitwiseOrInShortArrayKey */'], + 'in short array value' => ['/* testBitwiseOrInShortArrayValue */'], + 'in catch condition' => ['/* testBitwiseOrTryCatch */'], + 'in parameter in function call' => ['/* testBitwiseOrNonArrowFnFunctionCall */'], + 'live coding / undetermined' => ['/* testLiveCoding */'], ]; }//end dataBitwiseOr() @@ -120,6 +125,13 @@ public static function dataTypeUnion() 'type for readonly property, reversed modifier order' => ['/* testTypeUnionPropertyWithReadOnlyKeywordFirst */'], 'type for readonly property, no visibility' => ['/* testTypeUnionPropertyWithOnlyReadOnlyKeyword */'], 'type for static property, no visibility' => ['/* testTypeUnionPropertyWithOnlyStaticKeyword */'], + 'type for final property, no visibility' => ['/* testTypeUnionWithPHP84FinalKeyword */'], + 'type for final property, reversed modifier order' => ['/* testTypeUnionWithPHP84FinalKeywordFirst */'], + 'type for final property, no visibility, FQN type' => ['/* testTypeUnionWithPHP84FinalKeywordAndFQN */'], + 'type for private(set) property' => ['/* testTypeUnionPropertyPrivateSet */'], + 'type for public private(set) property' => ['/* testTypeUnionPropertyPublicPrivateSet */'], + 'type for protected(set) property' => ['/* testTypeUnionPropertyProtected */'], + 'type for public protected(set) property' => ['/* testTypeUnionPropertyPublicProtected */'], 'type for method parameter' => ['/* testTypeUnionParam1 */'], 'type for method parameter, first in multi-union' => ['/* testTypeUnionParam2 */'], 'type for method parameter, last in multi-union' => ['/* testTypeUnionParam3 */'], @@ -135,14 +147,18 @@ public static function dataTypeUnion() 'return type for method with fully qualified names' => ['/* testTypeUnionReturnFullyQualified */'], 'type for function parameter with reference' => ['/* testTypeUnionWithReference */'], 'type for function parameter with spread operator' => ['/* testTypeUnionWithSpreadOperator */'], + 'DNF type for OO constant, union before DNF' => ['/* testTypeUnionConstantTypeUnionBeforeDNF */'], + 'DNF type for property, union after DNF' => ['/* testTypeUnionPropertyTypeUnionAfterDNF */'], + 'DNF type for function param, union before and after DNF' => ['/* testTypeUnionParamUnionBeforeAndAfterDNF */'], + 'DNF type for function return, union after DNF with null' => ['/* testTypeUnionReturnTypeUnionAfterDNF */'], 'type for closure parameter with illegal nullable' => ['/* testTypeUnionClosureParamIllegalNullable */'], 'return type for closure' => ['/* testTypeUnionClosureReturn */'], 'type for arrow function parameter' => ['/* testTypeUnionArrowParam */'], 'return type for arrow function' => ['/* testTypeUnionArrowReturnType */'], 'type for function parameter, return by ref' => ['/* testTypeUnionNonArrowFunctionDeclaration */'], 'type for function param with true type first' => ['/* testTypeUnionPHP82TrueFirst */'], - 'type for function param with true type middle' => ['/* testTypeUnionPHP82TrueMiddle */'], - 'type for function param with true type last' => ['/* testTypeUnionPHP82TrueLast */'], + 'return type for function with true type middle' => ['/* testTypeUnionPHP82TrueMiddle */'], + 'return type for closure with true type last' => ['/* testTypeUnionPHP82TrueLast */'], ]; }//end dataTypeUnion() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ContextSensitiveKeywordsTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ContextSensitiveKeywordsTest.inc similarity index 95% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ContextSensitiveKeywordsTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ContextSensitiveKeywordsTest.inc index 2d471285c..e019dfe8a 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ContextSensitiveKeywordsTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ContextSensitiveKeywordsTest.inc @@ -102,6 +102,10 @@ namespace /* testNamespaceNameIsString1 */ my\ /* testNamespaceNameIsString2 */ /* testProtectedIsKeyword */ protected $protected; /* testPublicIsKeyword */ public $public; + /* testPrivateSetIsKeyword */ private(set) mixed $privateSet; + /* testProtectedSetIsKeyword */ protected(set) mixed $protectedSet; + /* testPublicSetIsKeyword */ public(set) mixed $publicSet; + /* testVarIsKeyword */ var $var; /* testStaticIsKeyword */ static $static; @@ -235,3 +239,10 @@ $obj-> /* testKeywordAsMethodCallNameShouldBeStringStatic */ static(); $function = /* testStaticIsKeywordBeforeClosure */ static function(/* testStaticIsKeywordWhenParamType */ static $param) {}; $arrow = /* testStaticIsKeywordBeforeArrow */ static fn(): /* testStaticIsKeywordWhenReturnType */ static => 10; + +/* testKeywordAsFunctionCallNameShouldBeStringStaticDNFLookaLike */ +$obj->static((CONST_A&CONST_B)|CONST_C | $var); + +class DNF { + public /* testStaticIsKeywordPropertyModifierBeforeDNF */ static (DN&F)|null $dnfProp; +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ContextSensitiveKeywordsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ContextSensitiveKeywordsTest.php similarity index 94% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ContextSensitiveKeywordsTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ContextSensitiveKeywordsTest.php index 51c545387..09ff9050f 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ContextSensitiveKeywordsTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ContextSensitiveKeywordsTest.php @@ -7,8 +7,9 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; use PHP_CodeSniffer\Util\Tokens; final class ContextSensitiveKeywordsTest extends AbstractTokenizerTestCase @@ -135,6 +136,7 @@ public static function dataStrings() 'function call: static' => ['/* testKeywordAsFunctionCallNameShouldBeStringStatic */'], 'method call: static' => ['/* testKeywordAsMethodCallNameShouldBeStringStatic */'], + 'method call: static with dnf look a like param' => ['/* testKeywordAsFunctionCallNameShouldBeStringStaticDNFLookaLike */'], ]; }//end dataStrings() @@ -153,8 +155,16 @@ public static function dataStrings() */ public function testKeywords($testMarker, $expectedTokenType) { + $tokenTargets = Tokens::$contextSensitiveKeywords; + $tokenTargets[] = T_STRING; + $tokenTargets[] = T_ANON_CLASS; + $tokenTargets[] = T_MATCH_DEFAULT; + $tokenTargets[] = T_PRIVATE_SET; + $tokenTargets[] = T_PROTECTED_SET; + $tokenTargets[] = T_PUBLIC_SET; + $tokens = $this->phpcsFile->getTokens(); - $target = $this->getTargetToken($testMarker, (Tokens::$contextSensitiveKeywords + [T_ANON_CLASS, T_MATCH_DEFAULT, T_STRING])); + $target = $this->getTargetToken($testMarker, $tokenTargets); $tokenArray = $tokens[$target]; $this->assertSame( @@ -176,7 +186,7 @@ public function testKeywords($testMarker, $expectedTokenType) * * @see testKeywords() * - * @return array + * @return array> */ public static function dataKeywords() { @@ -242,6 +252,18 @@ public static function dataKeywords() 'testMarker' => '/* testPublicIsKeyword */', 'expectedTokenType' => 'T_PUBLIC', ], + 'private(set): property declaration' => [ + 'testMarker' => '/* testPrivateSetIsKeyword */', + 'expectedTokenType' => 'T_PRIVATE_SET', + ], + 'protected(set): property declaration' => [ + 'testMarker' => '/* testProtectedSetIsKeyword */', + 'expectedTokenType' => 'T_PROTECTED_SET', + ], + 'public(set): property declaration' => [ + 'testMarker' => '/* testPublicSetIsKeyword */', + 'expectedTokenType' => 'T_PUBLIC_SET', + ], 'var: property declaration' => [ 'testMarker' => '/* testVarIsKeyword */', 'expectedTokenType' => 'T_VAR', @@ -534,6 +556,10 @@ public static function dataKeywords() 'testMarker' => '/* testStaticIsKeywordWhenReturnType */', 'expectedTokenType' => 'T_STATIC', ], + 'static: property modifier before DNF' => [ + 'testMarker' => '/* testStaticIsKeywordPropertyModifierBeforeDNF */', + 'expectedTokenType' => 'T_STATIC', + ], ]; }//end dataKeywords() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesParseError1Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesParseError1Test.inc new file mode 100644 index 000000000..a6cf511c2 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesParseError1Test.inc @@ -0,0 +1,17 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class DNFTypesParseError1Test extends AbstractTokenizerTestCase +{ + + + /** + * Document handling for a DNF type / parse error where the last significant type specific token is an open parenthesis. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataBrokenDNFTypeCantEndOnOpenParenthesis + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testBrokenDNFTypeCantEndOnOpenParenthesis($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + + $openPtr = $this->getTargetToken($testMarker, [T_OPEN_PARENTHESIS, T_TYPE_OPEN_PARENTHESIS], '('); + $token = $tokens[$openPtr]; + + // Verify that the open parenthesis is tokenized as a normal parenthesis. + $this->assertSame(T_OPEN_PARENTHESIS, $token['code'], 'Token tokenized as '.$token['type'].', not T_OPEN_PARENTHESIS (code)'); + $this->assertSame('T_OPEN_PARENTHESIS', $token['type'], 'Token tokenized as '.$token['type'].', not T_OPEN_PARENTHESIS (type)'); + + // Verify that the type union is still tokenized as T_BITWISE_OR as the type declaration + // is not recognized as a valid type declaration. + $unionPtr = $this->getTargetToken($testMarker, [T_BITWISE_OR, T_TYPE_UNION], '|'); + $token = $tokens[$unionPtr]; + + $this->assertSame(T_BITWISE_OR, $token['code'], 'Token tokenized as '.$token['type'].', not T_BITWISE_OR (code)'); + $this->assertSame('T_BITWISE_OR', $token['type'], 'Token tokenized as '.$token['type'].', not T_BITWISE_OR (type)'); + + }//end testBrokenDNFTypeCantEndOnOpenParenthesis() + + + /** + * Data provider. + * + * @see testBrokenDNFTypeCantEndOnOpenParenthesis() + * + * @return array> + */ + public static function dataBrokenDNFTypeCantEndOnOpenParenthesis() + { + return [ + 'OO const type' => ['/* testBrokenConstDNFTypeEndOnOpenParenthesis */'], + 'OO property type' => ['/* testBrokenPropertyDNFTypeEndOnOpenParenthesis */'], + 'Parameter type' => ['/* testBrokenParamDNFTypeEndOnOpenParenthesis */'], + 'Return type' => ['/* testBrokenReturnDNFTypeEndOnOpenParenthesis */'], + ]; + + }//end dataBrokenDNFTypeCantEndOnOpenParenthesis() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesParseError2Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesParseError2Test.inc new file mode 100644 index 000000000..792975828 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesParseError2Test.inc @@ -0,0 +1,48 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +final class DNFTypesParseError2Test extends AbstractTokenizerTestCase +{ + + + /** + * Document handling for a DNF type / parse error where the type declaration contains an unmatched parenthesis. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataBrokenDNFTypeParensShouldAlwaysBeAPairMissingCloseParens + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testBrokenDNFTypeParensShouldAlwaysBeAPairMissingCloseParens($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + + // Verify that the type union is still tokenized as T_BITWISE_OR as the type declaration + // is not recognized as a valid type declaration. + $unionPtr = $this->getTargetToken($testMarker, [T_BITWISE_OR, T_TYPE_UNION], '|'); + $token = $tokens[$unionPtr]; + + $this->assertSame(T_BITWISE_OR, $token['code'], 'Token tokenized as '.$token['type'].', not T_BITWISE_OR (code)'); + $this->assertSame('T_BITWISE_OR', $token['type'], 'Token tokenized as '.$token['type'].', not T_BITWISE_OR (type)'); + + // Verify that the unmatched open parenthesis is tokenized as a normal parenthesis. + $openPtr = $this->getTargetToken($testMarker, [T_OPEN_PARENTHESIS, T_TYPE_OPEN_PARENTHESIS], '('); + $token = $tokens[$openPtr]; + + $this->assertSame(T_OPEN_PARENTHESIS, $token['code'], 'Token tokenized as '.$token['type'].', not T_OPEN_PARENTHESIS (code)'); + $this->assertSame('T_OPEN_PARENTHESIS', $token['type'], 'Token tokenized as '.$token['type'].', not T_OPEN_PARENTHESIS (type)'); + + // Verify that the type intersection is still tokenized as T_BITWISE_AND as the type declaration + // is not recognized as a valid type declaration. + $intersectPtr = $this->getTargetToken($testMarker, [T_BITWISE_AND, T_TYPE_INTERSECTION], '&'); + $token = $tokens[$intersectPtr]; + + $this->assertSame(T_BITWISE_AND, $token['code'], 'Token tokenized as '.$token['type'].', not T_BITWISE_AND (code)'); + $this->assertSame('T_BITWISE_AND', $token['type'], 'Token tokenized as '.$token['type'].', not T_BITWISE_AND (type)'); + + }//end testBrokenDNFTypeParensShouldAlwaysBeAPairMissingCloseParens() + + + /** + * Data provider. + * + * @see testBrokenDNFTypeParensShouldAlwaysBeAPairMissingCloseParens() + * + * @return array> + */ + public static function dataBrokenDNFTypeParensShouldAlwaysBeAPairMissingCloseParens() + { + return [ + 'OO const type' => ['/* testBrokenConstDNFTypeParensMissingClose */'], + 'OO property type' => ['/* testBrokenPropertyDNFTypeParensMissingClose */'], + 'Parameter type' => ['/* testBrokenParamDNFTypeParensMissingClose */'], + 'Return type' => ['/* testBrokenReturnDNFTypeParensMissingClose */'], + ]; + + }//end dataBrokenDNFTypeParensShouldAlwaysBeAPairMissingCloseParens() + + + /** + * Document handling for a DNF type / parse error where the type declaration contains an unmatched parenthesis. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataBrokenDNFTypeParensShouldAlwaysBeAPairMissingOpenParens + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testBrokenDNFTypeParensShouldAlwaysBeAPairMissingOpenParens($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + + // Verify that the type union is still tokenized as T_BITWISE_OR as the type declaration + // is not recognized as a valid type declaration. + $unionPtr = $this->getTargetToken($testMarker, [T_BITWISE_OR, T_TYPE_UNION], '|'); + $token = $tokens[$unionPtr]; + + $this->assertSame(T_BITWISE_OR, $token['code'], 'Token tokenized as '.$token['type'].', not T_BITWISE_OR (code)'); + $this->assertSame('T_BITWISE_OR', $token['type'], 'Token tokenized as '.$token['type'].', not T_BITWISE_OR (type)'); + + // Verify that the unmatched open parenthesis is tokenized as a normal parenthesis. + $closePtr = $this->getTargetToken($testMarker, [T_CLOSE_PARENTHESIS, T_TYPE_CLOSE_PARENTHESIS], ')'); + $token = $tokens[$closePtr]; + + $this->assertSame(T_CLOSE_PARENTHESIS, $token['code'], 'Token tokenized as '.$token['type'].', not T_CLOSE_PARENTHESIS (code)'); + $this->assertSame('T_CLOSE_PARENTHESIS', $token['type'], 'Token tokenized as '.$token['type'].', not T_CLOSE_PARENTHESIS (type)'); + + // Verify that the type intersection is still tokenized as T_BITWISE_AND as the type declaration + // is not recognized as a valid type declaration. + $intersectPtr = $this->getTargetToken($testMarker, [T_BITWISE_AND, T_TYPE_INTERSECTION], '&'); + $token = $tokens[$intersectPtr]; + + $this->assertSame(T_BITWISE_AND, $token['code'], 'Token tokenized as '.$token['type'].', not T_BITWISE_AND (code)'); + $this->assertSame('T_BITWISE_AND', $token['type'], 'Token tokenized as '.$token['type'].', not T_BITWISE_AND (type)'); + + }//end testBrokenDNFTypeParensShouldAlwaysBeAPairMissingOpenParens() + + + /** + * Data provider. + * + * @see testBrokenDNFTypeParensShouldAlwaysBeAPairMissingOpenParens() + * + * @return array> + */ + public static function dataBrokenDNFTypeParensShouldAlwaysBeAPairMissingOpenParens() + { + return [ + 'OO const type' => ['/* testBrokenConstDNFTypeParensMissingOpen */'], + 'OO property type' => ['/* testBrokenPropertyDNFTypeParensMissingOpen */'], + 'Parameter type' => ['/* testBrokenParamDNFTypeParensMissingOpen */'], + 'Return type' => ['/* testBrokenReturnDNFTypeParensMissingOpen */'], + ]; + + }//end dataBrokenDNFTypeParensShouldAlwaysBeAPairMissingOpenParens() + + + /** + * Document handling for a DNF type / parse error where the type declaration contains an unmatched parenthesis, + * but also contains a set of matched parentheses. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataBrokenDNFTypeParensShouldAlwaysBeAPairMatchedAndUnmatched + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testBrokenDNFTypeParensShouldAlwaysBeAPairMatchedAndUnmatched($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $startPtr = $this->getTargetToken($testMarker, [T_OPEN_PARENTHESIS, T_TYPE_OPEN_PARENTHESIS], '('); + + for ($i = $startPtr; $i < $this->phpcsFile->numTokens; $i++) { + if (isset(Tokens::$emptyTokens[$tokens[$i]['code']]) === true) { + continue; + } + + if ($tokens[$i]['code'] === T_EQUAL + || $tokens[$i]['code'] === T_VARIABLE + || $tokens[$i]['code'] === T_OPEN_CURLY_BRACKET + ) { + // Reached the end of the type. + break; + } + + $errorPrefix = 'Token tokenized as '.$tokens[$i]['type']; + + // Verify that type tokens have not been retokenized to `T_TYPE_*` tokens for broken type declarations. + switch ($tokens[$i]['content']) { + case '|': + $this->assertSame(T_BITWISE_OR, $tokens[$i]['code'], $errorPrefix.', not T_BITWISE_OR (code)'); + $this->assertSame('T_BITWISE_OR', $tokens[$i]['type'], $errorPrefix.', not T_BITWISE_OR (type)'); + break; + + case '&': + $this->assertSame(T_BITWISE_AND, $tokens[$i]['code'], $errorPrefix.', not T_BITWISE_AND (code)'); + $this->assertSame('T_BITWISE_AND', $tokens[$i]['type'], $errorPrefix.', not T_BITWISE_AND (type)'); + break; + + case '(': + // Verify that the open parenthesis is tokenized as a normal parenthesis. + $this->assertSame(T_OPEN_PARENTHESIS, $tokens[$i]['code'], $errorPrefix.', not T_OPEN_PARENTHESIS (code)'); + $this->assertSame('T_OPEN_PARENTHESIS', $tokens[$i]['type'], $errorPrefix.', not T_OPEN_PARENTHESIS (type)'); + break; + + case ')': + $this->assertSame(T_CLOSE_PARENTHESIS, $tokens[$i]['code'], $errorPrefix.', not T_CLOSE_PARENTHESIS (code)'); + $this->assertSame('T_CLOSE_PARENTHESIS', $tokens[$i]['type'], $errorPrefix.', not T_CLOSE_PARENTHESIS (type)'); + break; + + default: + break; + }//end switch + }//end for + + }//end testBrokenDNFTypeParensShouldAlwaysBeAPairMatchedAndUnmatched() + + + /** + * Data provider. + * + * @see testBrokenDNFTypeParensShouldAlwaysBeAPairMatchedAndUnmatched() + * + * @return array> + */ + public static function dataBrokenDNFTypeParensShouldAlwaysBeAPairMatchedAndUnmatched() + { + return [ + 'OO const type - missing one close parenthesis' => ['/* testBrokenConstDNFTypeParensMissingOneClose */'], + 'OO property type - missing one open parenthesis' => ['/* testBrokenPropertyDNFTypeParensMissingOneOpen */'], + 'Parameter type - missing one close parenthesis' => ['/* testBrokenParamDNFTypeParensMissingOneClose */'], + 'Return type - missing one open parenthesis' => ['/* testBrokenReturnDNFTypeParensMissingOneOpen */'], + ]; + + }//end dataBrokenDNFTypeParensShouldAlwaysBeAPairMatchedAndUnmatched() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesTest.inc new file mode 100644 index 000000000..ae9dc9448 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesTest.inc @@ -0,0 +1,282 @@ + 10 ) {} + +/* testParensOwnerFor */ +for ($i =0; $i < /* testParensNoOwnerInForCondition */ ( CONST_A & CONST_B ); $i++ ); + +/* testParensOwnerMatch */ +$match = match(CONST_A & CONST_B) { + default => $a, +}; + +/* testParensOwnerArray */ +$array = array ( + 'text', + \CONST_A & \Fully\Qualified\CONST_B, + /* testParensNoOwnerFunctionCallWithAmpersandInCallable */ + do_something($a, /* testParensOwnerArrowFn */ fn($b) => $a & $b, $c), +); + +/* testParensOwnerListWithRefVars */ +list(&$a, &$b) = $array; + +/* testParensNoOwnerFunctionCallwithDNFLookALikeParam */ +$obj->static((CONST_A&CONST_B)|CONST_C | $var); + +/* testParensNoOwnerFunctionCallWithDNFLookALikeNamedParamPlain */ +callMe(label: false); + +/* testParensNoOwnerFunctionCallWithDNFLookALikeNamedParamUnion */ +callMe(label: CONST_A | CONST_B); + +/* testParensNoOwnerFunctionCallWithDNFLookALikeNamedParamIntersect */ +callMe(label: CONST_A & CONST_B); + +\Z1\call11( + /* testParensNoOwnerFunctionCallInNamedParam */ + param1: \Z2\call12(), + /* testParensOwnerArrowFunctionInNamedParam */ + param2: fn (): /* testDNFTypeArrowFnReturnInNamedParam */ int|(\Countable&\Iterable) + /* testParensNoOwnerFunctionCallInArrowFnReturn */ + => \Z3\call13(), + /* testParensOwnerClosureInNamedParam */ + param3: function (): /* testDNFTypeClosureReturnInNamedParam */ int|(\DateTime&\ArrayObject) { + /* testParensNoOwnerFunctionCallInClosureReturn */ + return \Z4\call14(); + }, +); + +/* testSwitchControlStructureCondition */ +switch (CONST_A | CONST_B) { + /* testFunctionCallInSwitchCaseCondition */ + case get_bool(): + /* testFunctionCallInSwitchCaseBody */ + \Name\functionInSwitch(); + break; + + default: + /* testFunctionCallInSwitchDefaultBody */ + functionInSwitch(); + break; +} + +/* testIfAlternativeSyntaxCondition */ +if (true): + /* testFunctionCallInIfBody */ + \B\call(); +/* testElseIfAlternativeSyntaxCondition */ +elseif (10): + /* testFunctionCallInElseIfBody */ + C\call(); +else: + /* testFunctionCallInElseBody */ + \C\call3(); +endif; + +gotolabel: + /* testFunctionCallInGotoBody */ + \doSomething(); + +/* testWhileAlternativeSyntaxCondition */ +while ($c3): + /* testFunctionCallInWhileBody */ + \D\call4(); +endwhile; + +/* testForAlternativeSyntaxCondition */ +for ($i = 0; $i < 10; $i++): + /* testFunctionCallInForBody */ + \F\call5(); +endfor; + +/* testForEachAlternativeSyntaxCondition */ +foreach ($array as $key => $value): + /* testFunctionCallInForeachBody */ + \G\call6(); +endforeach; + +/* + * DNF parentheses. + */ + +abstract class DNFTypes { + /* testDNFTypeOOConstUnqualifiedClasses */ + public const (A&B)|D UNQUALIFIED = new Foo; + + /* testDNFTypeOOConstReverseModifierOrder */ + protected final const int|(Foo&Bar)|float MODIFIERS_REVERSED /* testParensNoOwnerOOConstDefaultValue */ = (E_WARNING & E_NOTICE) | E_DEPRECATED; + + const + /* testDNFTypeOOConstMulti1 */ + (A&B) | + /* testDNFTypeOOConstMulti2 */ + (C&D) | // phpcs:ignore Stnd.Cat.Sniff + /* testDNFTypeOOConstMulti3 */ + (Y&D) + | null MULTI_DNF = null; + + /* testDNFTypeOOConstNamespaceRelative */ + final protected const (namespace\Sub\NameA&namespace\Sub\NameB)|namespace\Sub\NameC NAMESPACE_RELATIVE = new namespace\Sub\NameB; + + /* testDNFTypeOOConstPartiallyQualified */ + const Partially\Qualified\NameC|(Partially\Qualified\NameA&Partially\Qualified\NameB) PARTIALLY_QUALIFIED = new Partially\Qualified\NameA; + + /* testDNFTypeOOConstFullyQualified */ + const (\Fully\Qualified\NameA&\Fully\Qualified\NameB)|\Fully\Qualified\NameC FULLY_QUALIFIED = new \Fully\Qualified\NameB(); + + /* testDNFTypePropertyUnqualifiedClasses */ + public static (Foo&Bar)|array $obj; + + /* testDNFTypePropertyReverseModifierOrder */ + static protected string|(A&B)|int $dnf /* testParensNoOwnerPropertyDefaultValue1 */ = ( E_WARNING & E_NOTICE ) | /* testParensNoOwnerPropertyDefaultValue2 */ (E_ALL & E_DEPRECATED); + + private + /* testDNFTypePropertyMultiNamespaceRelative */ + (namespace\Sub\NameA&namespace\Sub\NameB) | + /* testDNFTypePropertyMultiPartiallyQualified */ + (Partially\Qualified\NameA&Partially\Qualified\NameB) | // phpcs:ignore Stnd.Cat.Sniff + false + /* testDNFTypePropertyMultiFullyQualified */ + | (\Fully\Qualified\NameA&\Fully\Qualified\NameB) $multiDnf; + + /* testDNFTypePropertyWithReadOnlyKeyword1 */ + protected readonly (A&B) | /* testDNFTypePropertyWithReadOnlyKeyword2 */ (C&D) $readonly; + + /* testDNFTypePropertyWithStaticAndReadOnlyKeywords */ + static readonly (A&B&C)|array $staticReadonly; + + /* testDNFTypePropertyWithOnlyStaticKeyword */ + static (A&B&C)|true $onlyStaticModified; + + /* testDNFTypeWithPHP84FinalKeyword */ + final (className&InterfaceName)|false $finalKeywordA; + + /* testDNFTypeWithPHP84FinalKeywordAndStatic */ + final static (\className&\InterfaceName)|false $finalKeywordB; + + /* testDNFTypePropertyWithPrivateSet */ + private(set) (A&B&C)|true $asym1; + + /* testDNFTypePropertyWithPublicPrivateSet */ + public private(set) (A&B&C)|true $asym2; + + /* testDNFTypePropertyWithProtectedSet */ + protected(set) (A&B&C)|true $asym3; + + /* testDNFTypePropertyWithPublicProtectedSet */ + public protected(set) (A&B&C)|true $asym4; + + public function paramTypes( + /* testDNFTypeParam1WithAttribute */ + #[MyAttribute] + (\Foo&Bar)|int|float $paramA /* testParensNoOwnerParamDefaultValue */ = SOMETHING | (CONSTANT_A & CONSTANT_B), + + /* testDNFTypeParam2 */ + (Foo&\Bar) /* testDNFTypeParam3 */ |(Baz&Fop) &...$paramB, + ) { + /* testParensNoOwnerInReturnValue1 */ + return ( + /* testParensNoOwnerInReturnValue2 */ + ($a1 & $b1) | + /* testParensNoOwnerInReturnValue3 */ + ($a2 & $b2) + ) + $c; + } + + public function identifierNames( + /* testDNFTypeParamNamespaceRelative */ + (namespace\Sub\NameA&namespace\Sub\NameB)|false $paramA, + /* testDNFTypeParamPartiallyQualified */ + Partially\Qualified\NameC|(Partially\Qualified\NameA&Partially\Qualified\NameB) $paramB, + /* testDNFTypeParamFullyQualified */ + name|(\Fully\Qualified\NameA&\Fully\Qualified\NameB) $paramC, + ) {} + + public function __construct( + /* testDNFTypeConstructorPropertyPromotion1 */ + public (A&B)| /* testDNFTypeConstructorPropertyPromotion2 */ (A&D) $property + ) {} + + public function returnType()/* testDNFTypeReturnType1 */ : A|(B&D)|/* testDNFTypeReturnType2 */(B&W)|null {} + + abstract public function abstractMethod(): /* testDNFTypeAbstractMethodReturnType1 */ (X&Y) /* testDNFTypeAbstractMethodReturnType2 */ |(W&Z); + + public function identifierNamesReturnRelative( + ) : /* testDNFTypeReturnTypeNamespaceRelative */ (namespace\Sub\NameA&namespace\Sub\NameB)|namespace\Sub\NameC {} + + public function identifierNamesReturnPQ( + ) : /* testDNFTypeReturnPartiallyQualified */Partially\Qualified\NameA|(Partially\Qualified\NameB&Partially\Qualified\NameC) {} + + // Illegal type: segments which are strict subsets of others are disallowed, but that's not the concern of the tokenizer. + public function identifierNamesReturnFQ( + ) /* testDNFTypeReturnFullyQualified */ : (\Fully\Qualified\NameA&\Fully\Qualified\NameB)|\Fully\Qualified\NameB {} +} + +function globalFunctionWithSpreadAndReference( + /* testDNFTypeWithReference */ + float|(B&A) &$paramA, + /* testDNFTypeWithSpreadOperator */ + string|(B&D) ...$paramB +) {} + + +$closureWithParamType = function ( /* testDNFTypeClosureParamIllegalNullable */ ?(A&B)|bool $string) {}; + +/* testParensOwnerClosureAmpersandInDefaultValue */ +$closureWithReturnType = function ($string = NONSENSE & FAKE) /* testDNFTypeClosureReturn */ : (\Package\MyA&PackageB)|null {}; + +$closureWithUseAndReturnType = function ($foo) use ($a) /* testDNFTypeClosureWithUseReturn */ : null|(Foo&\Bar)|false {}; + +/* testParensOwnerArrowDNFUsedWithin */ +$arrowWithParamType = fn ( + /* testDNFTypeArrowParam */ + int|(A&B&C)|array $param, + /* testParensNoOwnerAmpersandInDefaultValue */ ?int $int = (CONSTA & CONSTB )| CONST_C +) + /* testParensNoOwnerInArrowReturnExpression */ + => ($param & $foo ) | $int; + +$arrowWithReturnType = fn ($param) : /* testDNFTypeArrowReturnType */ int|(A&B) => $param * 10; + +$arrowWithParamReturnByRef = fn &( + /* testDNFTypeArrowParamWithReturnByRef */ + (A&B)|null $param +) => $param * 10; + +function InvalidSyntaxes( + /* testDNFTypeParamIllegalUnnecessaryParens */ + (A&B) $parensNotNeeded, + + /* testDNFTypeParamIllegalIntersectUnionReversed */ + A&(B|D) $onlyIntersectAllowedWithinParensAndUnionOutside, + + /* testDNFTypeParamIllegalNestedParens */ + A|(B&(D|W)|null) $nestedParensNotAllowed, +) {} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesTest.php new file mode 100644 index 000000000..5ef220ec7 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DNFTypesTest.php @@ -0,0 +1,550 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +final class DNFTypesTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that parentheses when **not** used in a type declaration are correctly tokenized. + * + * @param string $testMarker The comment prefacing the target token. + * @param bool $skipCheckInside Optional. Skip checking correct token type inside the parentheses. + * Use judiciously for combined normal + DNF tests only. + * + * @dataProvider dataNormalParentheses + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testNormalParentheses($testMarker, $skipCheckInside=false) + { + $tokens = $this->phpcsFile->getTokens(); + + $openPtr = $this->getTargetToken($testMarker, [T_OPEN_PARENTHESIS, T_TYPE_OPEN_PARENTHESIS]); + $opener = $tokens[$openPtr]; + + $this->assertSame('(', $opener['content'], 'Content of type open parenthesis is not "("'); + $this->assertSame(T_OPEN_PARENTHESIS, $opener['code'], 'Token tokenized as '.$opener['type'].', not T_OPEN_PARENTHESIS (code)'); + $this->assertSame('T_OPEN_PARENTHESIS', $opener['type'], 'Token tokenized as '.$opener['type'].', not T_OPEN_PARENTHESIS (type)'); + + $closePtr = $opener['parenthesis_closer']; + $closer = $tokens[$closePtr]; + + $this->assertSame(')', $closer['content'], 'Content of type close parenthesis is not ")"'); + $this->assertSame(T_CLOSE_PARENTHESIS, $closer['code'], 'Token tokenized as '.$closer['type'].', not T_CLOSE_PARENTHESIS (code)'); + $this->assertSame('T_CLOSE_PARENTHESIS', $closer['type'], 'Token tokenized as '.$closer['type'].', not T_CLOSE_PARENTHESIS (type)'); + + if ($skipCheckInside === false) { + for ($i = ($openPtr + 1); $i < $closePtr; $i++) { + // If there are ampersands, make sure these are tokenized as bitwise and. + if ($tokens[$i]['content'] === '&') { + $this->assertSame(T_BITWISE_AND, $tokens[$i]['code'], 'Token tokenized as '.$tokens[$i]['type'].', not T_BITWISE_AND (code)'); + $this->assertSame('T_BITWISE_AND', $tokens[$i]['type'], 'Token tokenized as '.$tokens[$i]['type'].', not T_BITWISE_AND (type)'); + } + + // If there are pipes, make sure these are tokenized as bitwise or. + if ($tokens[$i]['content'] === '|') { + $this->assertSame(T_BITWISE_OR, $tokens[$i]['code'], 'Token tokenized as '.$tokens[$i]['type'].', not T_BITWISE_OR (code)'); + $this->assertSame('T_BITWISE_OR', $tokens[$i]['type'], 'Token tokenized as '.$tokens[$i]['type'].', not T_BITWISE_OR (type)'); + } + } + } + + $before = $this->phpcsFile->findPrevious(Tokens::$emptyTokens, ($openPtr - 1), null, true); + if ($before !== false && $tokens[$before]['content'] === '|') { + $this->assertSame( + T_BITWISE_OR, + $tokens[$before]['code'], + 'Token before tokenized as '.$tokens[$before]['type'].', not T_BITWISE_OR (code)' + ); + $this->assertSame( + 'T_BITWISE_OR', + $tokens[$before]['type'], + 'Token before tokenized as '.$tokens[$before]['type'].', not T_BITWISE_OR (type)' + ); + } + + $after = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($closePtr + 1), null, true); + if ($after !== false && $tokens[$after]['content'] === '|') { + $this->assertSame( + T_BITWISE_OR, + $tokens[$after]['code'], + 'Token after tokenized as '.$tokens[$after]['type'].', not T_BITWISE_OR (code)' + ); + $this->assertSame( + 'T_BITWISE_OR', + $tokens[$after]['type'], + 'Token after tokenized as '.$tokens[$after]['type'].', not T_BITWISE_OR (type)' + ); + } + + }//end testNormalParentheses() + + + /** + * Data provider. + * + * @see testNormalParentheses() + * + * @return array> + */ + public static function dataNormalParentheses() + { + // "Owner" offsets are relative to the open parenthesis. + return [ + 'parens without owner' => [ + 'testMarker' => '/* testParensNoOwner */', + ], + 'parens without owner in ternary then' => [ + 'testMarker' => '/* testParensNoOwnerInTernary */', + ], + 'parens without owner in short ternary' => [ + 'testMarker' => '/* testParensNoOwnerInShortTernary */', + ], + 'parens without owner in ternary then (fn call in inline then)' => [ + 'testMarker' => '/* testFnCallParensNoOwnerInTernaryA */', + ], + 'parens without owner in ternary then (fn call in inline else)' => [ + 'testMarker' => '/* testFnCallParensNoOwnerInTernaryB */', + ], + 'parens without owner in short ternary (fn call)' => [ + 'testMarker' => '/* testPFnCallarensNoOwnerInShortTernary */', + ], + 'parens with owner: function; & in default value' => [ + 'testMarker' => '/* testParensOwnerFunctionAmpersandInDefaultValue */', + ], + 'parens with owner: closure; param declared by & ref' => [ + 'testMarker' => '/* testParensOwnerClosureAmpersandParamRef */', + ], + 'parens with owner: if' => [ + 'testMarker' => '/* testParensOwnerIf */', + ], + 'parens without owner in if condition' => [ + 'testMarker' => '/* testParensNoOwnerInIfCondition */', + ], + 'parens with owner: for' => [ + 'testMarker' => '/* testParensOwnerFor */', + ], + 'parens without owner in for condition' => [ + 'testMarker' => '/* testParensNoOwnerInForCondition */', + ], + 'parens with owner: match' => [ + 'testMarker' => '/* testParensOwnerMatch */', + ], + 'parens with owner: array' => [ + 'testMarker' => '/* testParensOwnerArray */', + ], + 'parens without owner in array; function call with & in callable' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallWithAmpersandInCallable */', + ], + 'parens with owner: fn; & in return value' => [ + 'testMarker' => '/* testParensOwnerArrowFn */', + ], + 'parens with owner: list with reference vars' => [ + 'testMarker' => '/* testParensOwnerListWithRefVars */', + ], + 'parens without owner, function call with DNF look-a-like param' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallwithDNFLookALikeParam */', + ], + 'parens without owner, function call, named param' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallWithDNFLookALikeNamedParamPlain */', + ], + 'parens without owner, function call, named param + bitwise or' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallWithDNFLookALikeNamedParamUnion */', + ], + 'parens without owner, function call, named param + bitwise and' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallWithDNFLookALikeNamedParamIntersect */', + ], + 'parens without owner, function call in named param' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallInNamedParam */', + ], + 'parens with owner: fn; in named param' => [ + 'testMarker' => '/* testParensOwnerArrowFunctionInNamedParam */', + ], + 'parens without owner, function call in named param arrow return' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallInArrowFnReturn */', + ], + 'parens with owner: closure; in named param' => [ + 'testMarker' => '/* testParensOwnerClosureInNamedParam */', + ], + 'parens without owner, function call, named param closure return' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallInClosureReturn */', + ], + 'parens with owner: switch condition' => [ + 'testMarker' => '/* testSwitchControlStructureCondition */', + ], + 'parens without owner in switch-case condition' => [ + 'testMarker' => '/* testFunctionCallInSwitchCaseCondition */', + ], + 'parens without owner in switch-case body' => [ + 'testMarker' => '/* testFunctionCallInSwitchCaseBody */', + ], + 'parens without owner in switch-default body' => [ + 'testMarker' => '/* testFunctionCallInSwitchDefaultBody */', + ], + 'parens with owner: if condition, alternative syntax' => [ + 'testMarker' => '/* testIfAlternativeSyntaxCondition */', + ], + 'parens without owner in if body, alternative syntax' => [ + 'testMarker' => '/* testFunctionCallInIfBody */', + ], + 'parens with owner: elseif condition, alternative syntax' => [ + 'testMarker' => '/* testElseIfAlternativeSyntaxCondition */', + ], + 'parens without owner in elseif body, alternative syntax' => [ + 'testMarker' => '/* testFunctionCallInElseIfBody */', + ], + 'parens without owner in else body, alternative syntax' => [ + 'testMarker' => '/* testFunctionCallInElseBody */', + ], + 'parens without owner in goto body' => [ + 'testMarker' => '/* testFunctionCallInGotoBody */', + ], + 'parens with owner: while condition, alternative syntax' => [ + 'testMarker' => '/* testWhileAlternativeSyntaxCondition */', + ], + 'parens without owner in while body, alternative syntax' => [ + 'testMarker' => '/* testFunctionCallInWhileBody */', + ], + 'parens with owner: for condition, alternative syntax' => [ + 'testMarker' => '/* testForAlternativeSyntaxCondition */', + ], + 'parens without owner in for body, alternative syntax' => [ + 'testMarker' => '/* testFunctionCallInForBody */', + ], + 'parens with owner: foreach condition, alternative syntax' => [ + 'testMarker' => '/* testForEachAlternativeSyntaxCondition */', + ], + 'parens without owner in foreach body, alternative syntax' => [ + 'testMarker' => '/* testFunctionCallInForeachBody */', + ], + + 'parens without owner in OO const default value' => [ + 'testMarker' => '/* testParensNoOwnerOOConstDefaultValue */', + ], + 'parens without owner in property default 1' => [ + 'testMarker' => '/* testParensNoOwnerPropertyDefaultValue1 */', + ], + 'parens without owner in property default 2' => [ + 'testMarker' => '/* testParensNoOwnerPropertyDefaultValue2 */', + ], + 'parens without owner in param default value' => [ + 'testMarker' => '/* testParensNoOwnerParamDefaultValue */', + ], + 'parens without owner in return statement 1' => [ + 'testMarker' => '/* testParensNoOwnerInReturnValue1 */', + ], + 'parens without owner in return statement 2' => [ + 'testMarker' => '/* testParensNoOwnerInReturnValue2 */', + ], + 'parens without owner in return statement 3' => [ + 'testMarker' => '/* testParensNoOwnerInReturnValue3 */', + ], + 'parens with owner: closure; & in default value' => [ + 'testMarker' => '/* testParensOwnerClosureAmpersandInDefaultValue */', + ], + 'parens with owner: fn; dnf used within' => [ + 'testMarker' => '/* testParensOwnerArrowDNFUsedWithin */', + 'skipCheckInside' => true, + ], + 'parens without owner: default value for param in arrow function' => [ + 'testMarker' => '/* testParensNoOwnerAmpersandInDefaultValue */', + ], + 'parens without owner in arrow function return expression' => [ + 'testMarker' => '/* testParensNoOwnerInArrowReturnExpression */', + ], + ]; + + }//end dataNormalParentheses() + + + /** + * Test that parentheses when used in a DNF type declaration are correctly tokenized. + * + * Includes verifying that: + * - the tokens between the parentheses all have a "nested_parenthesis" key. + * - all ampersands between the parentheses are tokenized as T_TYPE_INTERSECTION. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataDNFTypeParentheses + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional + * + * @return void + */ + public function testDNFTypeParentheses($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + + $openPtr = $this->getTargetToken($testMarker, [T_OPEN_PARENTHESIS, T_TYPE_OPEN_PARENTHESIS]); + $opener = $tokens[$openPtr]; + + $this->assertSame('(', $opener['content'], 'Content of type open parenthesis is not "("'); + $this->assertSame(T_TYPE_OPEN_PARENTHESIS, $opener['code'], 'Token tokenized as '.$opener['type'].', not T_TYPE_OPEN_PARENTHESIS (code)'); + $this->assertSame('T_TYPE_OPEN_PARENTHESIS', $opener['type'], 'Token tokenized as '.$opener['type'].', not T_TYPE_OPEN_PARENTHESIS (type)'); + + $closePtr = $opener['parenthesis_closer']; + $closer = $tokens[$closePtr]; + + $this->assertSame(')', $closer['content'], 'Content of type close parenthesis is not ")"'); + $this->assertSame(T_TYPE_CLOSE_PARENTHESIS, $closer['code'], 'Token tokenized as '.$closer['type'].', not T_TYPE_CLOSE_PARENTHESIS (code)'); + $this->assertSame('T_TYPE_CLOSE_PARENTHESIS', $closer['type'], 'Token tokenized as '.$closer['type'].', not T_TYPE_CLOSE_PARENTHESIS (type)'); + + $intersectionCount = 0; + for ($i = ($openPtr + 1); $i < $closePtr; $i++) { + if ($tokens[$i]['content'] === '&') { + $this->assertSame( + T_TYPE_INTERSECTION, + $tokens[$i]['code'], + 'Token tokenized as '.$tokens[$i]['type'].', not T_TYPE_INTERSECTION (code)' + ); + $this->assertSame( + 'T_TYPE_INTERSECTION', + $tokens[$i]['type'], + 'Token tokenized as '.$tokens[$i]['type'].', not T_TYPE_INTERSECTION (type)' + ); + ++$intersectionCount; + } + + // Not valid, but that's irrelevant for the tokenization. + if ($tokens[$i]['content'] === '|') { + $this->assertSame(T_TYPE_UNION, $tokens[$i]['code'], 'Token tokenized as '.$tokens[$i]['type'].', not T_TYPE_UNION (code)'); + $this->assertSame('T_TYPE_UNION', $tokens[$i]['type'], 'Token tokenized as '.$tokens[$i]['type'].', not T_TYPE_UNION (type)'); + + // For the purposes of this test, presume it was intended as an intersection. + ++$intersectionCount; + } + }//end for + + $this->assertGreaterThanOrEqual(1, $intersectionCount, 'Did not find an intersection "&" between the DNF type parentheses'); + + $before = $this->phpcsFile->findPrevious(Tokens::$emptyTokens, ($openPtr - 1), null, true); + if ($before !== false && $tokens[$before]['content'] === '|') { + $this->assertSame( + T_TYPE_UNION, + $tokens[$before]['code'], + 'Token before tokenized as '.$tokens[$before]['type'].', not T_TYPE_UNION (code)' + ); + $this->assertSame( + 'T_TYPE_UNION', + $tokens[$before]['type'], + 'Token before tokenized as '.$tokens[$before]['type'].', not T_TYPE_UNION (type)' + ); + } + + // Invalid, but that's not relevant for the tokenization. + if ($before !== false && $tokens[$before]['content'] === '?') { + $this->assertSame( + T_NULLABLE, + $tokens[$before]['code'], + 'Token before tokenized as '.$tokens[$before]['type'].', not T_NULLABLE (code)' + ); + $this->assertSame( + 'T_NULLABLE', + $tokens[$before]['type'], + 'Token before tokenized as '.$tokens[$before]['type'].', not T_NULLABLE (type)' + ); + } + + $after = $this->phpcsFile->findNext(Tokens::$emptyTokens, ($closePtr + 1), null, true); + if ($after !== false && $tokens[$after]['content'] === '|') { + $this->assertSame( + T_TYPE_UNION, + $tokens[$after]['code'], + 'Token after tokenized as '.$tokens[$after]['type'].', not T_TYPE_UNION (code)' + ); + $this->assertSame( + 'T_TYPE_UNION', + $tokens[$after]['type'], + 'Token after tokenized as '.$tokens[$after]['type'].', not T_TYPE_UNION (type)' + ); + } + + }//end testDNFTypeParentheses() + + + /** + * Data provider. + * + * @see testDNFTypeParentheses() + * + * @return array> + */ + public static function dataDNFTypeParentheses() + { + return [ + 'arrow function return type: in named parameter' => [ + 'testMarker' => '/* testDNFTypeArrowFnReturnInNamedParam */', + ], + 'closure return type: in named parameter' => [ + 'testMarker' => '/* testDNFTypeClosureReturnInNamedParam */', + ], + + 'OO const type: unqualified classes' => [ + 'testMarker' => '/* testDNFTypeOOConstUnqualifiedClasses */', + ], + 'OO const type: modifiers in reverse order' => [ + 'testMarker' => '/* testDNFTypeOOConstReverseModifierOrder */', + ], + 'OO const type: multi-dnf part 1' => [ + 'testMarker' => '/* testDNFTypeOOConstMulti1 */', + ], + 'OO const type: multi-dnf part 2' => [ + 'testMarker' => '/* testDNFTypeOOConstMulti2 */', + ], + 'OO const type: multi-dnf part 3' => [ + 'testMarker' => '/* testDNFTypeOOConstMulti3 */', + ], + 'OO const type: namespace relative classes' => [ + 'testMarker' => '/* testDNFTypeOOConstNamespaceRelative */', + ], + 'OO const type: partially qualified classes' => [ + 'testMarker' => '/* testDNFTypeOOConstPartiallyQualified */', + ], + 'OO const type: fully qualified classes' => [ + 'testMarker' => '/* testDNFTypeOOConstFullyQualified */', + ], + + 'OO property type: unqualified classes' => [ + 'testMarker' => '/* testDNFTypePropertyUnqualifiedClasses */', + ], + 'OO property type: modifiers in reverse order' => [ + 'testMarker' => '/* testDNFTypePropertyReverseModifierOrder */', + ], + 'OO property type: multi-dnf namespace relative classes' => [ + 'testMarker' => '/* testDNFTypePropertyMultiNamespaceRelative */', + ], + 'OO property type: multi-dnf partially qualified classes' => [ + 'testMarker' => '/* testDNFTypePropertyMultiPartiallyQualified */', + ], + 'OO property type: multi-dnf fully qualified classes' => [ + 'testMarker' => '/* testDNFTypePropertyMultiFullyQualified */', + ], + 'OO property type: multi-dnf with readonly keyword 1' => [ + 'testMarker' => '/* testDNFTypePropertyWithReadOnlyKeyword1 */', + ], + 'OO property type: multi-dnf with readonly keyword 2' => [ + 'testMarker' => '/* testDNFTypePropertyWithReadOnlyKeyword2 */', + ], + 'OO property type: with static and readonly keywords' => [ + 'testMarker' => '/* testDNFTypePropertyWithStaticAndReadOnlyKeywords */', + ], + 'OO property type: with only static keyword' => [ + 'testMarker' => '/* testDNFTypePropertyWithOnlyStaticKeyword */', + ], + 'OO property type: with only final keyword' => [ + 'testMarker' => '/* testDNFTypeWithPHP84FinalKeyword */', + ], + 'OO property type: with final and static keyword' => [ + 'testMarker' => '/* testDNFTypeWithPHP84FinalKeywordAndStatic */', + ], + 'OO property type: asymmetric visibility, private(set)' => [ + 'testMarker' => '/* testDNFTypePropertyWithPrivateSet */', + ], + 'OO property type: asymmetric vis, public private(set)' => [ + 'testMarker' => '/* testDNFTypePropertyWithPublicPrivateSet */', + ], + 'OO property type: asymmetric visibility, protected(set)' => [ + 'testMarker' => '/* testDNFTypePropertyWithProtectedSet */', + ], + 'OO property type: asymmetric vis, public protected(set)' => [ + 'testMarker' => '/* testDNFTypePropertyWithPublicProtectedSet */', + ], + 'OO method param type: first param' => [ + 'testMarker' => '/* testDNFTypeParam1WithAttribute */', + ], + 'OO method param type: second param, first DNF' => [ + 'testMarker' => '/* testDNFTypeParam2 */', + ], + 'OO method param type: second param, second DNF' => [ + 'testMarker' => '/* testDNFTypeParam3 */', + ], + 'OO method param type: namespace relative classes' => [ + 'testMarker' => '/* testDNFTypeParamNamespaceRelative */', + ], + 'OO method param type: partially qualified classes' => [ + 'testMarker' => '/* testDNFTypeParamPartiallyQualified */', + ], + 'OO method param type: fully qualified classes' => [ + 'testMarker' => '/* testDNFTypeParamFullyQualified */', + ], + 'Constructor property promotion with multi DNF 1' => [ + 'testMarker' => '/* testDNFTypeConstructorPropertyPromotion1 */', + ], + 'Constructor property promotion with multi DNF 2' => [ + 'testMarker' => '/* testDNFTypeConstructorPropertyPromotion2 */', + ], + 'OO method return type: multi DNF 1' => [ + 'testMarker' => '/* testDNFTypeReturnType1 */', + ], + 'OO method return type: multi DNF 2' => [ + 'testMarker' => '/* testDNFTypeReturnType2 */', + ], + 'OO abstract method return type: multi DNF 1' => [ + 'testMarker' => '/* testDNFTypeAbstractMethodReturnType1 */', + ], + 'OO abstract method return type: multi DNF 2' => [ + 'testMarker' => '/* testDNFTypeAbstractMethodReturnType2 */', + ], + 'OO method return type: namespace relative classes' => [ + 'testMarker' => '/* testDNFTypeReturnTypeNamespaceRelative */', + ], + 'OO method return type: partially qualified classes' => [ + 'testMarker' => '/* testDNFTypeReturnPartiallyQualified */', + ], + 'OO method return type: fully qualified classes' => [ + 'testMarker' => '/* testDNFTypeReturnFullyQualified */', + ], + 'function param type: with reference' => [ + 'testMarker' => '/* testDNFTypeWithReference */', + ], + 'function param type: with spread' => [ + 'testMarker' => '/* testDNFTypeWithSpreadOperator */', + ], + 'closure param type: with illegal nullable' => [ + 'testMarker' => '/* testDNFTypeClosureParamIllegalNullable */', + ], + 'closure return type' => [ + 'testMarker' => '/* testDNFTypeClosureReturn */', + ], + 'closure with use return type' => [ + 'testMarker' => '/* testDNFTypeClosureWithUseReturn */', + ], + + 'arrow function param type' => [ + 'testMarker' => '/* testDNFTypeArrowParam */', + ], + 'arrow function return type' => [ + 'testMarker' => '/* testDNFTypeArrowReturnType */', + ], + 'arrow function param type with return by ref' => [ + 'testMarker' => '/* testDNFTypeArrowParamWithReturnByRef */', + ], + + 'illegal syntax: unnecessary parentheses (no union)' => [ + 'testMarker' => '/* testDNFTypeParamIllegalUnnecessaryParens */', + ], + 'illegal syntax: union within parentheses, intersect outside' => [ + 'testMarker' => '/* testDNFTypeParamIllegalIntersectUnionReversed */', + ], + 'illegal syntax: nested parentheses' => [ + 'testMarker' => '/* testDNFTypeParamIllegalNestedParens */', + ], + ]; + + }//end dataDNFTypeParentheses() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DefaultKeywordTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DefaultKeywordTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DefaultKeywordTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DefaultKeywordTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DefaultKeywordTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DefaultKeywordTest.php similarity index 61% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DefaultKeywordTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DefaultKeywordTest.php index cee3d263d..c398aa6cb 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DefaultKeywordTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DefaultKeywordTest.php @@ -8,7 +8,9 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; final class DefaultKeywordTest extends AbstractTokenizerTestCase { @@ -25,7 +27,6 @@ final class DefaultKeywordTest extends AbstractTokenizerTestCase * * @dataProvider dataMatchDefault * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap * * @return void */ @@ -39,10 +40,6 @@ public function testMatchDefault($testMarker, $testContent='default') $this->assertSame(T_MATCH_DEFAULT, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_MATCH_DEFAULT (code)'); $this->assertSame('T_MATCH_DEFAULT', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_MATCH_DEFAULT (type)'); - $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); - $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); - $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); - }//end testMatchDefault() @@ -105,70 +102,24 @@ public static function dataMatchDefault() * Verify that the retokenization of `T_DEFAULT` tokens in match constructs, doesn't negatively * impact the tokenization of `T_DEFAULT` tokens in switch control structures. * - * Note: Cases and default structures within a switch control structure *do* get case/default scope - * conditions. - * - * @param string $testMarker The comment prefacing the target token. - * @param int $openerOffset The expected offset of the scope opener in relation to the testMarker. - * @param int $closerOffset The expected offset of the scope closer in relation to the testMarker. - * @param int|null $conditionStop The expected offset at which tokens stop having T_DEFAULT as a scope condition. - * @param string $testContent The token content to look for. + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to look for. * * @dataProvider dataSwitchDefault - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize * * @return void */ - public function testSwitchDefault($testMarker, $openerOffset, $closerOffset, $conditionStop=null, $testContent='default') + public function testSwitchDefault($testMarker, $testContent='default') { $tokens = $this->phpcsFile->getTokens(); $token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent); $tokenArray = $tokens[$token]; - $expectedScopeOpener = ($token + $openerOffset); - $expectedScopeCloser = ($token + $closerOffset); $this->assertSame(T_DEFAULT, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_DEFAULT (code)'); $this->assertSame('T_DEFAULT', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_DEFAULT (type)'); - $this->assertArrayHasKey('scope_condition', $tokenArray, 'Scope condition is not set'); - $this->assertArrayHasKey('scope_opener', $tokenArray, 'Scope opener is not set'); - $this->assertArrayHasKey('scope_closer', $tokenArray, 'Scope closer is not set'); - $this->assertSame($token, $tokenArray['scope_condition'], 'Scope condition is not the T_DEFAULT token'); - $this->assertSame($expectedScopeOpener, $tokenArray['scope_opener'], 'Scope opener of the T_DEFAULT token incorrect'); - $this->assertSame($expectedScopeCloser, $tokenArray['scope_closer'], 'Scope closer of the T_DEFAULT token incorrect'); - - $opener = $tokenArray['scope_opener']; - $this->assertArrayHasKey('scope_condition', $tokens[$opener], 'Opener scope condition is not set'); - $this->assertArrayHasKey('scope_opener', $tokens[$opener], 'Opener scope opener is not set'); - $this->assertArrayHasKey('scope_closer', $tokens[$opener], 'Opener scope closer is not set'); - $this->assertSame($token, $tokens[$opener]['scope_condition'], 'Opener scope condition is not the T_DEFAULT token'); - $this->assertSame($expectedScopeOpener, $tokens[$opener]['scope_opener'], 'T_DEFAULT opener scope opener token incorrect'); - $this->assertSame($expectedScopeCloser, $tokens[$opener]['scope_closer'], 'T_DEFAULT opener scope closer token incorrect'); - - $closer = $tokenArray['scope_closer']; - $this->assertArrayHasKey('scope_condition', $tokens[$closer], 'Closer scope condition is not set'); - $this->assertArrayHasKey('scope_opener', $tokens[$closer], 'Closer scope opener is not set'); - $this->assertArrayHasKey('scope_closer', $tokens[$closer], 'Closer scope closer is not set'); - $this->assertSame($token, $tokens[$closer]['scope_condition'], 'Closer scope condition is not the T_DEFAULT token'); - $this->assertSame($expectedScopeOpener, $tokens[$closer]['scope_opener'], 'T_DEFAULT closer scope opener token incorrect'); - $this->assertSame($expectedScopeCloser, $tokens[$closer]['scope_closer'], 'T_DEFAULT closer scope closer token incorrect'); - - if (($opener + 1) !== $closer) { - $end = $closer; - if (isset($conditionStop) === true) { - $end = $conditionStop; - } - - for ($i = ($opener + 1); $i < $end; $i++) { - $this->assertArrayHasKey( - $token, - $tokens[$i]['conditions'], - 'T_DEFAULT condition not added for token belonging to the T_DEFAULT structure' - ); - } - } - }//end testSwitchDefault() @@ -183,34 +134,19 @@ public static function dataSwitchDefault() { return [ 'simple_switch_default' => [ - 'testMarker' => '/* testSimpleSwitchDefault */', - 'openerOffset' => 1, - 'closerOffset' => 4, + 'testMarker' => '/* testSimpleSwitchDefault */', ], 'simple_switch_default_with_curlies' => [ - // For a default structure with curly braces, the scope opener - // will be the open curly and the closer the close curly. - // However, scope conditions will not be set for open to close, - // but only for the open token up to the "break/return/continue" etc. - 'testMarker' => '/* testSimpleSwitchDefaultWithCurlies */', - 'openerOffset' => 3, - 'closerOffset' => 12, - 'conditionStop' => 6, + 'testMarker' => '/* testSimpleSwitchDefaultWithCurlies */', ], 'switch_default_toplevel' => [ - 'testMarker' => '/* testSwitchDefault */', - 'openerOffset' => 1, - 'closerOffset' => 43, + 'testMarker' => '/* testSwitchDefault */', ], 'switch_default_nested_in_match_case' => [ - 'testMarker' => '/* testSwitchDefaultNestedInMatchCase */', - 'openerOffset' => 1, - 'closerOffset' => 20, + 'testMarker' => '/* testSwitchDefaultNestedInMatchCase */', ], 'switch_default_nested_in_match_default' => [ - 'testMarker' => '/* testSwitchDefaultNestedInMatchDefault */', - 'openerOffset' => 1, - 'closerOffset' => 18, + 'testMarker' => '/* testSwitchDefaultNestedInMatchDefault */', ], ]; @@ -240,10 +176,6 @@ public function testNotDefaultKeyword($testMarker, $testContent='DEFAULT') $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); - $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); - $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); - $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); - }//end testNotDefaultKeyword() @@ -320,28 +252,4 @@ public static function dataNotDefaultKeyword() }//end dataNotDefaultKeyword() - /** - * Test a specific edge case where a scope opener would be incorrectly set. - * - * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/3326 - * - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap - * - * @return void - */ - public function testIssue3326() - { - $tokens = $this->phpcsFile->getTokens(); - - $token = $this->getTargetToken('/* testClassConstant */', [T_SEMICOLON]); - $tokenArray = $tokens[$token]; - - $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); - $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); - $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); - - }//end testIssue3326() - - }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleArrowTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleArrowTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleArrowTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleArrowTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleArrowTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleArrowTest.php similarity index 99% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleArrowTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleArrowTest.php index 768ff65d7..5258d9c16 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleArrowTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleArrowTest.php @@ -9,7 +9,9 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; final class DoubleArrowTest extends AbstractTokenizerTestCase { diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleQuotedStringTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleQuotedStringTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleQuotedStringTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleQuotedStringTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleQuotedStringTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleQuotedStringTest.php similarity index 98% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleQuotedStringTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleQuotedStringTest.php index 83ba0aab7..aa0817a46 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/DoubleQuotedStringTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/DoubleQuotedStringTest.php @@ -8,7 +8,9 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; final class DoubleQuotedStringTest extends AbstractTokenizerTestCase { diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/EnumCaseTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/EnumCaseTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/EnumCaseTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/EnumCaseTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/EnumCaseTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/EnumCaseTest.php similarity index 89% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/EnumCaseTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/EnumCaseTest.php index f5b68507d..6836ea05e 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/EnumCaseTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/EnumCaseTest.php @@ -7,7 +7,9 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; final class EnumCaseTest extends AbstractTokenizerTestCase { @@ -20,7 +22,6 @@ final class EnumCaseTest extends AbstractTokenizerTestCase * * @dataProvider dataEnumCases * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap * * @return void */ @@ -33,10 +34,6 @@ public function testEnumCases($testMarker) $this->assertSame(T_ENUM_CASE, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_ENUM_CASE (code)'); $this->assertSame('T_ENUM_CASE', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_ENUM_CASE (type)'); - $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); - $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); - $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); - }//end testEnumCases() @@ -69,7 +66,6 @@ public static function dataEnumCases() * * @dataProvider dataNotEnumCases * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap * * @return void */ @@ -82,10 +78,6 @@ public function testNotEnumCases($testMarker) $this->assertSame(T_CASE, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_CASE (code)'); $this->assertSame('T_CASE', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_CASE (type)'); - $this->assertArrayHasKey('scope_condition', $tokenArray, 'Scope condition is not set'); - $this->assertArrayHasKey('scope_opener', $tokenArray, 'Scope opener is not set'); - $this->assertArrayHasKey('scope_closer', $tokenArray, 'Scope closer is not set'); - }//end testNotEnumCases() diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/FinallyTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/FinallyTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/FinallyTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/FinallyTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/FinallyTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/FinallyTest.php similarity index 96% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/FinallyTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/FinallyTest.php index a73ac57e5..e73dde122 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/FinallyTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/FinallyTest.php @@ -7,7 +7,9 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; final class FinallyTest extends AbstractTokenizerTestCase { diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/GotoLabelTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/GotoLabelTest.inc similarity index 67% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/GotoLabelTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/GotoLabelTest.inc index 12df5d296..249064a23 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/GotoLabelTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/GotoLabelTest.inc @@ -23,6 +23,35 @@ echo "i = $i"; end: echo 'j hit 17'; +switch($x){ + case 3: + print($x); + if($x) + /* testGotoStatementInSwitch */ + goto def; + default: + /* testGotoDeclarationInSwitch */ + def: + print($x); +} + +function hasGoto() { + if ($hide_form_and_script) { + /* testGotoStatementInFunction */ + goto label; + } + ?> + +
+ +
+ + '/* testGotoStatementInLoop */', 'testContent' => 'end', ], + 'label for goto statement in switch' => [ + 'testMarker' => '/* testGotoStatementInSwitch */', + 'testContent' => 'def', + ], + 'label for goto statement within function' => [ + 'testMarker' => '/* testGotoStatementInFunction */', + 'testContent' => 'label', + ], ]; }//end dataGotoStatement() @@ -66,7 +80,6 @@ public static function dataGotoStatement() * @param string $testContent The token content to expect. * * @dataProvider dataGotoDeclaration - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize * * @return void */ @@ -100,6 +113,14 @@ public static function dataGotoDeclaration() 'testMarker' => '/* testGotoDeclarationOutsideLoop */', 'testContent' => 'end:', ], + 'label in goto declaration - def' => [ + 'testMarker' => '/* testGotoDeclarationInSwitch */', + 'testContent' => 'def:', + ], + 'label in goto declaration - label' => [ + 'testMarker' => '/* testGotoDeclarationInFunction */', + 'testContent' => 'label:', + ], ]; }//end dataGotoDeclaration() @@ -112,7 +133,6 @@ public static function dataGotoDeclaration() * @param string $testContent The token content to expect. * * @dataProvider dataNotAGotoDeclaration - * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize * * @return void */ diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocNowdocTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocNowdocTest.inc new file mode 100644 index 000000000..5041dda15 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocNowdocTest.inc @@ -0,0 +1,39 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +/** + * Tests the tokenization for heredoc/nowdoc constructs. + * + * Verifies that: + * - Nowdoc opener/closers are retokenized from `T_[START_|END_]HEREDOC` to `T_[START_|END_]NOWDOC`. + * - The contents of the heredoc/nowdoc is tokenized as `T_HEREDOC`/`T_NOWDOC`. + * - Each line of the contents has its own token, which includes the new line char. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + */ +final class HeredocNowdocTest extends AbstractTokenizerTestCase +{ + + + /** + * Verify tokenization a heredoc construct. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testHeredocSingleLine() + { + $expectedSequence = [ + [T_START_HEREDOC => '<< 'Some $var text'."\n"], + [T_END_HEREDOC => 'EOD'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_START_HEREDOC); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testHeredocSingleLine() + + + /** + * Verify tokenization a nowdoc construct. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testNowdocSingleLine() + { + $expectedSequence = [ + [T_START_NOWDOC => "<<<'MARKER'\n"], + [T_NOWDOC => 'Some text'."\n"], + [T_END_NOWDOC => 'MARKER'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_START_NOWDOC); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testNowdocSingleLine() + + + /** + * Verify tokenization a multiline heredoc construct. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testHeredocMultiLine() + { + $expectedSequence = [ + [T_START_HEREDOC => '<<<"😬"'."\n"], + [T_HEREDOC => 'Lorum ipsum'."\n"], + [T_HEREDOC => 'Some $var text'."\n"], + [T_HEREDOC => 'dolor sit amet'."\n"], + [T_END_HEREDOC => '😬'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_START_HEREDOC); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testHeredocMultiLine() + + + /** + * Verify tokenization a multiline testNowdocSingleLine construct. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testNowdocMultiLine() + { + $expectedSequence = [ + [T_START_NOWDOC => "<<<'multi_line'\n"], + [T_NOWDOC => 'Lorum ipsum'."\n"], + [T_NOWDOC => 'Some text'."\n"], + [T_NOWDOC => 'dolor sit amet'."\n"], + [T_END_NOWDOC => 'multi_line'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_START_NOWDOC); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testNowdocMultiLine() + + + /** + * Verify tokenization a multiline heredoc construct. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testHeredocEndsOnBlankLine() + { + $expectedSequence = [ + [T_START_HEREDOC => '<< 'Lorum ipsum'."\n"], + [T_HEREDOC => 'dolor sit amet'."\n"], + [T_HEREDOC => "\n"], + [T_END_HEREDOC => 'EOD'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_START_HEREDOC); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testHeredocEndsOnBlankLine() + + + /** + * Verify tokenization a multiline testNowdocSingleLine construct. + * + * @phpcs:disable Squiz.Arrays.ArrayDeclaration.SpaceBeforeDoubleArrow -- Readability is better with alignment. + * + * @return void + */ + public function testNowdocEndsOnBlankLine() + { + $expectedSequence = [ + [T_START_NOWDOC => "<<<'EOD'\n"], + [T_NOWDOC => 'Lorum ipsum'."\n"], + [T_NOWDOC => 'dolor sit amet'."\n"], + [T_NOWDOC => "\n"], + [T_END_NOWDOC => 'EOD'], + ]; + + $target = $this->getTargetToken('/* '.__FUNCTION__.' */', T_START_NOWDOC); + + $this->checkTokenSequence($target, $expectedSequence); + + }//end testNowdocEndsOnBlankLine() + + + /** + * Test helper. Check a token sequence complies with an expected token sequence. + * + * @param int $startPtr The position in the file to start checking from. + * @param array> $expectedSequence The consecutive token constants and their contents to expect. + * + * @return void + */ + private function checkTokenSequence($startPtr, array $expectedSequence) + { + $tokens = $this->phpcsFile->getTokens(); + + $sequenceKey = 0; + $sequenceCount = count($expectedSequence); + + for ($i = $startPtr; $sequenceKey < $sequenceCount; $i++, $sequenceKey++) { + $currentItem = $expectedSequence[$sequenceKey]; + $expectedCode = key($currentItem); + $expectedType = Tokens::tokenName($expectedCode); + $expectedContent = current($currentItem); + $errorMsgSuffix = PHP_EOL.'(StackPtr: '.$i.' | Position in sequence: '.$sequenceKey.' | Expected: '.$expectedType.')'; + + $this->assertSame( + $expectedCode, + $tokens[$i]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$i]['code']).', not '.$expectedType.' (code)'.$errorMsgSuffix + ); + + $this->assertSame( + $expectedType, + $tokens[$i]['type'], + 'Token tokenized as '.$tokens[$i]['type'].', not '.$expectedType.' (type)'.$errorMsgSuffix + ); + + $this->assertSame( + $expectedContent, + $tokens[$i]['content'], + 'Token content did not match expectations'.$errorMsgSuffix + ); + }//end for + + }//end checkTokenSequence() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocParseErrorTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocParseErrorTest.inc new file mode 100644 index 000000000..d552b1283 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocParseErrorTest.inc @@ -0,0 +1,11 @@ +>>>>>> master diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocParseErrorTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocParseErrorTest.php new file mode 100644 index 000000000..877706fb4 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocParseErrorTest.php @@ -0,0 +1,41 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +/** + * Tests the tokenization for an unclosed heredoc construct. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + */ +final class HeredocParseErrorTest extends AbstractTokenizerTestCase +{ + + + /** + * Verify that a heredoc (and nowdoc) start token is retokenized to T_STRING if no closer is found. + * + * @return void + */ + public function testMergeConflict() + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken('/* testUnclosedHeredoc */', [T_START_HEREDOC, T_STRING], '<<< HEAD'."\n"); + $tokenArray = $tokens[$token]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_START_HEREDOC (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_START_HEREDOC (type)'); + + }//end testMergeConflict() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocStringTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocStringTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocStringTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocStringTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocStringTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocStringTest.php similarity index 98% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocStringTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocStringTest.php index da3f361b2..c31c17538 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocStringTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/HeredocStringTest.php @@ -8,7 +8,9 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; final class HeredocStringTest extends AbstractTokenizerTestCase { diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NamedFunctionCallArgumentsTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NamedFunctionCallArgumentsTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NamedFunctionCallArgumentsTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NamedFunctionCallArgumentsTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NamedFunctionCallArgumentsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NamedFunctionCallArgumentsTest.php similarity index 99% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NamedFunctionCallArgumentsTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NamedFunctionCallArgumentsTest.php index 058129f56..768e41a98 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NamedFunctionCallArgumentsTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NamedFunctionCallArgumentsTest.php @@ -7,8 +7,9 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; use PHP_CodeSniffer\Util\Tokens; final class NamedFunctionCallArgumentsTest extends AbstractTokenizerTestCase @@ -735,7 +736,7 @@ public function testOtherColonsInTernary($testMarker) // Third colon should be T_COLON for the return type. $colonCount = 0; for ($i = ($startOfStatement + 1); $tokens[$i]['line'] === $tokens[$startOfStatement]['line']; $i++) { - $this->assertNotEquals(T_PARAM_NAME, $tokens[$i]['code'], "Token $i is tokenized as parameter label"); + $this->assertNotSame(T_PARAM_NAME, $tokens[$i]['code'], "Token $i is tokenized as parameter label"); if ($tokens[$i]['content'] === ':') { ++$colonCount; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NullableVsInlineThenTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NullableVsInlineThenTest.inc new file mode 100644 index 000000000..56ad3856c --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NullableVsInlineThenTest.inc @@ -0,0 +1,19 @@ +phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_NULLABLE, T_INLINE_THEN]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_NULLABLE, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_NULLABLE (code)'); + $this->assertSame('T_NULLABLE', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_NULLABLE (type)'); + + }//end testNullable() + + + /** + * Data provider. + * + * @see testNullable() + * + * @return array> + */ + public static function dataNullable() + { + return [ + 'property declaration, readonly, no visibility' => ['/* testNullableReadonlyOnly */'], + 'property declaration, private set' => ['/* testNullablePrivateSet */'], + 'property declaration, public and protected set' => ['/* testNullablePublicProtectedSet */'], + ]; + + }//end dataNullable() + + + /** + * Test that "readonly" when not used as the keyword is still tokenized as `T_STRING`. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataInlineThen + * + * @return void + */ + public function testInlineThen($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_NULLABLE, T_INLINE_THEN]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_INLINE_THEN, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_INLINE_THEN (code)'); + $this->assertSame('T_INLINE_THEN', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_INLINE_THEN (type)'); + + }//end testInlineThen() + + + /** + * Data provider. + * + * @see testInlineThen() + * + * @return array> + */ + public static function dataInlineThen() + { + return [ + 'ternary in property default value' => ['/* testInlineThenInPropertyDefaultValue */'], + ]; + + }//end dataInlineThen() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NullsafeObjectOperatorTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NullsafeObjectOperatorTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NullsafeObjectOperatorTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NullsafeObjectOperatorTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NullsafeObjectOperatorTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NullsafeObjectOperatorTest.php similarity index 97% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NullsafeObjectOperatorTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NullsafeObjectOperatorTest.php index f97ff6978..368fee4db 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/NullsafeObjectOperatorTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/NullsafeObjectOperatorTest.php @@ -7,8 +7,9 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; use PHP_CodeSniffer\Util\Tokens; final class NullsafeObjectOperatorTest extends AbstractTokenizerTestCase diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/OtherContextSensitiveKeywordsTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/OtherContextSensitiveKeywordsTest.inc new file mode 100644 index 000000000..028592f76 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/OtherContextSensitiveKeywordsTest.inc @@ -0,0 +1,247 @@ + $param->get(); + } +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/OtherContextSensitiveKeywordsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/OtherContextSensitiveKeywordsTest.php new file mode 100644 index 000000000..35c899714 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/OtherContextSensitiveKeywordsTest.php @@ -0,0 +1,721 @@ + + * @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +/** + * Tests the conversion of PHPCS native context sensitive keyword tokens to T_STRING. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * @covers PHP_CodeSniffer\Tokenizers\PHP::standardiseToken + */ +final class OtherContextSensitiveKeywordsTest extends AbstractTokenizerTestCase +{ + + + /** + * Clear the "resolved tokens" cache before running this test as otherwise the code + * under test may not be run during the test. + * + * @beforeClass + * + * @return void + */ + public static function clearTokenCache() + { + parent::clearResolvedTokensCache(); + + }//end clearTokenCache() + + + /** + * Test that context sensitive keyword is tokenized as string when it should be string. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataStrings + * + * @return void + */ + public function testStrings($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_STRING, T_NULL, T_FALSE, T_TRUE, T_PARENT, T_SELF]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + }//end testStrings() + + + /** + * Data provider. + * + * @see testStrings() + * + * @return array> + */ + public static function dataStrings() + { + return [ + 'constant declaration: parent' => ['/* testParent */'], + 'constant declaration: self' => ['/* testSelf */'], + 'constant declaration: false' => ['/* testFalse */'], + 'constant declaration: true' => ['/* testTrue */'], + 'constant declaration: null' => ['/* testNull */'], + + 'function declaration with return by ref: self' => ['/* testKeywordSelfAfterFunctionByRefShouldBeString */'], + 'function declaration with return by ref: parent' => ['/* testKeywordParentAfterFunctionByRefShouldBeString */'], + 'function declaration with return by ref: false' => ['/* testKeywordFalseAfterFunctionByRefShouldBeString */'], + 'function declaration with return by ref: true' => ['/* testKeywordTrueAfterFunctionByRefShouldBeString */'], + 'function declaration with return by ref: null' => ['/* testKeywordNullAfterFunctionByRefShouldBeString */'], + + 'function call: self' => ['/* testKeywordAsFunctionCallNameShouldBeStringSelf */'], + 'function call: parent' => ['/* testKeywordAsFunctionCallNameShouldBeStringParent */'], + 'function call: false' => ['/* testKeywordAsFunctionCallNameShouldBeStringFalse */'], + 'function call: true' => ['/* testKeywordAsFunctionCallNameShouldBeStringTrue */'], + 'function call: null; with comment between keyword and parentheses' => ['/* testKeywordAsFunctionCallNameShouldBeStringNull */'], + + 'class instantiation: false' => ['/* testClassInstantiationFalseIsString */'], + 'class instantiation: true' => ['/* testClassInstantiationTrueIsString */'], + 'class instantiation: null' => ['/* testClassInstantiationNullIsString */'], + + 'constant declaration: false as name after type' => ['/* testFalseIsNameForTypedConstant */'], + 'constant declaration: true as name after type' => ['/* testTrueIsNameForTypedConstant */'], + 'constant declaration: null as name after type' => ['/* testNullIsNameForTypedConstant */'], + 'constant declaration: self as name after type' => ['/* testSelfIsNameForTypedConstant */'], + 'constant declaration: parent as name after type' => ['/* testParentIsNameForTypedConstant */'], + ]; + + }//end dataStrings() + + + /** + * Test that context sensitive keyword is tokenized as keyword when it should be keyword. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expectedTokenType The expected token type. + * + * @dataProvider dataKeywords + * + * @return void + */ + public function testKeywords($testMarker, $expectedTokenType) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_STRING, T_NULL, T_FALSE, T_TRUE, T_PARENT, T_SELF]); + $tokenArray = $tokens[$target]; + + $this->assertSame( + constant($expectedTokenType), + $tokenArray['code'], + 'Token tokenized as '.$tokenArray['type'].', not '.$expectedTokenType.' (code)' + ); + $this->assertSame( + $expectedTokenType, + $tokenArray['type'], + 'Token tokenized as '.$tokenArray['type'].', not '.$expectedTokenType.' (type)' + ); + + }//end testKeywords() + + + /** + * Data provider. + * + * @see testKeywords() + * + * @return array> + */ + public static function dataKeywords() + { + return [ + 'self: param type declaration' => [ + 'testMarker' => '/* testSelfIsKeyword */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: param type declaration' => [ + 'testMarker' => '/* testParentIsKeyword */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'parent: class instantiation' => [ + 'testMarker' => '/* testClassInstantiationParentIsKeyword */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: class instantiation' => [ + 'testMarker' => '/* testClassInstantiationSelfIsKeyword */', + 'expectedTokenType' => 'T_SELF', + ], + + 'false: param type declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsParamType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: param type declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsParamType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: param type declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsParamType */', + 'expectedTokenType' => 'T_NULL', + ], + 'false: return type declaration in union' => [ + 'testMarker' => '/* testFalseIsKeywordAsReturnType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: return type declaration in union' => [ + 'testMarker' => '/* testTrueIsKeywordAsReturnType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: return type declaration in union' => [ + 'testMarker' => '/* testNullIsKeywordAsReturnType */', + 'expectedTokenType' => 'T_NULL', + ], + 'false: in comparison' => [ + 'testMarker' => '/* testFalseIsKeywordInComparison */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: in comparison' => [ + 'testMarker' => '/* testTrueIsKeywordInComparison */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: in comparison' => [ + 'testMarker' => '/* testNullIsKeywordInComparison */', + 'expectedTokenType' => 'T_NULL', + ], + + 'false: type in OO constant declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsConstType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: type in OO constant declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsConstType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: type in OO constant declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsConstType */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: type in OO constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstType */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: type in OO constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstType */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: value in constant declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsConstDefault */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: value in constant declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsConstDefault */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: value in constant declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsConstDefault */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: value in constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstDefault */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: value in constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstDefault */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: type in property declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsPropertyType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: type in property declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsPropertyType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: type in property declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsPropertyType */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: type in property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyType */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: type in property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyType */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: value in property declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsPropertyDefault */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: value in property declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsPropertyDefault */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: value in property declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsPropertyDefault */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: value in property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyDefault */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: value in property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyDefault */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: first in union type for OO constant declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsConstUnionTypeFirst */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: first in union type for OO constant declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsConstUnionTypeFirst */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: first in union type for OO constant declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsConstUnionTypeFirst */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: first in union type for OO constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstUnionTypeFirst */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: first in union type for OO constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstUnionTypeFirst */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: middle in union type for OO constant declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsConstUnionTypeMiddle */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: middle in union type for OO constant declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsConstUnionTypeMiddle */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: middle in union type for OO constant declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsConstUnionTypeMiddle */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: middle in union type for OO constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstUnionTypeMiddle */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: middle in union type for OO constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstUnionTypeMiddle */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: last in union type for OO constant declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsConstUnionTypeLast */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: last in union type for OO constant declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsConstUnionTypeLast */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: last in union type for OO constant declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsConstUnionTypeLast */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: last in union type for OO constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstUnionTypeLast */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: last in union type for OO constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstUnionTypeLast */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: first in union type for property declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsPropertyUnionTypeFirst */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: first in union type for property declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsPropertyUnionTypeFirst */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: first in union type for property declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsPropertyUnionTypeFirst */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: first in union type for property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyUnionTypeFirst */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: first in union type for property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyUnionTypeFirst */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: middle in union type for property declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsPropertyUnionTypeMiddle */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: middle in union type for property declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsPropertyUnionTypeMiddle */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: middle in union type for property declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsPropertyUnionTypeMiddle */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: middle in union type for property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyUnionTypeMiddle */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: middle in union type for property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyUnionTypeMiddle */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: last in union type for property declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsPropertyUnionTypeLast */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: last in union type for property declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsPropertyUnionTypeLast */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: last in union type for property declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsPropertyUnionTypeLast */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: last in union type for property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyUnionTypeLast */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: last in union type for property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyUnionTypeLast */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: first in union type for param declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsParamUnionTypeFirst */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: first in union type for param declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsParamUnionTypeFirst */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: first in union type for param declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsParamUnionTypeFirst */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: first in union type for param declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsParamUnionTypeFirst */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: first in union type for param declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsParamUnionTypeFirst */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: middle in union type for param declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsParamUnionTypeMiddle */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: middle in union type for param declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsParamUnionTypeMiddle */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: middle in union type for param declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsParamUnionTypeMiddle */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: middle in union type for param declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsParamUnionTypeMiddle */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: middle in union type for param declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsParamUnionTypeMiddle */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: last in union type for param declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsParamUnionTypeLast */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: last in union type for param declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsParamUnionTypeLast */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: last in union type for param declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsParamUnionTypeLast */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: last in union type for param declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsParamUnionTypeLast */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: last in union type for param declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsParamUnionTypeLast */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: first in union type for return declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsReturnUnionTypeFirst */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: first in union type for return declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsReturnUnionTypeFirst */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: first in union type for return declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsReturnUnionTypeFirst */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: first in union type for return declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsReturnUnionTypeFirst */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: first in union type for return declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsReturnUnionTypeFirst */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: middle in union type for return declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsReturnUnionTypeMiddle */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: middle in union type for return declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsReturnUnionTypeMiddle */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: middle in union type for return declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsReturnUnionTypeMiddle */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: middle in union type for return declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsReturnUnionTypeMiddle */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: middle in union type for return declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsReturnUnionTypeMiddle */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: last in union type for return declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsReturnUnionTypeLast */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: last in union type for return declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsReturnUnionTypeLast */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: last in union type for return declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsReturnUnionTypeLast */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: last in union type for return declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsReturnUnionTypeLast */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: last in union type for return declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsReturnUnionTypeLast */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'self: first in intersection type for OO constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstIntersectionTypeFirst */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: first in intersection type for OO constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstIntersectionTypeFirst */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: middle in intersection type for OO constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstIntersectionTypeMiddle */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: middle in intersection type for OO constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstIntersectionTypeMiddle */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: last in intersection type for OO constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstIntersectionTypeLast */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: last in intersection type for OO constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstIntersectionTypeLast */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'self: first in intersection type for property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyIntersectionTypeFirst */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: first in intersection type for property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyIntersectionTypeFirst */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: middle in intersection type for property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyIntersectionTypeMiddle */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: middle in intersection type for property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyIntersectionTypeMiddle */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: last in intersection type for property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyIntersectionTypeLast */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: last in intersection type for property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyIntersectionTypeLast */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'self: first in intersection type for param declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsParamIntersectionTypeFirst */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: first in intersection type for param declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsParamIntersectionTypeFirst */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: middle in intersection type for param declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsParamIntersectionTypeMiddle */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: middle in intersection type for param declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsParamIntersectionTypeMiddle */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: last in intersection type for param declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsParamIntersectionTypeLast */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: last in intersection type for param declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsParamIntersectionTypeLast */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'self: first in intersection type for return declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsReturnIntersectionTypeFirst */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: first in intersection type for return declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsReturnIntersectionTypeFirst */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: middle in intersection type for return declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsReturnIntersectionTypeMiddle */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: middle in intersection type for return declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsReturnIntersectionTypeMiddle */', + 'expectedTokenType' => 'T_PARENT', + ], + 'self: last in intersection type for return declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsReturnIntersectionTypeLast */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: last in intersection type for return declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsReturnIntersectionTypeLast */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: DNF type in OO constant declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsConstDNFType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: DNF type in OO constant declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsConstDNFType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: DNF type in OO constant declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsConstDNFType */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: DNF type in OO constant declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsConstDNFType */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: DNF type in OO constant declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsConstDNFType */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: DNF type in property declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsPropertyDNFType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: DNF type in property declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsPropertyDNFType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: DNF type in property declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsPropertyDNFType */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: DNF type in property declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsPropertyDNFType */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: DNF type in property declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsPropertyDNFType */', + 'expectedTokenType' => 'T_PARENT', + ], + + 'false: DNF type in function param declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsParamDNFType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'false: DNF type in function return declaration' => [ + 'testMarker' => '/* testFalseIsKeywordAsReturnDNFType */', + 'expectedTokenType' => 'T_FALSE', + ], + 'true: DNF type in function param declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsParamDNFType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'true: DNF type in function return declaration' => [ + 'testMarker' => '/* testTrueIsKeywordAsReturnDNFType */', + 'expectedTokenType' => 'T_TRUE', + ], + 'null: DNF type in function param declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsParamDNFType */', + 'expectedTokenType' => 'T_NULL', + ], + 'null: DNF type in function return declaration' => [ + 'testMarker' => '/* testNullIsKeywordAsReturnDNFType */', + 'expectedTokenType' => 'T_NULL', + ], + 'self: DNF type in function param declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsParamDNFType */', + 'expectedTokenType' => 'T_SELF', + ], + 'self: DNF type in function return declaration' => [ + 'testMarker' => '/* testSelfIsKeywordAsReturnDNFType */', + 'expectedTokenType' => 'T_SELF', + ], + 'parent: DNF type in function param declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsParamDNFType */', + 'expectedTokenType' => 'T_PARENT', + ], + 'parent: DNF type in function return declaration' => [ + 'testMarker' => '/* testParentIsKeywordAsReturnDNFType */', + 'expectedTokenType' => 'T_PARENT', + ], + + ]; + + }//end dataKeywords() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF1Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF1Test.inc new file mode 100644 index 000000000..2244b3891 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF1Test.inc @@ -0,0 +1,4 @@ + +phpcsFile->getTokens(); + $stackPtr = $this->getTargetToken('/* testLongOpenTagEndOfFileSpaceNoNewLine */', [T_OPEN_TAG, T_STRING, T_INLINE_HTML]); + + $this->assertSame( + T_OPEN_TAG, + $tokens[$stackPtr]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$stackPtr]['code']).', not T_OPEN_TAG (code)' + ); + $this->assertSame( + 'T_OPEN_TAG', + $tokens[$stackPtr]['type'], + 'Token tokenized as '.$tokens[$stackPtr]['type'].', not T_OPEN_TAG (type)' + ); + $this->assertSame('assertArrayNotHasKey(($stackPtr + 1), $tokens); + + }//end testLongOpenTagAtEndOfFile() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF2Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF2Test.inc new file mode 100644 index 000000000..191bdae16 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF2Test.inc @@ -0,0 +1,4 @@ + +phpcsFile->getTokens(); + $stackPtr = $this->getTargetToken('/* testLongOpenTagEndOfFileNoSpaceNoNewLine */', [T_OPEN_TAG, T_STRING, T_INLINE_HTML]); + + $this->assertSame( + T_OPEN_TAG, + $tokens[$stackPtr]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$stackPtr]['code']).', not T_OPEN_TAG (code)' + ); + $this->assertSame( + 'T_OPEN_TAG', + $tokens[$stackPtr]['type'], + 'Token tokenized as '.$tokens[$stackPtr]['type'].', not T_OPEN_TAG (type)' + ); + $this->assertSame('assertArrayNotHasKey(($stackPtr + 1), $tokens); + + }//end testLongOpenTagAtEndOfFile() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF3Test.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF3Test.inc new file mode 100644 index 000000000..583314db3 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/PHPOpenTagEOF3Test.inc @@ -0,0 +1,4 @@ + +phpcsFile->getTokens(); + $stackPtr = $this->getTargetToken('/* testLongOpenTagEndOfFileNoSpaceNoNewLineUppercase */', [T_OPEN_TAG, T_STRING, T_INLINE_HTML]); + + $this->assertSame( + T_OPEN_TAG, + $tokens[$stackPtr]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$stackPtr]['code']).', not T_OPEN_TAG (code)' + ); + $this->assertSame( + 'T_OPEN_TAG', + $tokens[$stackPtr]['type'], + 'Token tokenized as '.$tokens[$stackPtr]['type'].', not T_OPEN_TAG (type)' + ); + $this->assertSame('assertArrayNotHasKey(($stackPtr + 1), $tokens); + + }//end testLongOpenTagAtEndOfFile() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ResolveSimpleTokenTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ResolveSimpleTokenTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ResolveSimpleTokenTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ResolveSimpleTokenTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ResolveSimpleTokenTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ResolveSimpleTokenTest.php similarity index 98% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ResolveSimpleTokenTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ResolveSimpleTokenTest.php index 706b1fe3c..06a130c24 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ResolveSimpleTokenTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ResolveSimpleTokenTest.php @@ -7,8 +7,9 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; use PHP_CodeSniffer\Util\Tokens; /** diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ShortArrayTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ShortArrayTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ShortArrayTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ShortArrayTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ShortArrayTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ShortArrayTest.php similarity index 98% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ShortArrayTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ShortArrayTest.php index 189523863..da9c7c104 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ShortArrayTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/ShortArrayTest.php @@ -7,7 +7,9 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; final class ShortArrayTest extends AbstractTokenizerTestCase { diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/StableCommentWhitespaceTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/StableCommentWhitespaceTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/StableCommentWhitespaceTest.php similarity index 99% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/StableCommentWhitespaceTest.php index b3b19c6ba..ad7d9ceb3 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/StableCommentWhitespaceTest.php @@ -13,8 +13,9 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; use PHP_CodeSniffer\Util\Tokens; final class StableCommentWhitespaceTest extends AbstractTokenizerTestCase @@ -37,7 +38,7 @@ public function testCommentTokenization($testMarker, $expectedTokens) $tokens = $this->phpcsFile->getTokens(); $comment = $this->getTargetToken($testMarker, Tokens::$commentTokens); - foreach ($expectedTokens as $key => $tokenInfo) { + foreach ($expectedTokens as $tokenInfo) { $this->assertSame( constant($tokenInfo['type']), $tokens[$comment]['code'], diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceWinTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/StableCommentWhitespaceWinTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceWinTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/StableCommentWhitespaceWinTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceWinTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/StableCommentWhitespaceWinTest.php similarity index 98% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceWinTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/StableCommentWhitespaceWinTest.php index 2d0ce30d8..816fc571a 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/StableCommentWhitespaceWinTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/StableCommentWhitespaceWinTest.php @@ -10,8 +10,9 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; use PHP_CodeSniffer\Util\Tokens; final class StableCommentWhitespaceWinTest extends AbstractTokenizerTestCase @@ -34,7 +35,7 @@ public function testCommentTokenization($testMarker, $expectedTokens) $tokens = $this->phpcsFile->getTokens(); $comment = $this->getTargetToken($testMarker, Tokens::$commentTokens); - foreach ($expectedTokens as $key => $tokenInfo) { + foreach ($expectedTokens as $tokenInfo) { $this->assertSame( constant($tokenInfo['type']), $tokens[$comment]['code'], diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypeIntersectionTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypeIntersectionTest.inc similarity index 80% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypeIntersectionTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypeIntersectionTest.inc index d9a68db36..54b3c06e1 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypeIntersectionTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypeIntersectionTest.inc @@ -63,6 +63,24 @@ class TypeIntersection /* testTypeIntersectionPropertyWithStaticKeyword */ static Foo&Bar $obj; + /* testTypeIntersectionWithPHP84FinalKeyword */ + final className&InterfaceName $finalKeywordA; + + /* testTypeIntersectionWithPHP84FinalKeywordFirst */ + final private \className&InterfaceName $finalKeywordB; + + /* testTypeIntersectionPropertyWithPrivateSet */ + private(set) Foo&Bar $asym1; + + /* testTypeIntersectionPropertyWithPublicPrivateSet */ + public private(set) Foo&Bar $asym2; + + /* testTypeIntersectionPropertyWithProtectedSet */ + protected(set) Foo&Bar $asym3; + + /* testTypeIntersectionPropertyWithPublicProtectedSet */ + public protected(set) Foo&Bar $asym4; + public function paramTypes( /* testTypeIntersectionParam1 */ Foo&Bar $paramA /* testBitwiseAndParamDefaultValue */ = CONSTANT_A & CONSTANT_B, @@ -109,6 +127,20 @@ function globalFunctionWithSpreadAndReference( Foo&Bar ...$paramB ) {} + +$dnfTypes = new class { + /* testTypeIntersectionConstantTypeUnionBeforeDNF */ + const Foo|(A&B) UNION_BEFORE = /* testBitwiseAndOOConstDefaultValueDNF */ Foo|(A&B); + + /* testTypeIntersectionPropertyTypeUnionAfterDNF */ + protected (\FQN&namespace\Relative)|Partially\Qualified $union_after = /* testBitwiseAndPropertyDefaultValueDNF */ (A&B)|Foo; + + public function unionBeforeAndAfter( + /* testTypeIntersectionParamUnionBeforeAndAfterDNF */ + string|(Stringable&\Countable)|int $param = /* testBitwiseAndParamDefaultValueDNF */ ( CONST_A & CONST_B) | CONST_C + ): /* testTypeIntersectionReturnTypeUnionAfterDNF */ (A&B)|null {} +}; + /* testTypeIntersectionClosureParamIllegalNullable */ $closureWithParamType = function (?Foo&Bar $string) {}; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypeIntersectionTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypeIntersectionTest.php similarity index 68% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypeIntersectionTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypeIntersectionTest.php index c719850c1..3a4eb0070 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypeIntersectionTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypeIntersectionTest.php @@ -8,7 +8,9 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; final class TypeIntersectionTest extends AbstractTokenizerTestCase { @@ -46,24 +48,27 @@ public function testBitwiseAnd($testMarker) public static function dataBitwiseAnd() { return [ - 'in simple assignment 1' => ['/* testBitwiseAnd1 */'], - 'in simple assignment 2' => ['/* testBitwiseAnd2 */'], - 'in OO constant default value' => ['/* testBitwiseAndOOConstDefaultValue */'], - 'in property default value' => ['/* testBitwiseAndPropertyDefaultValue */'], - 'in method parameter default value' => ['/* testBitwiseAndParamDefaultValue */'], - 'reference for method parameter' => ['/* testBitwiseAnd3 */'], - 'in return statement' => ['/* testBitwiseAnd4 */'], - 'reference for function parameter' => ['/* testBitwiseAnd5 */'], - 'in closure parameter default value' => ['/* testBitwiseAndClosureParamDefault */'], - 'in arrow function parameter default value' => ['/* testBitwiseAndArrowParamDefault */'], - 'in arrow function return expression' => ['/* testBitwiseAndArrowExpression */'], - 'in long array key' => ['/* testBitwiseAndInArrayKey */'], - 'in long array value' => ['/* testBitwiseAndInArrayValue */'], - 'in short array key' => ['/* testBitwiseAndInShortArrayKey */'], - 'in short array value' => ['/* testBitwiseAndInShortArrayValue */'], - 'in parameter in function call' => ['/* testBitwiseAndNonArrowFnFunctionCall */'], - 'function return by reference' => ['/* testBitwiseAnd6 */'], - 'live coding / undetermined' => ['/* testLiveCoding */'], + 'in simple assignment 1' => ['/* testBitwiseAnd1 */'], + 'in simple assignment 2' => ['/* testBitwiseAnd2 */'], + 'in OO constant default value' => ['/* testBitwiseAndOOConstDefaultValue */'], + 'in property default value' => ['/* testBitwiseAndPropertyDefaultValue */'], + 'in method parameter default value' => ['/* testBitwiseAndParamDefaultValue */'], + 'reference for method parameter' => ['/* testBitwiseAnd3 */'], + 'in return statement' => ['/* testBitwiseAnd4 */'], + 'reference for function parameter' => ['/* testBitwiseAnd5 */'], + 'in OO constant default value DNF-like' => ['/* testBitwiseAndOOConstDefaultValueDNF */'], + 'in property default value DNF-like' => ['/* testBitwiseAndPropertyDefaultValueDNF */'], + 'in method parameter default value DNF-like' => ['/* testBitwiseAndParamDefaultValueDNF */'], + 'in closure parameter default value' => ['/* testBitwiseAndClosureParamDefault */'], + 'in arrow function parameter default value' => ['/* testBitwiseAndArrowParamDefault */'], + 'in arrow function return expression' => ['/* testBitwiseAndArrowExpression */'], + 'in long array key' => ['/* testBitwiseAndInArrayKey */'], + 'in long array value' => ['/* testBitwiseAndInArrayValue */'], + 'in short array key' => ['/* testBitwiseAndInShortArrayKey */'], + 'in short array value' => ['/* testBitwiseAndInShortArrayValue */'], + 'in parameter in function call' => ['/* testBitwiseAndNonArrowFnFunctionCall */'], + 'function return by reference' => ['/* testBitwiseAnd6 */'], + 'live coding / undetermined' => ['/* testLiveCoding */'], ]; }//end dataBitwiseAnd() @@ -119,6 +124,12 @@ public static function dataTypeIntersection() 'type for property using fully qualified names' => ['/* testTypeIntersectionPropertyFullyQualified */'], 'type for readonly property' => ['/* testTypeIntersectionPropertyWithReadOnlyKeyword */'], 'type for static readonly property' => ['/* testTypeIntersectionPropertyWithStaticKeyword */'], + 'type for final property' => ['/* testTypeIntersectionWithPHP84FinalKeyword */'], + 'type for final property reversed modifier order' => ['/* testTypeIntersectionWithPHP84FinalKeywordFirst */'], + 'type for asymmetric visibility (private(set)) property' => ['/* testTypeIntersectionPropertyWithPrivateSet */'], + 'type for asymmetric visibility (public private(set)) prop' => ['/* testTypeIntersectionPropertyWithPublicPrivateSet */'], + 'type for asymmetric visibility (protected(set)) property' => ['/* testTypeIntersectionPropertyWithProtectedSet */'], + 'type for asymmetric visibility (public protected(set)) prop' => ['/* testTypeIntersectionPropertyWithPublicProtectedSet */'], 'type for method parameter' => ['/* testTypeIntersectionParam1 */'], 'type for method parameter, first in multi-intersect' => ['/* testTypeIntersectionParam2 */'], 'type for method parameter, last in multi-intersect' => ['/* testTypeIntersectionParam3 */'], @@ -134,6 +145,10 @@ public static function dataTypeIntersection() 'return type for method with fully qualified names' => ['/* testTypeIntersectionReturnFullyQualified */'], 'type for function parameter with reference' => ['/* testTypeIntersectionWithReference */'], 'type for function parameter with spread operator' => ['/* testTypeIntersectionWithSpreadOperator */'], + 'DNF type for OO constant, union before DNF' => ['/* testTypeIntersectionConstantTypeUnionBeforeDNF */'], + 'DNF type for property, union after DNF' => ['/* testTypeIntersectionPropertyTypeUnionAfterDNF */'], + 'DNF type for function param, union before and after DNF' => ['/* testTypeIntersectionParamUnionBeforeAndAfterDNF */'], + 'DNF type for function return, union after DNF with null' => ['/* testTypeIntersectionReturnTypeUnionAfterDNF */'], 'type for closure parameter with illegal nullable' => ['/* testTypeIntersectionClosureParamIllegalNullable */'], 'return type for closure' => ['/* testTypeIntersectionClosureReturn */'], 'type for arrow function parameter' => ['/* testTypeIntersectionArrowParam */'], diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypedConstantsTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypedConstantsTest.inc similarity index 82% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypedConstantsTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypedConstantsTest.inc index a68831392..4c6212b78 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypedConstantsTest.inc +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypedConstantsTest.inc @@ -130,3 +130,27 @@ enum EnumWithIntersectionTypedConstants { /* testEnumConstTypedIntersectFullyQualifiedPartiallyQualified */ const \Fully\Qualified&Partially\Qualified UNION_FQN_PARTIAL = new Partial\Qualified; } + +$anonClassWithDNFTypes = new class() extends Something { + /* testAnonClassConstDNFTypeNullAfter */ + const (A&B)|null DNF_OR_NULL_1 = null; + /* testAnonClassConstDNFTypeNullBefore */ + public final const NULL|(A&B) DNF_OR_NULL_2 = null; + /* testAnonClassConstDNFTypeFalseBefore */ + final const false|(C&D) DNF_OR_FALSE = false; + /* testAnonClassConstDNFTypeTrueAfter */ + private final const ( F & G ) | true DNF_OR_ARRAY = true; + /* testAnonClassConstDNFTypeTrueBeforeFalseAfter */ + public const TRUE|(SplBool&Stringable)|FALSE DNF_OR_BOOL = true; + /* testAnonClassConstDNFTypeArrayAfter */ + final protected const (Traversable&Countable)|array DNF_OR_ARRAY_1 = []; + /* testAnonClassConstDNFTypeArrayBefore */ + private const array /*comment*/ | ( Traversable /*comment*/ & Countable ) DNF_OR_ARRAY_2 = new MyClass; + /* testAnonClassConstDNFTypeInvalidNullable */ + const ? (Invalid&Fatal)|NullableNotAllowed DNF = null; + + /* testAnonClassConstDNFTypeFQNRelativePartiallyQualified */ + const (\FQN&namespace\Relative)|Partially\Qualified DNF_CLASSNAME = MyClass::getInstance(); + /* testAnonClassConstDNFTypeParentSelfStatic */ + const (parent&self)|static DNF_PARENT = parent::getInstance(); +}; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypedConstantsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypedConstantsTest.php similarity index 74% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypedConstantsTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypedConstantsTest.php index 0c4a9b614..6968c4ef8 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/TypedConstantsTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/TypedConstantsTest.php @@ -12,8 +12,9 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; use PHP_CodeSniffer\Util\Tokens; final class TypedConstantsTest extends AbstractTokenizerTestCase @@ -109,14 +110,16 @@ public static function dataUntypedConstant() /** * Test the tokens in the type of a typed constant as well as the constant name are tokenized correctly. * - * @param string $testMarker The comment prefacing the target token. - * @param string $sequence The expected token sequence. + * @param string $testMarker The comment prefacing the target token. + * @param array $sequence The expected token sequence. * * @dataProvider dataTypedConstant * @dataProvider dataNullableTypedConstant * @dataProvider dataUnionTypedConstant * @dataProvider dataIntersectionTypedConstant + * @dataProvider dataDNFTypedConstant * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + * @covers PHP_CodeSniffer\Tokenizers\PHP::processAdditional * * @return void */ @@ -149,7 +152,7 @@ public function testTypedConstant($testMarker, array $sequence) * * @see testTypedConstant() * - * @return array> + * @return array>> */ public static function dataTypedConstant() { @@ -268,7 +271,7 @@ public static function dataTypedConstant() * * @see testTypedConstant() * - * @return array> + * @return array>> */ public static function dataNullableTypedConstant() { @@ -383,7 +386,7 @@ public static function dataNullableTypedConstant() * * @see testTypedConstant() * - * @return array> + * @return array>> */ public static function dataUnionTypedConstant() { @@ -472,7 +475,7 @@ public static function dataUnionTypedConstant() * * @see testTypedConstant() * - * @return array> + * @return array>> */ public static function dataIntersectionTypedConstant() { @@ -512,4 +515,154 @@ public static function dataIntersectionTypedConstant() }//end dataIntersectionTypedConstant() + /** + * Data provider. + * + * @see testTypedConstant() + * + * @return array>> + */ + public static function dataDNFTypedConstant() + { + $data = [ + 'DNF type: null after' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeNullAfter */', + 'sequence' => [ + T_TYPE_OPEN_PARENTHESIS, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + T_TYPE_UNION, + T_NULL, + ], + ], + 'DNF type: null before' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeNullBefore */', + 'sequence' => [ + T_NULL, + T_TYPE_UNION, + T_TYPE_OPEN_PARENTHESIS, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + ], + ], + 'DNF type: false before' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeFalseBefore */', + 'sequence' => [ + T_FALSE, + T_TYPE_UNION, + T_TYPE_OPEN_PARENTHESIS, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + ], + ], + 'DNF type: true after' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeTrueAfter */', + 'sequence' => [ + T_TYPE_OPEN_PARENTHESIS, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + T_TYPE_UNION, + T_TRUE, + ], + ], + 'DNF type: true before, false after' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeTrueBeforeFalseAfter */', + 'sequence' => [ + T_TRUE, + T_TYPE_UNION, + T_TYPE_OPEN_PARENTHESIS, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + T_TYPE_UNION, + T_FALSE, + ], + ], + 'DNF type: array after' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeArrayAfter */', + 'sequence' => [ + T_TYPE_OPEN_PARENTHESIS, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + T_TYPE_UNION, + T_STRING, + ], + ], + 'DNF type: array before' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeArrayBefore */', + 'sequence' => [ + T_STRING, + T_TYPE_UNION, + T_TYPE_OPEN_PARENTHESIS, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + ], + ], + 'DNF type: invalid nullable DNF' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeInvalidNullable */', + 'sequence' => [ + T_NULLABLE, + T_TYPE_OPEN_PARENTHESIS, + T_STRING, + T_TYPE_INTERSECTION, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + T_TYPE_UNION, + T_STRING, + ], + ], + 'DNF type: FQN/namespace relative/partially qualified names' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeFQNRelativePartiallyQualified */', + 'sequence' => [ + T_TYPE_OPEN_PARENTHESIS, + T_NS_SEPARATOR, + T_STRING, + T_TYPE_INTERSECTION, + T_NAMESPACE, + T_NS_SEPARATOR, + T_STRING, + T_TYPE_CLOSE_PARENTHESIS, + T_TYPE_UNION, + T_STRING, + T_NS_SEPARATOR, + T_STRING, + ], + ], + 'DNF type: invalid self/parent/static' => [ + 'testMarker' => '/* testAnonClassConstDNFTypeParentSelfStatic */', + 'sequence' => [ + T_TYPE_OPEN_PARENTHESIS, + T_PARENT, + T_TYPE_INTERSECTION, + T_SELF, + T_TYPE_CLOSE_PARENTHESIS, + T_TYPE_UNION, + T_STATIC, + ], + ], + ]; + + // The constant name, as the last token in the sequence, is always T_STRING. + foreach ($data as $key => $value) { + $data[$key]['sequence'][] = T_STRING; + } + + return $data; + + }//end dataDNFTypedConstant() + + }//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/UndoNamespacedNameSingleTokenTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/UndoNamespacedNameSingleTokenTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/UndoNamespacedNameSingleTokenTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/UndoNamespacedNameSingleTokenTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/UndoNamespacedNameSingleTokenTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/UndoNamespacedNameSingleTokenTest.php similarity index 99% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/UndoNamespacedNameSingleTokenTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/UndoNamespacedNameSingleTokenTest.php index 9e1038dcf..18a88fe8e 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/UndoNamespacedNameSingleTokenTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/UndoNamespacedNameSingleTokenTest.php @@ -17,8 +17,9 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; use PHP_CodeSniffer\Util\Tokens; final class UndoNamespacedNameSingleTokenTest extends AbstractTokenizerTestCase @@ -41,7 +42,7 @@ public function testIdentifierTokenization($testMarker, $expectedTokens) $tokens = $this->phpcsFile->getTokens(); $identifier = $this->getTargetToken($testMarker, constant($expectedTokens[0]['type'])); - foreach ($expectedTokens as $key => $tokenInfo) { + foreach ($expectedTokens as $tokenInfo) { $this->assertSame( constant($tokenInfo['type']), $tokens[$identifier]['code'], diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/YieldTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/YieldTest.inc new file mode 100644 index 000000000..3130b8460 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/YieldTest.inc @@ -0,0 +1,77 @@ +yield; + + /* testYieldUsedAsPropertyName2 */ + echo $obj?->yield(); + + /* testYieldUsedForClassConstantAccess1 */ + echo MyClass::YIELD; + /* testFromUsedForClassConstantAccess1 */ + echo MyClass::FROM; + } + + /* testYieldUsedAsMethodNameReturnByRef */ + public function &yield() {} +} + +function myGen() { + /* testYieldLiveCoding */ + yield diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/YieldTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/YieldTest.php new file mode 100644 index 000000000..efb12096c --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/PHP/YieldTest.php @@ -0,0 +1,448 @@ + + * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; +use PHP_CodeSniffer\Util\Tokens; + +/** + * Tests the tokenization of the `yield` and `yield from` keywords. + * + * @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize + */ +final class YieldTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that the yield keyword is tokenized as such. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expectedContent Expected token content. + * + * @dataProvider dataYieldKeyword + * + * @return void + */ + public function testYieldKeyword($testMarker, $expectedContent) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_YIELD, T_YIELD_FROM, T_STRING]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_YIELD, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_YIELD (code)'); + + // This assertion would fail on PHP 5.4 with PHPUnit 4 as PHPUnit polyfills the `T_YIELD` token too, but + // with a different value, which causes the token 'type' to be set to `UNKNOWN`. + // This issue _only_ occurs when running the tests, not when running PHPCS outside of a test situation. + // The PHPUnit polyfilled token is declared in the PHP_CodeCoverage_Report_HTML_Renderer_File class + // in vendor/phpunit/php-code-coverage/src/CodeCoverage/Report/HTML/Renderer/File.php. + if (PHP_VERSION_ID >= 50500) { + $this->assertSame('T_YIELD', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_YIELD (type)'); + } + + $this->assertSame($expectedContent, $tokenArray['content'], 'Token content does not match expectation'); + + }//end testYieldKeyword() + + + /** + * Data provider. + * + * @see testYieldKeyword() + * + * @return array> + */ + public static function dataYieldKeyword() + { + return [ + 'yield' => [ + 'testMarker' => '/* testYield */', + 'expectedContent' => 'yield', + ], + 'yield followed by comment' => [ + 'testMarker' => '/* testYieldFollowedByComment */', + 'expectedContent' => 'YIELD', + ], + 'yield at end of file, live coding' => [ + 'testMarker' => '/* testYieldLiveCoding */', + 'expectedContent' => 'yield', + ], + ]; + + }//end dataYieldKeyword() + + + /** + * Test that the yield from keyword is tokenized as a single token when it in on a single line + * and only has whitespace between the words. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param string $expectedContent Expected token content. + * + * @dataProvider dataYieldFromKeywordSingleToken + * + * @return void + */ + public function testYieldFromKeywordSingleToken($testMarker, $expectedContent) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_YIELD, T_YIELD_FROM, T_STRING]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_YIELD_FROM, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_YIELD_FROM (code)'); + $this->assertSame('T_YIELD_FROM', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_YIELD_FROM (type)'); + + if (isset($tokenArray['orig_content']) === true) { + $this->assertSame($expectedContent, $tokenArray['orig_content'], 'Token (orig) content does not match expectation'); + } else { + $this->assertSame($expectedContent, $tokenArray['content'], 'Token content does not match expectation'); + } + + }//end testYieldFromKeywordSingleToken() + + + /** + * Data provider. + * + * @see testYieldFromKeywordSingleToken() + * + * @return array> + */ + public static function dataYieldFromKeywordSingleToken() + { + return [ + 'yield from' => [ + 'testMarker' => '/* testYieldFrom */', + 'expectedContent' => 'yield from', + ], + 'yield from with extra space between' => [ + 'testMarker' => '/* testYieldFromWithExtraSpacesBetween */', + 'expectedContent' => 'Yield From', + ], + 'yield from with tab between' => [ + 'testMarker' => '/* testYieldFromWithTabBetween */', + 'expectedContent' => 'yield from', + ], + ]; + + }//end dataYieldFromKeywordSingleToken() + + + /** + * Test that the yield from keyword is tokenized as a single token when it in on a single line + * and only has whitespace between the words. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array> $expectedTokens The tokenization expected. + * + * @dataProvider dataYieldFromKeywordMultiToken + * + * @return void + */ + public function testYieldFromKeywordMultiToken($testMarker, $expectedTokens) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_YIELD, T_YIELD_FROM, T_STRING]); + + foreach ($expectedTokens as $nr => $tokenInfo) { + $this->assertSame( + constant($tokenInfo['type']), + $tokens[$target]['code'], + 'Token tokenized as '.Tokens::tokenName($tokens[$target]['code']).', not '.$tokenInfo['type'].' (code)' + ); + $this->assertSame( + $tokenInfo['type'], + $tokens[$target]['type'], + 'Token tokenized as '.$tokens[$target]['type'].', not '.$tokenInfo['type'].' (type)' + ); + $this->assertSame( + $tokenInfo['content'], + $tokens[$target]['content'], + 'Content of token '.($nr + 1).' ('.$tokens[$target]['type'].') does not match expectations' + ); + + ++$target; + } + + }//end testYieldFromKeywordMultiToken() + + + /** + * Data provider. + * + * @see testYieldFromKeywordMultiToken() + * + * @return array>>> + */ + public static function dataYieldFromKeywordMultiToken() + { + return [ + 'yield from with new line' => [ + 'testMarker' => '/* testYieldFromSplitByNewLines */', + 'expectedTokens' => [ + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'yield', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'FROM', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'yield from with comment' => [ + 'testMarker' => '/* testYieldFromSplitByComment */', + 'expectedTokens' => [ + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'yield', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '/* comment */', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'from', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + ], + ], + 'yield from with trailing comment' => [ + 'testMarker' => '/* testYieldFromWithTrailingComment */', + 'expectedTokens' => [ + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'yield', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// comment +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'from', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + ], + ], + 'yield from with trailing annotation' => [ + 'testMarker' => '/* testYieldFromWithTrailingAnnotation */', + 'expectedTokens' => [ + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'yield', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_PHPCS_IGNORE', + 'content' => '// phpcs:ignore Stnd.Cat.Sniff -- for reasons. +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'from', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + ], + ], + 'yield from with new line and comment' => [ + 'testMarker' => '/* testYieldFromSplitByNewLineAndComments */', + 'expectedTokens' => [ + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'yield', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '/* comment line 1 +', + ], + [ + 'type' => 'T_COMMENT', + 'content' => ' line 2 */', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_COMMENT', + 'content' => '// another comment +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'from', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + 'yield from with new line and annotation' => [ + 'testMarker' => '/* testYieldFromSplitByNewLineAndAnnotation */', + 'expectedTokens' => [ + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'YIELD', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_PHPCS_DISABLE', + 'content' => '// @phpcs:disable Stnd.Cat.Sniff -- for reasons. +', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' ', + ], + [ + 'type' => 'T_YIELD_FROM', + 'content' => 'From', + ], + [ + 'type' => 'T_WHITESPACE', + 'content' => ' +', + ], + ], + ], + ]; + + }//end dataYieldFromKeywordMultiToken() + + + /** + * Test that 'yield' or 'from' when not used as the reserved keyword are tokenized as `T_STRING`. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataYieldNonKeyword + * + * @return void + */ + public function testYieldNonKeyword($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_YIELD, T_YIELD_FROM, T_STRING]); + $tokenArray = $tokens[$target]; + + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + $this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)'); + + }//end testYieldNonKeyword() + + + /** + * Data provider. + * + * @see testYieldNonKeyword() + * + * @return array> + */ + public static function dataYieldNonKeyword() + { + return [ + 'yield used as class name' => ['/* testYieldUsedAsClassName */'], + 'yield used as class constant name' => ['/* testYieldUsedAsClassConstantName */'], + 'yield used as method name' => ['/* testYieldUsedAsMethodName */'], + 'yield used as property access 1' => ['/* testYieldUsedAsPropertyName1 */'], + 'yield used as property access 2' => ['/* testYieldUsedAsPropertyName2 */'], + 'yield used as class constant access' => ['/* testYieldUsedForClassConstantAccess1 */'], + 'from used as class constant access' => ['/* testFromUsedForClassConstantAccess1 */'], + 'yield used as method name with ref' => ['/* testYieldUsedAsMethodNameReturnByRef */'], + ]; + + }//end dataYieldNonKeyword() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateParenthesisNestingMapDNFTypesTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateParenthesisNestingMapDNFTypesTest.inc new file mode 100644 index 000000000..89031bd19 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateParenthesisNestingMapDNFTypesTest.inc @@ -0,0 +1,185 @@ + 10 ) {} + +/* testParensOwnerFor */ +for ($i =0; $i < /* testParensNoOwnerInForCondition */ ( CONST_A & CONST_B ); $i++ ); + +/* testParensOwnerMatch */ +$match = match(CONST_A & CONST_B) { + default => $a, +}; + +/* testParensOwnerArray */ +$array = array ( + 'text', + \CONST_A & \Fully\Qualified\CONST_B, + /* testParensNoOwnerFunctionCallWithAmpersandInCallable */ + do_something($a, /* testParensOwnerArrowFn */ fn($b) => $a & $b, $c), +); + +/* testParensOwnerListWithRefVars */ +list(&$a, &$b) = $array; + +/* testParensNoOwnerFunctionCallwithDNFLookALikeParam */ +$obj->static((CONST_A&CONST_B)|CONST_C | $var); + + +/* + * DNF parentheses. + */ + +abstract class DNFTypes { + /* testDNFTypeOOConstUnqualifiedClasses */ + public const (A&B)|D UNQUALIFIED = new Foo; + + /* testDNFTypeOOConstReverseModifierOrder */ + protected final const int|(Foo&Bar)|float MODIFIERS_REVERSED /* testParensNoOwnerOOConstDefaultValue */ = (E_WARNING & E_NOTICE) | E_DEPRECATED; + + const + /* testDNFTypeOOConstMulti1 */ + (A&B) | + /* testDNFTypeOOConstMulti2 */ + (C&D) | // phpcs:ignore Stnd.Cat.Sniff + /* testDNFTypeOOConstMulti3 */ + (Y&D) + | null MULTI_DNF = null; + + /* testDNFTypeOOConstNamespaceRelative */ + final protected const (namespace\Sub\NameA&namespace\Sub\NameB)|namespace\Sub\NameC NAMESPACE_RELATIVE = new namespace\Sub\NameB; + + /* testDNFTypeOOConstPartiallyQualified */ + const Partially\Qualified\NameC|(Partially\Qualified\NameA&Partially\Qualified\NameB) PARTIALLY_QUALIFIED = new Partially\Qualified\NameA; + + /* testDNFTypeOOConstFullyQualified */ + const (\Fully\Qualified\NameA&\Fully\Qualified\NameB)|\Fully\Qualified\NameC FULLY_QUALIFIED = new \Fully\Qualified\NameB(); + + /* testDNFTypePropertyUnqualifiedClasses */ + public static (Foo&Bar)|array $obj; + + /* testDNFTypePropertyReverseModifierOrder */ + static protected string|(A&B)|int $dnf /* testParensNoOwnerPropertyDefaultValue1 */ = ( E_WARNING & E_NOTICE ) | /* testParensNoOwnerPropertyDefaultValue2 */ (E_ALL & E_DEPRECATED); + + private + /* testDNFTypePropertyMultiNamespaceRelative */ + (namespace\Sub\NameA&namespace\Sub\NameB) | + /* testDNFTypePropertyMultiPartiallyQualified */ + (Partially\Qualified\NameA&Partially\Qualified\NameB) | // phpcs:ignore Stnd.Cat.Sniff + false + /* testDNFTypePropertyMultiFullyQualified */ + | (\Fully\Qualified\NameA&\Fully\Qualified\NameB) $multiDnf; + + /* testDNFTypePropertyWithReadOnlyKeyword1 */ + protected readonly (A&B) | /* testDNFTypePropertyWithReadOnlyKeyword2 */ (C&D) $readonly; + + /* testDNFTypePropertyWithStaticAndReadOnlyKeywords */ + static readonly (A&B&C)|array $staticReadonly; + + /* testDNFTypePropertyWithOnlyStaticKeyword */ + static (A&B&C)|true $onlyStaticModified; + + public function paramTypes( + /* testDNFTypeParam1WithAttribute */ + #[MyAttribute] + (\Foo&Bar)|int|float $paramA /* testParensNoOwnerParamDefaultValue */ = SOMETHING | (CONSTANT_A & CONSTANT_B), + + /* testDNFTypeParam2 */ + (Foo&\Bar) /* testDNFTypeParam3 */ |(Baz&Fop) &...$paramB, + ) { + /* testParensNoOwnerInReturnValue1 */ + return ( + /* testParensNoOwnerInReturnValue2 */ + ($a1 & $b1) | + /* testParensNoOwnerInReturnValue3 */ + ($a2 & $b2) + ) + $c; + } + + public function identifierNames( + /* testDNFTypeParamNamespaceRelative */ + (namespace\Sub\NameA&namespace\Sub\NameB)|false $paramA, + /* testDNFTypeParamPartiallyQualified */ + Partially\Qualified\NameC|(Partially\Qualified\NameA&Partially\Qualified\NameB) $paramB, + /* testDNFTypeParamFullyQualified */ + name|(\Fully\Qualified\NameA&\Fully\Qualified\NameB) $paramC, + ) {} + + public function __construct( + /* testDNFTypeConstructorPropertyPromotion1 */ + public (A&B)| /* testDNFTypeConstructorPropertyPromotion2 */ (A&D) $property + ) {} + + public function returnType()/* testDNFTypeReturnType1 */ : A|(B&D)|/* testDNFTypeReturnType2 */(B&W)|null {} + + abstract public function abstractMethod(): /* testDNFTypeAbstractMethodReturnType1 */ (X&Y) /* testDNFTypeAbstractMethodReturnType2 */ |(W&Z); + + public function identifierNamesReturnRelative( + ) : /* testDNFTypeReturnTypeNamespaceRelative */ (namespace\Sub\NameA&namespace\Sub\NameB)|namespace\Sub\NameC {} + + public function identifierNamesReturnPQ( + ) : /* testDNFTypeReturnPartiallyQualified */Partially\Qualified\NameA|(Partially\Qualified\NameB&Partially\Qualified\NameC) {} + + // Illegal type: segments which are strict subsets of others are disallowed, but that's not the concern of the tokenizer. + public function identifierNamesReturnFQ( + ) /* testDNFTypeReturnFullyQualified */ : (\Fully\Qualified\NameA&\Fully\Qualified\NameB)|\Fully\Qualified\NameB {} +} + +function globalFunctionWithSpreadAndReference( + /* testDNFTypeWithReference */ + float|(B&A) &$paramA, + /* testDNFTypeWithSpreadOperator */ + string|(B&D) ...$paramB +) {} + + +$closureWithParamType = function ( /* testDNFTypeClosureParamIllegalNullable */ ?(A&B)|bool $string) {}; + +/* testParensOwnerClosureAmpersandInDefaultValue */ +$closureWithReturnType = function ($string = NONSENSE & FAKE) /* testDNFTypeClosureReturn */ : (\Package\MyA&PackageB)|null {}; + +/* testParensOwnerArrowDNFUsedWithin */ +$arrowWithParamType = fn ( + /* testDNFTypeArrowParam */ + int|(A&B&C)|array $param, + /* testParensNoOwnerAmpersandInDefaultValue */ ?int $int = (CONSTA & CONSTB )| CONST_C +) + /* testParensNoOwnerInArrowReturnExpression */ + => ($param & $foo ) | $int; + +$arrowWithReturnType = fn ($param) : /* testDNFTypeArrowReturnType */ int|(A&B) => $param * 10; + +$arrowWithParamReturnByRef = fn &( + /* testDNFTypeArrowParamWithReturnByRef */ + (A&B)|null $param +) => $param * 10; + +function InvalidSyntaxes( + /* testDNFTypeParamIllegalUnnecessaryParens */ + (A&B) $parensNotNeeded, + + /* testDNFTypeParamIllegalIntersectUnionReversed */ + A&(B|D) $onlyIntersectAllowedWithinParensAndUnionOutside, + + /* testDNFTypeParamIllegalNestedParens */ + A|(B&(D|W)|null) $nestedParensNotAllowed, +) {} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateParenthesisNestingMapDNFTypesTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateParenthesisNestingMapDNFTypesTest.php new file mode 100644 index 000000000..d8393387c --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateParenthesisNestingMapDNFTypesTest.php @@ -0,0 +1,374 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class CreateParenthesisNestingMapDNFTypesTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that parentheses when **not** used in a type declaration are correctly tokenized. + * + * @param string $testMarker The comment prefacing the target token. + * @param int|false $owner Optional. The parentheses owner or false when no parentheses owner is expected. + * + * @dataProvider dataNormalParentheses + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createParenthesisNestingMap + * + * @return void + */ + public function testNormalParentheses($testMarker, $owner=false) + { + $tokens = $this->phpcsFile->getTokens(); + + $openPtr = $this->getTargetToken($testMarker, [T_OPEN_PARENTHESIS, T_TYPE_OPEN_PARENTHESIS]); + $opener = $tokens[$openPtr]; + + // Make sure we're looking at the right token. + $this->assertSame(T_OPEN_PARENTHESIS, $opener['code'], 'Token tokenized as '.$opener['type'].', not T_OPEN_PARENTHESIS (code)'); + + if ($owner !== false) { + $this->assertArrayHasKey('parenthesis_owner', $opener, 'Parenthesis owner is not set'); + $this->assertSame(($openPtr + $owner), $opener['parenthesis_owner'], 'Opener parenthesis owner is not the expected token'); + } else { + $this->assertArrayNotHasKey('parenthesis_owner', $opener, 'Parenthesis owner is set'); + } + + $this->assertArrayHasKey('parenthesis_opener', $opener, 'Parenthesis opener is not set'); + $this->assertArrayHasKey('parenthesis_closer', $opener, 'Parenthesis closer is not set'); + $this->assertSame($openPtr, $opener['parenthesis_opener'], 'Parenthesis opener is not the expected token'); + + $closePtr = $opener['parenthesis_closer']; + $closer = $tokens[$closePtr]; + + // Make sure we're looking at the right token. + $this->assertSame(T_CLOSE_PARENTHESIS, $closer['code'], 'Token tokenized as '.$closer['type'].', not T_CLOSE_PARENTHESIS (code)'); + + if ($owner !== false) { + $this->assertArrayHasKey('parenthesis_owner', $closer, 'Parenthesis owner is not set'); + $this->assertSame(($openPtr + $owner), $closer['parenthesis_owner'], 'Closer parenthesis owner is not the expected token'); + } else { + $this->assertArrayNotHasKey('parenthesis_owner', $closer, 'Parenthesis owner is set'); + } + + $this->assertArrayHasKey('parenthesis_opener', $closer, 'Parenthesis opener is not set'); + $this->assertArrayHasKey('parenthesis_closer', $closer, 'Parenthesis closer is not set'); + $this->assertSame($closePtr, $closer['parenthesis_closer'], 'Parenthesis closer is not the expected token'); + + for ($i = ($openPtr + 1); $i < $closePtr; $i++) { + $this->assertArrayHasKey('nested_parenthesis', $tokens[$i], "Nested parenthesis key not set on token $i ({$tokens[$i]['type']})"); + $this->assertArrayHasKey($openPtr, $tokens[$i]['nested_parenthesis'], 'Nested parenthesis is missing target parentheses set'); + $this->assertSame($closePtr, $tokens[$i]['nested_parenthesis'][$openPtr], 'Nested parenthesis closer not set correctly'); + } + + }//end testNormalParentheses() + + + /** + * Data provider. + * + * @see testNormalParentheses() + * + * @return array> + */ + public static function dataNormalParentheses() + { + // "Owner" offsets are relative to the open parenthesis. + return [ + 'parens without owner' => [ + 'testMarker' => '/* testParensNoOwner */', + ], + 'parens without owner in ternary then' => [ + 'testMarker' => '/* testParensNoOwnerInTernary */', + ], + 'parens without owner in short ternary' => [ + 'testMarker' => '/* testParensNoOwnerInShortTernary */', + ], + 'parens with owner: function; & in default value' => [ + 'testMarker' => '/* testParensOwnerFunctionAmpersandInDefaultValue */', + 'owner' => -3, + ], + 'parens with owner: closure; param declared by & ref' => [ + 'testMarker' => '/* testParensOwnerClosureAmpersandParamRef */', + 'owner' => -1, + ], + 'parens with owner: if' => [ + 'testMarker' => '/* testParensOwnerIf */', + 'owner' => -2, + ], + 'parens without owner in if condition' => [ + 'testMarker' => '/* testParensNoOwnerInIfCondition */', + ], + 'parens with owner: for' => [ + 'testMarker' => '/* testParensOwnerFor */', + 'owner' => -2, + ], + 'parens without owner in for condition' => [ + 'testMarker' => '/* testParensNoOwnerInForCondition */', + ], + 'parens with owner: match' => [ + 'testMarker' => '/* testParensOwnerMatch */', + 'owner' => -1, + ], + 'parens with owner: array' => [ + 'testMarker' => '/* testParensOwnerArray */', + 'owner' => -2, + ], + 'parens without owner in array; function call with & in callable' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallWithAmpersandInCallable */', + ], + 'parens with owner: fn; & in return value' => [ + 'testMarker' => '/* testParensOwnerArrowFn */', + 'owner' => -1, + ], + 'parens with owner: list with reference vars' => [ + 'testMarker' => '/* testParensOwnerListWithRefVars */', + 'owner' => -1, + ], + 'parens without owner, function call with DNF look-a-like param' => [ + 'testMarker' => '/* testParensNoOwnerFunctionCallwithDNFLookALikeParam */', + ], + + 'parens without owner in OO const default value' => [ + 'testMarker' => '/* testParensNoOwnerOOConstDefaultValue */', + ], + 'parens without owner in property default 1' => [ + 'testMarker' => '/* testParensNoOwnerPropertyDefaultValue1 */', + ], + 'parens without owner in property default 2' => [ + 'testMarker' => '/* testParensNoOwnerPropertyDefaultValue2 */', + ], + 'parens without owner in param default value' => [ + 'testMarker' => '/* testParensNoOwnerParamDefaultValue */', + ], + 'parens without owner in return statement 1' => [ + 'testMarker' => '/* testParensNoOwnerInReturnValue1 */', + ], + 'parens without owner in return statement 2' => [ + 'testMarker' => '/* testParensNoOwnerInReturnValue2 */', + ], + 'parens without owner in return statement 3' => [ + 'testMarker' => '/* testParensNoOwnerInReturnValue3 */', + ], + 'parens with owner: closure; & in default value' => [ + 'testMarker' => '/* testParensOwnerClosureAmpersandInDefaultValue */', + 'owner' => -2, + ], + 'parens with owner: fn; dnf used within' => [ + 'testMarker' => '/* testParensOwnerArrowDNFUsedWithin */', + 'owner' => -2, + ], + 'parens without owner: default value for param in arrow function' => [ + 'testMarker' => '/* testParensNoOwnerAmpersandInDefaultValue */', + ], + 'parens without owner in arrow function return expression' => [ + 'testMarker' => '/* testParensNoOwnerInArrowReturnExpression */', + ], + ]; + + }//end dataNormalParentheses() + + + /** + * Test that parentheses when used in a DNF type declaration are correctly tokenized. + * + * Includes verifying that: + * - the tokens between the parentheses all have a "nested_parenthesis" key. + * - all ampersands between the parentheses are tokenized as T_TYPE_INTERSECTION. + * + * @param string $testMarker The comment prefacing the target token. + * + * @dataProvider dataDNFTypeParentheses + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createParenthesisNestingMap + * + * @return void + */ + public function testDNFTypeParentheses($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + + $openPtr = $this->getTargetToken($testMarker, [T_OPEN_PARENTHESIS, T_TYPE_OPEN_PARENTHESIS]); + $opener = $tokens[$openPtr]; + + // Make sure we're looking at the right token. + $this->assertSame(T_TYPE_OPEN_PARENTHESIS, $opener['code'], 'Token tokenized as '.$opener['type'].', not T_TYPE_OPEN_PARENTHESIS (code)'); + + $this->assertArrayNotHasKey('parenthesis_owner', $opener, 'Parenthesis owner is set'); + $this->assertArrayHasKey('parenthesis_opener', $opener, 'Parenthesis opener is not set'); + $this->assertArrayHasKey('parenthesis_closer', $opener, 'Parenthesis closer is not set'); + $this->assertSame($openPtr, $opener['parenthesis_opener'], 'Parenthesis opener is not the expected token'); + + $closePtr = $opener['parenthesis_closer']; + $closer = $tokens[$closePtr]; + + // Make sure we're looking at the right token. + $this->assertSame(T_TYPE_CLOSE_PARENTHESIS, $closer['code'], 'Token tokenized as '.$closer['type'].', not T_TYPE_CLOSE_PARENTHESIS (code)'); + + $this->assertArrayNotHasKey('parenthesis_owner', $closer, 'Parenthesis owner is set'); + $this->assertArrayHasKey('parenthesis_opener', $closer, 'Parenthesis opener is not set'); + $this->assertArrayHasKey('parenthesis_closer', $closer, 'Parenthesis closer is not set'); + $this->assertSame($closePtr, $closer['parenthesis_closer'], 'Parenthesis closer is not the expected token'); + + for ($i = ($openPtr + 1); $i < $closePtr; $i++) { + $this->assertArrayHasKey('nested_parenthesis', $tokens[$i], "Nested parenthesis key not set on token $i ({$tokens[$i]['type']})"); + $this->assertArrayHasKey($openPtr, $tokens[$i]['nested_parenthesis'], 'Nested parenthesis is missing target parentheses set'); + $this->assertSame($closePtr, $tokens[$i]['nested_parenthesis'][$openPtr], 'Nested parenthesis closer not set correctly'); + }//end for + + }//end testDNFTypeParentheses() + + + /** + * Data provider. + * + * @see testDNFTypeParentheses() + * + * @return array> + */ + public static function dataDNFTypeParentheses() + { + return [ + 'OO const type: unqualified classes' => [ + 'testMarker' => '/* testDNFTypeOOConstUnqualifiedClasses */', + ], + 'OO const type: modifiers in reverse order' => [ + 'testMarker' => '/* testDNFTypeOOConstReverseModifierOrder */', + ], + 'OO const type: multi-dnf part 1' => [ + 'testMarker' => '/* testDNFTypeOOConstMulti1 */', + ], + 'OO const type: multi-dnf part 2' => [ + 'testMarker' => '/* testDNFTypeOOConstMulti2 */', + ], + 'OO const type: multi-dnf part 3' => [ + 'testMarker' => '/* testDNFTypeOOConstMulti3 */', + ], + 'OO const type: namespace relative classes' => [ + 'testMarker' => '/* testDNFTypeOOConstNamespaceRelative */', + ], + 'OO const type: partially qualified classes' => [ + 'testMarker' => '/* testDNFTypeOOConstPartiallyQualified */', + ], + 'OO const type: fully qualified classes' => [ + 'testMarker' => '/* testDNFTypeOOConstFullyQualified */', + ], + + 'OO property type: unqualified classes' => [ + 'testMarker' => '/* testDNFTypePropertyUnqualifiedClasses */', + ], + 'OO property type: modifiers in reverse order' => [ + 'testMarker' => '/* testDNFTypePropertyReverseModifierOrder */', + ], + 'OO property type: multi-dnf namespace relative classes' => [ + 'testMarker' => '/* testDNFTypePropertyMultiNamespaceRelative */', + ], + 'OO property type: multi-dnf partially qualified classes' => [ + 'testMarker' => '/* testDNFTypePropertyMultiPartiallyQualified */', + ], + 'OO property type: multi-dnf fully qualified classes' => [ + 'testMarker' => '/* testDNFTypePropertyMultiFullyQualified */', + ], + + 'OO property type: multi-dnf with readonly keyword 1' => [ + 'testMarker' => '/* testDNFTypePropertyWithReadOnlyKeyword1 */', + ], + 'OO property type: multi-dnf with readonly keyword 2' => [ + 'testMarker' => '/* testDNFTypePropertyWithReadOnlyKeyword2 */', + ], + 'OO property type: with static and readonly keywords' => [ + 'testMarker' => '/* testDNFTypePropertyWithStaticAndReadOnlyKeywords */', + ], + 'OO property type: with only static keyword' => [ + 'testMarker' => '/* testDNFTypePropertyWithOnlyStaticKeyword */', + ], + 'OO method param type: first param' => [ + 'testMarker' => '/* testDNFTypeParam1WithAttribute */', + ], + 'OO method param type: second param, first DNF' => [ + 'testMarker' => '/* testDNFTypeParam2 */', + ], + 'OO method param type: second param, second DNF' => [ + 'testMarker' => '/* testDNFTypeParam3 */', + ], + 'OO method param type: namespace relative classes' => [ + 'testMarker' => '/* testDNFTypeParamNamespaceRelative */', + ], + 'OO method param type: partially qualified classes' => [ + 'testMarker' => '/* testDNFTypeParamPartiallyQualified */', + ], + 'OO method param type: fully qualified classes' => [ + 'testMarker' => '/* testDNFTypeParamFullyQualified */', + ], + 'Constructor property promotion with multi DNF 1' => [ + 'testMarker' => '/* testDNFTypeConstructorPropertyPromotion1 */', + ], + 'Constructor property promotion with multi DNF 2' => [ + 'testMarker' => '/* testDNFTypeConstructorPropertyPromotion2 */', + ], + 'OO method return type: multi DNF 1' => [ + 'testMarker' => '/* testDNFTypeReturnType1 */', + ], + 'OO method return type: multi DNF 2' => [ + 'testMarker' => '/* testDNFTypeReturnType2 */', + ], + 'OO abstract method return type: multi DNF 1' => [ + 'testMarker' => '/* testDNFTypeAbstractMethodReturnType1 */', + ], + 'OO abstract method return type: multi DNF 2' => [ + 'testMarker' => '/* testDNFTypeAbstractMethodReturnType2 */', + ], + 'OO method return type: namespace relative classes' => [ + 'testMarker' => '/* testDNFTypeReturnTypeNamespaceRelative */', + ], + 'OO method return type: partially qualified classes' => [ + 'testMarker' => '/* testDNFTypeReturnPartiallyQualified */', + ], + 'OO method return type: fully qualified classes' => [ + 'testMarker' => '/* testDNFTypeReturnFullyQualified */', + ], + 'function param type: with reference' => [ + 'testMarker' => '/* testDNFTypeWithReference */', + ], + 'function param type: with spread' => [ + 'testMarker' => '/* testDNFTypeWithSpreadOperator */', + ], + 'closure param type: with illegal nullable' => [ + 'testMarker' => '/* testDNFTypeClosureParamIllegalNullable */', + ], + 'closure return type' => [ + 'testMarker' => '/* testDNFTypeClosureReturn */', + ], + 'arrow function param type' => [ + 'testMarker' => '/* testDNFTypeArrowParam */', + ], + 'arrow function return type' => [ + 'testMarker' => '/* testDNFTypeArrowReturnType */', + ], + 'arrow function param type with return by ref' => [ + 'testMarker' => '/* testDNFTypeArrowParamWithReturnByRef */', + ], + + 'illegal syntax: unnecessary parentheses (no union)' => [ + 'testMarker' => '/* testDNFTypeParamIllegalUnnecessaryParens */', + ], + 'illegal syntax: union within parentheses, intersect outside' => [ + 'testMarker' => '/* testDNFTypeParamIllegalIntersectUnionReversed */', + ], + 'illegal syntax: nested parentheses' => [ + 'testMarker' => '/* testDNFTypeParamIllegalNestedParens */', + ], + ]; + + }//end dataDNFTypeParentheses() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocNowdocCloserTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapHeredocNowdocCloserTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocNowdocCloserTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapHeredocNowdocCloserTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocNowdocCloserTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapHeredocNowdocCloserTest.php similarity index 93% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocNowdocCloserTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapHeredocNowdocCloserTest.php index d43768f0e..fb9f04939 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/HeredocNowdocCloserTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapHeredocNowdocCloserTest.php @@ -7,14 +7,18 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; /** * Heredoc/nowdoc closer token test. * * @requires PHP 7.3 + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap */ -final class HeredocNowdocCloserTest extends AbstractTokenizerTestCase +final class CreatePositionMapHeredocNowdocCloserTest extends AbstractTokenizerTestCase { @@ -25,7 +29,6 @@ final class HeredocNowdocCloserTest extends AbstractTokenizerTestCase * @param array $expected Expectations for the token array. * * @dataProvider dataHeredocNowdocCloserTabReplacement - * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap * * @return void */ diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapHeredocNowdocOpenerTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapHeredocNowdocOpenerTest.inc new file mode 100644 index 000000000..dc2b2f2dc --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapHeredocNowdocOpenerTest.inc @@ -0,0 +1,31 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +/** + * Heredoc/nowdoc opener token test. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap + */ +final class CreatePositionMapHeredocNowdocOpenerTest extends AbstractTokenizerTestCase +{ + + + /** + * Verify that spaces/tabs in a heredoc/nowdoc opener token get the tab replacement treatment. + * + * @param string $testMarker The comment prefacing the target token. + * @param array $expected Expectations for the token array. + * + * @dataProvider dataHeredocNowdocOpenerTabReplacement + * + * @return void + */ + public function testHeredocNowdocOpenerTabReplacement($testMarker, $expected) + { + $tokens = $this->phpcsFile->getTokens(); + $opener = $this->getTargetToken($testMarker, [T_START_HEREDOC, T_START_NOWDOC]); + + foreach ($expected as $key => $value) { + if ($key === 'orig_content' && $value === null) { + $this->assertArrayNotHasKey($key, $tokens[$opener], "Unexpected 'orig_content' key found in the token array."); + continue; + } + + $this->assertArrayHasKey($key, $tokens[$opener], "Key $key not found in the token array."); + $this->assertSame($value, $tokens[$opener][$key], "Value for key $key does not match expectation."); + } + + }//end testHeredocNowdocOpenerTabReplacement() + + + /** + * Data provider. + * + * @see testHeredocNowdocOpenerTabReplacement() + * + * @return array>> + */ + public static function dataHeredocNowdocOpenerTabReplacement() + { + return [ + 'Heredoc opener without space' => [ + 'testMarker' => '/* testHeredocOpenerNoSpace */', + 'expected' => [ + 'length' => 6, + 'content' => '<< null, + ], + ], + 'Nowdoc opener without space' => [ + 'testMarker' => '/* testNowdocOpenerNoSpace */', + 'expected' => [ + 'length' => 8, + 'content' => "<<<'EOD' +", + 'orig_content' => null, + ], + ], + 'Heredoc opener with space(s)' => [ + 'testMarker' => '/* testHeredocOpenerHasSpace */', + 'expected' => [ + 'length' => 7, + 'content' => '<<< END +', + 'orig_content' => null, + ], + ], + 'Nowdoc opener with space(s)' => [ + 'testMarker' => '/* testNowdocOpenerHasSpace */', + 'expected' => [ + 'length' => 21, + 'content' => "<<< 'END' +", + 'orig_content' => null, + ], + ], + 'Heredoc opener with tab(s)' => [ + 'testMarker' => '/* testHeredocOpenerHasTab */', + 'expected' => [ + 'length' => 18, + 'content' => '<<< "END" +', + 'orig_content' => '<<< "END" +', + ], + ], + 'Nowdoc opener with tab(s)' => [ + 'testMarker' => '/* testNowdocOpenerHasTab */', + 'expected' => [ + 'length' => 11, + 'content' => "<<< 'END' +", + 'orig_content' => "<<< 'END' +", + ], + ], + ]; + + }//end dataHeredocNowdocOpenerTabReplacement() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapTabWidth0Test.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapTabWidth0Test.php new file mode 100644 index 000000000..fd47bf7da --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapTabWidth0Test.php @@ -0,0 +1,107 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +/** + * Tab replacement test using tab width 0, means no tab replacement will take place. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap + */ +final class CreatePositionMapTabWidth0Test extends ReplaceTabsInTokenTestCase +{ + + /** + * The tab width setting to use when tokenizing the file. + * + * @var integer + */ + protected $tabWidth = 0; + + + /** + * Data provider helper. + * + * @see ReplaceTabsInTokenTestCase::dataTabReplacement() + * + * @return array> + */ + public static function getTabReplacementExpected() + { + return [ + 'Tab indentation' => [ + 'length' => 2, + 'content' => ' ', + 'orig_content' => null, + ], + 'Mixed tab/space indentation' => [ + 'length' => 3, + 'content' => ' ', + 'orig_content' => null, + ], + 'Inline: single tab in text string' => [ + 'length' => 15, + 'content' => "'tab separated'", + 'orig_content' => null, + ], + 'Inline: single tab between each word in text string' => [ + 'length' => 24, + 'content' => '"tab $between each word"', + 'orig_content' => null, + ], + 'Inline: multiple tabs in heredoc' => [ + 'length' => 15, + 'content' => 'tab separated +', + 'orig_content' => null, + ], + 'Inline: multiple tabs between each word in nowdoc' => [ + 'length' => 27, + 'content' => 'tab between each word +', + 'orig_content' => null, + ], + 'Inline: mixed spaces/tabs in text string' => [ + 'length' => 20, + 'content' => "'tab separated'", + 'orig_content' => null, + ], + 'Inline: mixed spaces/tabs between each word in text string' => [ + 'length' => 31, + 'content' => '"tab $between each word"', + 'orig_content' => null, + ], + 'Inline: tab becomes single space in comment (with tabwidth 4)' => [ + 'length' => 50, + 'content' => '// -123 With tabwidth 4, the tab size should be 1. +', + 'orig_content' => null, + ], + 'Inline: tab becomes 2 spaces in comment (with tabwidth 4)' => [ + 'length' => 52, + 'content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + 'orig_content' => null, + ], + 'Inline: tab becomes 3 spaces in doc comment string (with tabwidth 4)' => [ + 'length' => 45, + 'content' => '-1 With tabwidth 4, the tab size should be 3.', + 'orig_content' => null, + ], + 'Inline: tab becomes 4 spaces in comment (with tabwidth 4)' => [ + 'length' => 47, + 'content' => '// - With tabwidth 4, the tab size should be 4. +', + 'orig_content' => null, + ], + ]; + + }//end getTabReplacementExpected() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapYieldFromTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapYieldFromTest.inc new file mode 100644 index 000000000..59365dd5c --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreatePositionMapYieldFromTest.inc @@ -0,0 +1,15 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +/** + * Yield from token test. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createPositionMap + */ +final class CreatePositionMapYieldFromTest extends AbstractTokenizerTestCase +{ + + + /** + * Verify that spaces/tabs in "yield from" tokens get the tab replacement treatment. + * + * @param string $testMarker The comment prefacing the target token. + * @param array $expected Expectations for the token array. + * @param string $content Optional. The test token content to search for. + * Defaults to null. + * + * @dataProvider dataYieldFromTabReplacement + * + * @return void + */ + public function testYieldFromTabReplacement($testMarker, $expected, $content=null) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, [T_YIELD_FROM], $content); + + foreach ($expected as $key => $value) { + if ($key === 'orig_content' && $value === null) { + $this->assertArrayNotHasKey($key, $tokens[$target], "Unexpected 'orig_content' key found in the token array."); + continue; + } + + $this->assertArrayHasKey($key, $tokens[$target], "Key $key not found in the token array."); + $this->assertSame($value, $tokens[$target][$key], "Value for key $key does not match expectation."); + } + + }//end testYieldFromTabReplacement() + + + /** + * Data provider. + * + * @see testYieldFromTabReplacement() + * + * @return array>> + */ + public static function dataYieldFromTabReplacement() + { + return [ + 'Yield from, single line, single space' => [ + 'testMarker' => '/* testYieldFromHasSingleSpace */', + 'expected' => [ + 'length' => 10, + 'content' => 'yield from', + 'orig_content' => null, + ], + ], + 'Yield from, single line, multiple spaces' => [ + 'testMarker' => '/* testYieldFromHasMultiSpace */', + 'expected' => [ + 'length' => 14, + 'content' => 'yield from', + 'orig_content' => null, + ], + ], + 'Yield from, single line, has tabs' => [ + 'testMarker' => '/* testYieldFromHasTabs */', + 'expected' => [ + 'length' => 16, + 'content' => 'yield from', + 'orig_content' => 'yield from', + ], + ], + 'Yield from, single line, mix of tabs and spaces' => [ + 'testMarker' => '/* testYieldFromMixedTabsSpaces */', + 'expected' => [ + 'length' => 20, + 'content' => 'Yield From', + 'orig_content' => 'Yield From', + ], + ], + ]; + + }//end dataYieldFromTabReplacement() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateTokenMapArrayParenthesesTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateTokenMapArrayParenthesesTest.inc new file mode 100644 index 000000000..6d8adfcba --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateTokenMapArrayParenthesesTest.inc @@ -0,0 +1,58 @@ + 10); + +/* testArrayWithComment */ +$var = Array /*comment*/ (1 => 10); + +/* testNestingArray */ +$var = array( + /* testNestedArray */ + array( + 'key' => 'value', + + /* testClosureReturnType */ + 'closure' => function($a) use($global) : Array {}, + ), +); + +/* testFunctionDeclarationParamType */ +function typedParam(array $a) {} + +/* testFunctionDeclarationReturnType */ +function returnType($a) : int|array|null {} + +class Bar { + /* testClassConst */ + const ARRAY = []; + + /* testClassMethod */ + public function array() {} + + /* testOOConstType */ + const array /* testTypedOOConstName */ ARRAY = /* testOOConstDefault */ array(); + + /* testOOPropertyType */ + protected array $property; +} + +class DNFTypes { + /* testOOConstDNFType */ + const (A&B)|array|(C&D) NAME = []; + + /* testOOPropertyDNFType */ + protected (A&B)|ARRAY|null $property; + + /* testFunctionDeclarationParamDNFType */ + public function name(null|array|(A&B) $param) { + /* testClosureDeclarationParamDNFType */ + $cl = function ( array|(A&B) $param) {}; + + /* testArrowDeclarationReturnDNFType */ + $arrow = fn($a): (A&B)|Array => new $a; + } +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateTokenMapArrayParenthesesTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateTokenMapArrayParenthesesTest.php new file mode 100644 index 000000000..e811211fd --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/CreateTokenMapArrayParenthesesTest.php @@ -0,0 +1,212 @@ + + * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class CreateTokenMapArrayParenthesesTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that the array keyword is correctly tokenized as `T_ARRAY`. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent Optional. The token content to look for. + * + * @dataProvider dataArrayKeyword + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createTokenMap + * + * @return void + */ + public function testArrayKeyword($testMarker, $testContent='array') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_ARRAY, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + // Make sure we're looking at the right token. + $this->assertSame(T_ARRAY, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_ARRAY (code)'); + + $this->assertArrayHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is not set'); + $this->assertArrayHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is not set'); + $this->assertArrayHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is not set'); + + }//end testArrayKeyword() + + + /** + * Data provider. + * + * @see testArrayKeyword() + * + * @return array> + */ + public static function dataArrayKeyword() + { + return [ + 'empty array' => [ + 'testMarker' => '/* testEmptyArray */', + ], + 'array with space before parenthesis' => [ + 'testMarker' => '/* testArrayWithSpace */', + ], + 'array with comment before parenthesis' => [ + 'testMarker' => '/* testArrayWithComment */', + 'testContent' => 'Array', + ], + 'nested: outer array' => [ + 'testMarker' => '/* testNestingArray */', + ], + 'nested: inner array' => [ + 'testMarker' => '/* testNestedArray */', + ], + 'OO constant default value' => [ + 'testMarker' => '/* testOOConstDefault */', + ], + ]; + + }//end dataArrayKeyword() + + + /** + * Test that the array keyword when used in a type declaration is correctly tokenized as `T_STRING`. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent Optional. The token content to look for. + * + * @dataProvider dataArrayType + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createTokenMap + * + * @return void + */ + public function testArrayType($testMarker, $testContent='array') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_ARRAY, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + // Make sure we're looking at the right token. + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + + $this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set'); + $this->assertArrayNotHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is set'); + $this->assertArrayNotHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is set'); + + }//end testArrayType() + + + /** + * Data provider. + * + * @see testArrayType() + * + * @return array> + */ + public static function dataArrayType() + { + return [ + 'closure return type' => [ + 'testMarker' => '/* testClosureReturnType */', + 'testContent' => 'Array', + ], + 'function param type' => [ + 'testMarker' => '/* testFunctionDeclarationParamType */', + ], + 'function union return type' => [ + 'testMarker' => '/* testFunctionDeclarationReturnType */', + ], + 'OO constant type' => [ + 'testMarker' => '/* testOOConstType */', + ], + 'OO property type' => [ + 'testMarker' => '/* testOOPropertyType */', + ], + + 'OO constant DNF type' => [ + 'testMarker' => '/* testOOConstDNFType */', + ], + 'OO property DNF type' => [ + 'testMarker' => '/* testOOPropertyDNFType */', + 'testContent' => 'ARRAY', + ], + 'function param DNF type' => [ + 'testMarker' => '/* testFunctionDeclarationParamDNFType */', + ], + 'closure param DNF type' => [ + 'testMarker' => '/* testClosureDeclarationParamDNFType */', + ], + 'arrow return DNF type' => [ + 'testMarker' => '/* testArrowDeclarationReturnDNFType */', + 'testContent' => 'Array', + ], + ]; + + }//end dataArrayType() + + + /** + * Verify that the retokenization of `T_ARRAY` tokens to `T_STRING` is handled correctly + * for tokens with the contents 'array' which aren't in actual fact the array keyword. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to look for. + * + * @dataProvider dataNotArrayKeyword + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::createTokenMap + * + * @return void + */ + public function testNotArrayKeyword($testMarker, $testContent='array') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_ARRAY, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + // Make sure we're looking at the right token. + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + + $this->assertArrayNotHasKey('parenthesis_owner', $tokenArray, 'Parenthesis owner is set'); + $this->assertArrayNotHasKey('parenthesis_opener', $tokenArray, 'Parenthesis opener is set'); + $this->assertArrayNotHasKey('parenthesis_closer', $tokenArray, 'Parenthesis closer is set'); + + }//end testNotArrayKeyword() + + + /** + * Data provider. + * + * @see testNotArrayKeyword() + * + * @return array> + */ + public static function dataNotArrayKeyword() + { + return [ + 'class-constant-name' => [ + 'testMarker' => '/* testClassConst */', + 'testContent' => 'ARRAY', + ], + 'class-method-name' => [ + 'testMarker' => '/* testClassMethod */', + ], + 'class-constant-name-after-type' => [ + 'testMarker' => '/* testTypedOOConstName */', + 'testContent' => 'ARRAY', + ], + ]; + + }//end dataNotArrayKeyword() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.inc new file mode 100644 index 000000000..5a0debcd0 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.inc @@ -0,0 +1,132 @@ + $num) + return bar( + baz( + "foobarbaz" + ) + ); + break; +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.php new file mode 100644 index 000000000..ca70a34c1 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapCaseKeywordConditionsTest.php @@ -0,0 +1,271 @@ + + * @copyright 2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class RecurseScopeMapCaseKeywordConditionsTest extends AbstractTokenizerTestCase +{ + + + /** + * Test that enum "case" tokens does not get scope indexes. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataEnumCases + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testEnumCases($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $enumCase = $this->getTargetToken($testMarker, [T_ENUM_CASE, T_CASE]); + $tokenArray = $tokens[$enumCase]; + + // Make sure we're looking at the right token. + $this->assertSame(T_ENUM_CASE, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_ENUM_CASE (code)'); + + $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); + $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); + $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); + + }//end testEnumCases() + + + /** + * Data provider. + * + * @see testEnumCases() + * + * @return array> + */ + public static function dataEnumCases() + { + return [ + 'enum case, no value' => ['/* testPureEnumCase */'], + 'enum case, integer value' => ['/* testBackingIntegerEnumCase */'], + 'enum case, string value' => ['/* testBackingStringEnumCase */'], + 'enum case, integer value in more complex enum' => ['/* testEnumCaseInComplexEnum */'], + 'enum case, keyword in mixed case' => ['/* testEnumCaseIsCaseInsensitive */'], + 'enum case, after switch statement' => ['/* testEnumCaseAfterSwitch */'], + 'enum case, after switch statement using alternative syntax' => ['/* testEnumCaseAfterSwitchWithEndSwitch */'], + ]; + + }//end dataEnumCases() + + + /** + * Test that switch "case" tokens do get the scope indexes. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expectedTokens The expected token codes for the scope opener/closer. + * @param string|null $testCloserMarker Optional. The comment which prefaces the scope closer if different + * from the test marker. + * + * @dataProvider dataNotEnumCases + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testNotEnumCases($testMarker, $expectedTokens, $testCloserMarker=null) + { + $tokens = $this->phpcsFile->getTokens(); + $caseIndex = $this->getTargetToken($testMarker, [T_ENUM_CASE, T_CASE]); + $tokenArray = $tokens[$caseIndex]; + + $scopeCloserMarker = $testMarker; + if (isset($testCloserMarker) === true) { + $scopeCloserMarker = $testCloserMarker; + } + + $expectedScopeCondition = $caseIndex; + $expectedScopeOpener = $this->getTargetToken($testMarker, $expectedTokens['scope_opener']); + $expectedScopeCloser = $this->getTargetToken($scopeCloserMarker, $expectedTokens['scope_closer']); + + // Make sure we're looking at the right token. + $this->assertSame(T_CASE, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_CASE (code)'); + + $this->assertArrayHasKey('scope_condition', $tokenArray, 'Scope condition is not set'); + $this->assertSame( + $expectedScopeCondition, + $tokenArray['scope_condition'], + sprintf( + 'Scope condition not set correctly; expected T_CASE, found %s.', + $tokens[$tokenArray['scope_condition']]['type'] + ) + ); + + $this->assertArrayHasKey('scope_opener', $tokenArray, 'Scope opener is not set'); + $this->assertSame( + $expectedScopeOpener, + $tokenArray['scope_opener'], + sprintf( + 'Scope opener not set correctly; expected %s, found %s.', + $tokens[$expectedScopeOpener]['type'], + $tokens[$tokenArray['scope_opener']]['type'] + ) + ); + + $this->assertArrayHasKey('scope_closer', $tokenArray, 'Scope closer is not set'); + $this->assertSame( + $expectedScopeCloser, + $tokenArray['scope_closer'], + sprintf( + 'Scope closer not set correctly; expected %s, found %s.', + $tokens[$expectedScopeCloser]['type'], + $tokens[$tokenArray['scope_closer']]['type'] + ) + ); + + }//end testNotEnumCases() + + + /** + * Data provider. + * + * @see testNotEnumCases() + * + * @return array>> + */ + public static function dataNotEnumCases() + { + return [ + 'switch case with constant, semicolon condition end' => [ + 'testMarker' => '/* testCaseWithSemicolonIsNotEnumCase */', + 'expectedTokens' => [ + 'scope_opener' => T_SEMICOLON, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + ], + 'switch case with constant, colon condition end' => [ + 'testMarker' => '/* testCaseWithConstantIsNotEnumCase */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testCloserMarker' => '/* testCaseConstantCloserMarker */', + ], + 'switch case with constant, comparison' => [ + 'testMarker' => '/* testCaseWithConstantAndIdenticalIsNotEnumCase */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testCloserMarker' => '/* testCaseConstantCloserMarker */', + ], + 'switch case with constant, assignment' => [ + 'testMarker' => '/* testCaseWithAssignmentToConstantIsNotEnumCase */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testCloserMarker' => '/* testCaseConstantCloserMarker */', + ], + 'switch case with constant, keyword in mixed case' => [ + 'testMarker' => '/* testIsNotEnumCaseIsCaseInsensitive */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testCloserMarker' => '/* testCaseConstantCloserMarker */', + ], + 'switch case, body in curlies declares enum' => [ + 'testMarker' => '/* testCaseInSwitchWhenCreatingEnumInSwitch1 */', + 'expectedTokens' => [ + 'scope_opener' => T_OPEN_CURLY_BRACKET, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testCloserMarker' => '/* testCaseInSwitchWhenCreatingEnumInSwitch1CloserMarker */', + ], + 'switch case, body after semicolon declares enum' => [ + 'testMarker' => '/* testCaseInSwitchWhenCreatingEnumInSwitch2 */', + 'expectedTokens' => [ + 'scope_opener' => T_SEMICOLON, + 'scope_closer' => T_BREAK, + ], + 'testCloserMarker' => '/* testCaseInSwitchWhenCreatingEnumInSwitch2CloserMarker */', + ], + 'switch case, shared closer with switch' => [ + 'testMarker' => '/* testSwitchCaseScopeCloserSharedWithSwitch */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_ENDSWITCH, + ], + ], + 'switch case, nested inline if/elseif/else with and without braces' => [ + 'testMarker' => '/* testSwitchCaseNestedIfWithAndWithoutBraces */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_BREAK, + ], + ], + 'switch case, nested inline if' => [ + 'testMarker' => '/* testSwitchCaseNestedInlineIfWithMoreThanThreeLines */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_BREAK, + ], + ], + ]; + + }//end dataNotEnumCases() + + + /** + * Test that a "case" keyword which is not a switch or enum case, does not get the scope indexes. + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * + * @dataProvider dataKeywordAsEnumCaseNameShouldBeString + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testKeywordAsEnumCaseNameShouldBeString($testMarker) + { + $tokens = $this->phpcsFile->getTokens(); + $enumCaseName = $this->getTargetToken($testMarker, [T_STRING, T_INTERFACE, T_TRAIT, T_ENUM, T_FUNCTION, T_FALSE, T_DEFAULT, T_ARRAY]); + $tokenArray = $tokens[$enumCaseName]; + + // Make sure we're looking at the right token. + $this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)'); + + $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); + $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); + $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); + + }//end testKeywordAsEnumCaseNameShouldBeString() + + + /** + * Data provider. + * + * @see testKeywordAsEnumCaseNameShouldBeString() + * + * @return array> + */ + public static function dataKeywordAsEnumCaseNameShouldBeString() + { + return [ + '"interface" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString1 */'], + '"trait" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString2 */'], + '"enum" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString3 */'], + '"function" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString4 */'], + '"false" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString5 */'], + '"default" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString6 */'], + '"array" as case name' => ['/* testKeywordAsEnumCaseNameShouldBeString7 */'], + ]; + + }//end dataKeywordAsEnumCaseNameShouldBeString() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapDefaultKeywordConditionsTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapDefaultKeywordConditionsTest.inc new file mode 100644 index 000000000..c98f518cb --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapDefaultKeywordConditionsTest.inc @@ -0,0 +1,231 @@ + 1, + 2 => 2, + /* testSimpleMatchDefault */ + default => 'default', + }; +} + +function switchWithDefault($i) { + switch ($i) { + case 1: + return 1; + case 2: + return 2; + /* testSimpleSwitchDefault */ + default: + return 'default'; + } +} + +function switchWithDefaultAndCurlies($i) { + switch ($i) { + case 1: + return 1; + case 2: + return 2; + /* testSimpleSwitchDefaultWithCurlies */ + default: /* testSimpleSwitchDefaultWithCurliesScopeOpener */ { + /* testSimpleSwitchDefaultWithCurliesConditionStop */ + return 'default'; + /* testSimpleSwitchDefaultWithCurliesScopeCloser */ + } + } +} + +function matchWithDefaultInSwitch() { + switch ($something) { + case 'foo': + $var = [1, 2, 3]; + $var = match ($i) { + 1 => 1, + /* testMatchDefaultNestedInSwitchCase1 */ + default => 'default', + }; + continue; + + case 'bar' : + $i = callMe($a, $b); + return match ($i) { + 1 => 1, + /* testMatchDefaultNestedInSwitchCase2 */ + default => 'default', + }; + + /* testSwitchDefault */ + default; + echo 'something', match ($i) { + 1, => 1, + /* testMatchDefaultNestedInSwitchDefault */ + default, => 'default', + }; + /* testSwitchDefaultCloserMarker */ + break; + } +} + +function switchWithDefaultInMatch() { + $x = match ($y) { + 5, 8 => function($z) { + switch($z) { + case 'a'; + $var = [1, 2, 3]; + return 'a'; + /* testSwitchDefaultNestedInMatchCase */ + default: + $var = [1, 2, 3]; + return 'default1'; + } + }, + /* testMatchDefault */ + default => function($z) { + switch($z) { + case 'a': + $i = callMe($a, $b); + return 'b'; + /* testSwitchDefaultNestedInMatchDefault */ + default: + $i = callMe($a, $b); + return 'default2'; + } + } + }; +} + +function switchAndDefaultSharingScopeCloser($i) { + switch ($i): + /* testSwitchAndDefaultSharingScopeCloser */ + default: + echo 'one'; + /* testSwitchAndDefaultSharingScopeCloserScopeCloser */ + endswitch; +} + +function switchDefaultNestedIfWithAndWithoutBraces($i, $foo, $baz) { + switch ($i) { + /* testSwitchDefaultNestedIfWithAndWithoutBraces */ + default: + if ($foo) { + return true; + } elseif ($baz) + return true; + else { + echo 'else'; + } + /* testSwitchDefaultNestedIfWithAndWithoutBracesScopeCloser */ + break; + } +} + +function shortArrayWithConstantKey() { + $arr = [ + /* testClassConstantAsShortArrayKey */ + SomeClass::DEFAULT => 1, + /* testClassPropertyAsShortArrayKey */ + SomeClass->DEFAULT => 1, + /* testNamespacedConstantAsShortArrayKey */ + // Intentional parse error PHP < 8.0. Reserved keyword used as namespaced constant. + SomeNamespace\DEFAULT => 1, + /* testFQNGlobalConstantAsShortArrayKey */ + // Intentional parse error in PHP < 8.0. Reserved keyword used as global constant. + \DEFAULT => 1, + ]; +} + +function longArrayWithConstantKey() { + $arr = array( + /* testClassConstantAsLongArrayKey */ + SomeClass::DEFAULT => 1, + ); +} + +function yieldWithConstantKey() { + /* testClassConstantAsYieldKey */ + yield SomeClass::DEFAULT => 1; +} + +function longArrayWithConstantKeyNestedInMatch() { + return match($x) { + /* testMatchDefaultWithNestedLongArrayWithClassConstantKey */ + DEFAULT => array( + /* testClassConstantAsLongArrayKeyNestedInMatch */ + SomeClass::DEFAULT => match($x) { + /* testMatchDefaultWithNestedLongArrayWithClassConstantKeyLevelDown */ + DEFAULT => array( + /* testClassConstantAsLongArrayKeyNestedInMatchLevelDown */ + SomeClass::DEFAULT => 1, + ), + }, + ), + }; +} + +function shortArrayWithConstantKeyNestedInMatch() { + return match($x) { + /* testMatchDefaultWithNestedShortArrayWithClassConstantKey */ + DEFAULT => [ + /* testClassConstantAsShortArrayKeyNestedInMatch */ + SomeClass::DEFAULT => match($x) { + /* testMatchDefaultWithNestedShortArrayWithClassConstantKeyLevelDown */ + DEFAULT => [ + /* testClassConstantAsShortArrayKeyNestedInMatchLevelDown */ + SomeClass::DEFAULT => 1, + ], + }, + ], + }; +} + + +function longArrayWithConstantKeyWithNestedMatch() { + return array( + /* testClassConstantAsLongArrayKeyWithNestedMatch */ + SomeClass::DEFAULT => match($x) { + /* testMatchDefaultNestedInLongArray */ + DEFAULT => 'foo' + }, + ); +} + +function shortArrayWithConstantKeyWithNestedMatch() { + return [ + /* testClassConstantAsShortArrayKeyWithNestedMatch */ + SomeClass::DEFAULT => match($x) { + /* testMatchDefaultNestedInShortArray */ + DEFAULT => 'foo' + }, + ]; +} + +function switchWithConstantNonDefault($i) { + switch ($i) { + /* testClassConstantInSwitchCase */ + case SomeClass::DEFAULT: + return 1; + + /* testClassPropertyInSwitchCase */ + case SomeClass->DEFAULT: + return 2; + + /* testNamespacedConstantInSwitchCase */ + // Intentional parse error PHP < 8.0. Reserved keyword used as constant. + case SomeNamespace\DEFAULT: + return 2; + + /* testNamespaceRelativeConstantInSwitchCase */ + // Intentional parse error PHP < 8.0. Reserved keyword used as global constant. + case namespace\DEFAULT: + return 2; + } +} + +class Foo { + /* testClassConstant */ + const DEFAULT = 'foo'; + + /* testMethodDeclaration */ + public function default() {} +} diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapDefaultKeywordConditionsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapDefaultKeywordConditionsTest.php new file mode 100644 index 000000000..9b40fe109 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapDefaultKeywordConditionsTest.php @@ -0,0 +1,487 @@ + + * @copyright 2020-2021 Squiz Pty Ltd (ABN 77 084 670 600) + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class RecurseScopeMapDefaultKeywordConditionsTest extends AbstractTokenizerTestCase +{ + + /** + * Condition stop tokens when `default` is used with curlies. + * + * @var array + */ + protected $conditionStopTokens = [ + T_BREAK, + T_CONTINUE, + T_EXIT, + T_GOTO, + T_RETURN, + T_THROW, + ]; + + + /** + * Test that match "default" tokens does not get scope indexes. + * + * Note: Cases and default structures within a match structure do *NOT* get case/default scope + * conditions, in contrast to case and default structures in switch control structures. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to look for. + * + * @dataProvider dataMatchDefault + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testMatchDefault($testMarker, $testContent='default') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + // Make sure we're looking at the right token. + $this->assertSame( + T_MATCH_DEFAULT, + $tokenArray['code'], + sprintf('Token tokenized as %s, not T_MATCH_DEFAULT (code). Marker: %s.', $tokenArray['type'], $testMarker) + ); + + $this->assertArrayNotHasKey( + 'scope_condition', + $tokenArray, + sprintf('Scope condition is set. Marker: %s.', $testMarker) + ); + $this->assertArrayNotHasKey( + 'scope_opener', + $tokenArray, + sprintf('Scope opener is set. Marker: %s.', $testMarker) + ); + $this->assertArrayNotHasKey( + 'scope_closer', + $tokenArray, + sprintf('Scope closer is set. Marker: %s.', $testMarker) + ); + + }//end testMatchDefault() + + + /** + * Data provider. + * + * @see testMatchDefault() + * + * @return array> + */ + public static function dataMatchDefault() + { + return [ + 'simple_match_default' => [ + 'testMarker' => '/* testSimpleMatchDefault */', + ], + 'match_default_in_switch_case_1' => [ + 'testMarker' => '/* testMatchDefaultNestedInSwitchCase1 */', + ], + 'match_default_in_switch_case_2' => [ + 'testMarker' => '/* testMatchDefaultNestedInSwitchCase2 */', + ], + 'match_default_in_switch_default' => [ + 'testMarker' => '/* testMatchDefaultNestedInSwitchDefault */', + ], + 'match_default_containing_switch' => [ + 'testMarker' => '/* testMatchDefault */', + ], + + 'match_default_with_nested_long_array_and_default_key' => [ + 'testMarker' => '/* testMatchDefaultWithNestedLongArrayWithClassConstantKey */', + 'testContent' => 'DEFAULT', + ], + 'match_default_with_nested_long_array_and_default_key_2' => [ + 'testMarker' => '/* testMatchDefaultWithNestedLongArrayWithClassConstantKeyLevelDown */', + 'testContent' => 'DEFAULT', + ], + 'match_default_with_nested_short_array_and_default_key' => [ + 'testMarker' => '/* testMatchDefaultWithNestedShortArrayWithClassConstantKey */', + 'testContent' => 'DEFAULT', + ], + 'match_default_with_nested_short_array_and_default_key_2' => [ + 'testMarker' => '/* testMatchDefaultWithNestedShortArrayWithClassConstantKeyLevelDown */', + 'testContent' => 'DEFAULT', + ], + 'match_default_in_long_array' => [ + 'testMarker' => '/* testMatchDefaultNestedInLongArray */', + 'testContent' => 'DEFAULT', + ], + 'match_default_in_short_array' => [ + 'testMarker' => '/* testMatchDefaultNestedInShortArray */', + 'testContent' => 'DEFAULT', + ], + ]; + + }//end dataMatchDefault() + + + /** + * Test that switch "default" tokens do get the scope indexes. + * + * Note: Cases and default structures within a switch control structure *do* get case/default scope + * conditions. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $openerMarker The comment prefacing the scope opener token. + * @param string $closerMarker The comment prefacing the scope closer token. + * @param string|null $conditionStopMarker The expected offset in relation to the testMarker, after which tokens stop + * having T_DEFAULT as a scope condition. + * @param string $testContent The token content to look for. + * @param bool $sharedScopeCloser Whether to skip checking for the `scope_condition` of the + * scope closer. Needed when the default and switch + * structures share a scope closer. See + * https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/810. + * + * @dataProvider dataSwitchDefault + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testSwitchDefault($testMarker, $openerMarker, $closerMarker, $conditionStopMarker=null, $testContent='default', $sharedScopeCloser=false) + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + $expectedScopeOpener = $this->getTargetToken($openerMarker, [T_COLON, T_OPEN_CURLY_BRACKET, T_SEMICOLON]); + $expectedScopeCloser = $this->getTargetToken($closerMarker, [T_BREAK, T_CLOSE_CURLY_BRACKET, T_RETURN, T_ENDSWITCH]); + + // Make sure we're looking at the right token. + $this->assertSame( + T_DEFAULT, + $tokenArray['code'], + sprintf('Token tokenized as %s, not T_DEFAULT (code). Marker: %s.', $tokenArray['type'], $testMarker) + ); + + $this->assertArrayHasKey( + 'scope_condition', + $tokenArray, + sprintf('Scope condition is not set. Marker: %s.', $testMarker) + ); + $this->assertArrayHasKey( + 'scope_opener', + $tokenArray, + sprintf('Scope opener is not set. Marker: %s.', $testMarker) + ); + $this->assertArrayHasKey( + 'scope_closer', + $tokenArray, + sprintf('Scope closer is not set. Marker: %s.', $testMarker) + ); + $this->assertSame( + $token, + $tokenArray['scope_condition'], + sprintf('Scope condition is not the T_DEFAULT token. Marker: %s.', $testMarker) + ); + $this->assertSame( + $expectedScopeOpener, + $tokenArray['scope_opener'], + sprintf('Scope opener of the T_DEFAULT token incorrect. Marker: %s.', $testMarker) + ); + $this->assertSame( + $expectedScopeCloser, + $tokenArray['scope_closer'], + sprintf('Scope closer of the T_DEFAULT token incorrect. Marker: %s.', $testMarker) + ); + + $opener = $tokenArray['scope_opener']; + $this->assertArrayHasKey( + 'scope_condition', + $tokens[$opener], + sprintf('Opener scope condition is not set. Marker: %s.', $openerMarker) + ); + $this->assertArrayHasKey( + 'scope_opener', + $tokens[$opener], + sprintf('Opener scope opener is not set. Marker: %s.', $openerMarker) + ); + $this->assertArrayHasKey( + 'scope_closer', + $tokens[$opener], + sprintf('Opener scope closer is not set. Marker: %s.', $openerMarker) + ); + $this->assertSame( + $token, + $tokens[$opener]['scope_condition'], + sprintf('Opener scope condition is not the T_DEFAULT token. Marker: %s.', $openerMarker) + ); + $this->assertSame( + $expectedScopeOpener, + $tokens[$opener]['scope_opener'], + sprintf('T_DEFAULT opener scope opener token incorrect. Marker: %s.', $openerMarker) + ); + $this->assertSame( + $expectedScopeCloser, + $tokens[$opener]['scope_closer'], + sprintf('T_DEFAULT opener scope closer token incorrect. Marker: %s.', $openerMarker) + ); + + $closer = $expectedScopeCloser; + + if ($sharedScopeCloser === false) { + $closer = $tokenArray['scope_closer']; + $this->assertArrayHasKey( + 'scope_condition', + $tokens[$closer], + sprintf('Closer scope condition is not set. Marker: %s.', $closerMarker) + ); + $this->assertArrayHasKey( + 'scope_opener', + $tokens[$closer], + sprintf('Closer scope opener is not set. Marker: %s.', $closerMarker) + ); + $this->assertArrayHasKey( + 'scope_closer', + $tokens[$closer], + sprintf('Closer scope closer is not set. Marker: %s.', $closerMarker) + ); + $this->assertSame( + $token, + $tokens[$closer]['scope_condition'], + sprintf('Closer scope condition is not the T_DEFAULT token. Marker: %s.', $closerMarker) + ); + $this->assertSame( + $expectedScopeOpener, + $tokens[$closer]['scope_opener'], + sprintf('T_DEFAULT closer scope opener token incorrect. Marker: %s.', $closerMarker) + ); + $this->assertSame( + $expectedScopeCloser, + $tokens[$closer]['scope_closer'], + sprintf('T_DEFAULT closer scope closer token incorrect. Marker: %s.', $closerMarker) + ); + }//end if + + if (($opener + 1) !== $closer) { + $end = $closer; + if (isset($conditionStopMarker) === true) { + $end = ( $this->getTargetToken($conditionStopMarker, $this->conditionStopTokens) + 1); + } + + for ($i = ($opener + 1); $i < $end; $i++) { + $this->assertArrayHasKey( + $token, + $tokens[$i]['conditions'], + sprintf('T_DEFAULT condition not added for token belonging to the T_DEFAULT structure. Marker: %s.', $testMarker) + ); + } + }//end if + + }//end testSwitchDefault() + + + /** + * Data provider. + * + * @see testSwitchDefault() + * + * @return array> + */ + public static function dataSwitchDefault() + { + return [ + 'simple_switch_default' => [ + 'testMarker' => '/* testSimpleSwitchDefault */', + 'openerMarker' => '/* testSimpleSwitchDefault */', + 'closerMarker' => '/* testSimpleSwitchDefault */', + ], + 'simple_switch_default_with_curlies' => [ + // For a default structure with curly braces, the scope opener + // will be the open curly and the closer the close curly. + // However, scope conditions will not be set for open to close, + // but only for the open token up to the "break/return/continue" etc. + 'testMarker' => '/* testSimpleSwitchDefaultWithCurlies */', + 'openerMarker' => '/* testSimpleSwitchDefaultWithCurliesScopeOpener */', + 'closerMarker' => '/* testSimpleSwitchDefaultWithCurliesScopeCloser */', + 'conditionStopMarker' => '/* testSimpleSwitchDefaultWithCurliesConditionStop */', + ], + 'switch_default_toplevel' => [ + 'testMarker' => '/* testSwitchDefault */', + 'openerMarker' => '/* testSwitchDefault */', + 'closerMarker' => '/* testSwitchDefaultCloserMarker */', + ], + 'switch_default_nested_in_match_case' => [ + 'testMarker' => '/* testSwitchDefaultNestedInMatchCase */', + 'openerMarker' => '/* testSwitchDefaultNestedInMatchCase */', + 'closerMarker' => '/* testSwitchDefaultNestedInMatchCase */', + ], + 'switch_default_nested_in_match_default' => [ + 'testMarker' => '/* testSwitchDefaultNestedInMatchDefault */', + 'openerMarker' => '/* testSwitchDefaultNestedInMatchDefault */', + 'closerMarker' => '/* testSwitchDefaultNestedInMatchDefault */', + ], + 'switch_and_default_sharing_scope_closer' => [ + 'testMarker' => '/* testSwitchAndDefaultSharingScopeCloser */', + 'openerMarker' => '/* testSwitchAndDefaultSharingScopeCloser */', + 'closerMarker' => '/* testSwitchAndDefaultSharingScopeCloserScopeCloser */', + 'conditionStopMarker' => null, + 'testContent' => 'default', + 'sharedScopeCloser' => true, + ], + 'switch_and_default_with_nested_if_with_and_without_braces' => [ + 'testMarker' => '/* testSwitchDefaultNestedIfWithAndWithoutBraces */', + 'openerMarker' => '/* testSwitchDefaultNestedIfWithAndWithoutBraces */', + 'closerMarker' => '/* testSwitchDefaultNestedIfWithAndWithoutBracesScopeCloser */', + ], + ]; + + }//end dataSwitchDefault() + + + /** + * Test that a "default" keyword which is not a switch or match default, does not get the scope indexes. + * + * @param string $testMarker The comment prefacing the target token. + * @param string $testContent The token content to look for. + * + * @dataProvider dataNotDefaultKeyword + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testNotDefaultKeyword($testMarker, $testContent='DEFAULT') + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken($testMarker, [T_MATCH_DEFAULT, T_DEFAULT, T_STRING], $testContent); + $tokenArray = $tokens[$token]; + + // Make sure we're looking at the right token. + $this->assertSame( + T_STRING, + $tokenArray['code'], + sprintf('Token tokenized as %s, not T_STRING (code). Marker: %s.', $tokenArray['type'], $testMarker) + ); + + $this->assertArrayNotHasKey( + 'scope_condition', + $tokenArray, + sprintf('Scope condition is set. Marker: %s.', $testMarker) + ); + $this->assertArrayNotHasKey( + 'scope_opener', + $tokenArray, + sprintf('Scope opener is set. Marker: %s.', $testMarker) + ); + $this->assertArrayNotHasKey( + 'scope_closer', + $tokenArray, + sprintf('Scope closer is set. Marker: %s.', $testMarker) + ); + + }//end testNotDefaultKeyword() + + + /** + * Data provider. + * + * @see testNotDefaultKeyword() + * + * @return array> + */ + public static function dataNotDefaultKeyword() + { + return [ + 'class-constant-as-short-array-key' => [ + 'testMarker' => '/* testClassConstantAsShortArrayKey */', + ], + 'class-property-as-short-array-key' => [ + 'testMarker' => '/* testClassPropertyAsShortArrayKey */', + ], + 'namespaced-constant-as-short-array-key' => [ + 'testMarker' => '/* testNamespacedConstantAsShortArrayKey */', + ], + 'fqn-global-constant-as-short-array-key' => [ + 'testMarker' => '/* testFQNGlobalConstantAsShortArrayKey */', + ], + 'class-constant-as-long-array-key' => [ + 'testMarker' => '/* testClassConstantAsLongArrayKey */', + ], + 'class-constant-as-yield-key' => [ + 'testMarker' => '/* testClassConstantAsYieldKey */', + ], + + 'class-constant-as-long-array-key-nested-in-match' => [ + 'testMarker' => '/* testClassConstantAsLongArrayKeyNestedInMatch */', + ], + 'class-constant-as-long-array-key-nested-in-match-2' => [ + 'testMarker' => '/* testClassConstantAsLongArrayKeyNestedInMatchLevelDown */', + ], + 'class-constant-as-short-array-key-nested-in-match' => [ + 'testMarker' => '/* testClassConstantAsShortArrayKeyNestedInMatch */', + ], + 'class-constant-as-short-array-key-nested-in-match-2' => [ + 'testMarker' => '/* testClassConstantAsShortArrayKeyNestedInMatchLevelDown */', + ], + 'class-constant-as-long-array-key-with-nested-match' => [ + 'testMarker' => '/* testClassConstantAsLongArrayKeyWithNestedMatch */', + ], + 'class-constant-as-short-array-key-with-nested-match' => [ + 'testMarker' => '/* testClassConstantAsShortArrayKeyWithNestedMatch */', + ], + + 'class-constant-in-switch-case' => [ + 'testMarker' => '/* testClassConstantInSwitchCase */', + ], + 'class-property-in-switch-case' => [ + 'testMarker' => '/* testClassPropertyInSwitchCase */', + ], + 'namespaced-constant-in-switch-case' => [ + 'testMarker' => '/* testNamespacedConstantInSwitchCase */', + ], + 'namespace-relative-constant-in-switch-case' => [ + 'testMarker' => '/* testNamespaceRelativeConstantInSwitchCase */', + ], + + 'class-constant-declaration' => [ + 'testMarker' => '/* testClassConstant */', + ], + 'class-method-declaration' => [ + 'testMarker' => '/* testMethodDeclaration */', + 'testContent' => 'default', + ], + ]; + + }//end dataNotDefaultKeyword() + + + /** + * Test a specific edge case where a scope opener would be incorrectly set. + * + * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/3326 + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testIssue3326() + { + $tokens = $this->phpcsFile->getTokens(); + + $token = $this->getTargetToken('/* testClassConstant */', [T_SEMICOLON]); + $tokenArray = $tokens[$token]; + + $this->assertArrayNotHasKey('scope_condition', $tokenArray, 'Scope condition is set'); + $this->assertArrayNotHasKey('scope_opener', $tokenArray, 'Scope opener is set'); + $this->assertArrayNotHasKey('scope_closer', $tokenArray, 'Scope closer is set'); + + }//end testIssue3326() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapIfKeywordConditionsTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapIfKeywordConditionsTest.inc new file mode 100644 index 000000000..e303c3850 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapIfKeywordConditionsTest.inc @@ -0,0 +1,13 @@ + + * @author Rodrigo Primo + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class RecurseScopeMapIfKeywordConditionsTest extends AbstractTokenizerTestCase +{ + + + /** + * Tests setting the scope for T_IF token with nested case statement missing break statement. + * + * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/497#ref-commit-fddc61a + * + * @covers \PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testIfElseWithNestedCaseMissingBreakSharedClosers() + { + + $tokens = $this->phpcsFile->getTokens(); + $ifTestMarker = '/* testIfElseWithNestedCaseMissingBreak */'; + $ifCloserTestMarker = '/* testIfElseWithNestedCaseMissingBreakCloser */'; + $ifTokenIndex = $this->getTargetToken($ifTestMarker, T_IF); + $tokenArray = $tokens[$ifTokenIndex]; + + $expectedScopeCondition = $ifTokenIndex; + $expectedScopeOpener = $this->getTargetToken($ifTestMarker, T_COLON); + $expectedScopeCloser = $this->getTargetToken($ifCloserTestMarker, T_ELSE); + + $this->assertArrayHasKey('scope_condition', $tokenArray, 'Scope condition not set'); + $this->assertSame( + $expectedScopeCondition, + $tokenArray['scope_condition'], + sprintf( + 'Scope condition not set correctly; expected T_IF, found %s', + $tokens[$tokenArray['scope_condition']]['type'] + ) + ); + + $this->assertArrayHasKey('scope_opener', $tokenArray, 'Scope opener not set'); + $this->assertSame( + $expectedScopeOpener, + $tokenArray['scope_opener'], + sprintf( + 'Scope opener not set correctly; expected %s, found %s', + $tokens[$expectedScopeOpener]['type'], + $tokens[$tokenArray['scope_opener']]['type'] + ) + ); + + $this->assertArrayHasKey('scope_closer', $tokenArray, 'Scope closer not set'); + $this->assertSame( + $expectedScopeCloser, + $tokenArray['scope_closer'], + sprintf( + 'Scope closer not set correctly; expected %s, found %s', + $tokens[$expectedScopeCloser]['type'], + $tokens[$tokenArray['scope_closer']]['type'] + ) + ); + + }//end testIfElseWithNestedCaseMissingBreakSharedClosers() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.inc new file mode 100644 index 000000000..6df910bed --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.inc @@ -0,0 +1,60 @@ + $obj->{$foo . $bar})()) /* testSwitchArrowFunctionWithinConditionScopeOpener */ { + case 1: + return 'test'; +/* testSwitchArrowFunctionWithinConditionScopeCloser */ +} + +/* testSwitchArrowFunctionWithReturnTypeWithinCondition */ +switch((fn(): string => $condition ? 'foo' : 'bar')()) /* testSwitchArrowFunctionWithReturnTypeWithinConditionScopeOpener */ : + /* testSwitchArrowFunctionWithReturnTypeWithinConditionEnsureTestWillNotPickUpWrongColon */ + case 1: + return 'test'; +/* testSwitchArrowFunctionWithReturnTypeWithinConditionScopeCloser */ +endswitch; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.php new file mode 100644 index 000000000..dd6634ace --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapSwitchTokenScopeTest.php @@ -0,0 +1,160 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class RecurseScopeMapSwitchTokenScopeTest extends AbstractTokenizerTestCase +{ + + + /** + * Tests setting the scope for T_SWITCH token (normal and alternative syntax). + * + * @param string $testMarker The comment which prefaces the target token in the test file. + * @param array $expectedTokens The expected token codes for the scope opener/closer. + * @param string|null $testOpenerMarker Optional. The comment which prefaces the scope opener if different + * from the test marker. + * @param string|null $testCloserMarker Optional. The comment which prefaces the scope closer if different + * from the test marker. + * + * @link https://github.com/squizlabs/PHP_CodeSniffer/issues/497#ref-commit-b24b96b + * + * @dataProvider dataSwitchScope + * @covers \PHP_CodeSniffer\Tokenizers\Tokenizer::recurseScopeMap + * + * @return void + */ + public function testSwitchScope($testMarker, $expectedTokens, $testOpenerMarker=null, $testCloserMarker=null) + { + $tokens = $this->phpcsFile->getTokens(); + $switchIndex = $this->getTargetToken($testMarker, [T_SWITCH]); + $tokenArray = $tokens[$switchIndex]; + + $scopeOpenerMarker = $testMarker; + if (isset($testOpenerMarker) === true) { + $scopeOpenerMarker = $testOpenerMarker; + } + + $scopeCloserMarker = $testMarker; + if (isset($testCloserMarker) === true) { + $scopeCloserMarker = $testCloserMarker; + } + + $expectedScopeCondition = $switchIndex; + $expectedScopeOpener = $this->getTargetToken($scopeOpenerMarker, $expectedTokens['scope_opener']); + $expectedScopeCloser = $this->getTargetToken($scopeCloserMarker, $expectedTokens['scope_closer']); + + $this->assertArrayHasKey('scope_condition', $tokenArray, 'Scope condition not set'); + $this->assertSame( + $expectedScopeCondition, + $tokenArray['scope_condition'], + sprintf( + 'Scope condition not set correctly; expected T_SWITCH, found %s', + $tokens[$tokenArray['scope_condition']]['type'] + ) + ); + + $this->assertArrayHasKey('scope_opener', $tokenArray, 'Scope opener not set'); + $this->assertSame( + $expectedScopeOpener, + $tokenArray['scope_opener'], + sprintf( + 'Scope opener not set correctly; expected %s, found %s', + $tokens[$expectedScopeOpener]['type'], + $tokens[$tokenArray['scope_opener']]['type'] + ) + ); + + $this->assertArrayHasKey('scope_closer', $tokenArray, 'Scope closer not set'); + $this->assertSame( + $expectedScopeCloser, + $tokenArray['scope_closer'], + sprintf( + 'Scope closer not set correctly; expected %s, found %s', + $tokens[$expectedScopeCloser]['type'], + $tokens[$tokenArray['scope_closer']]['type'] + ) + ); + + }//end testSwitchScope() + + + /** + * Data provider. + * + * @see testSwitchScope() + * + * @return array|null>> + */ + public static function dataSwitchScope() + { + return [ + 'switch normal syntax' => [ + 'testMarker' => '/* testSwitchNormalSyntax */', + 'expectedTokens' => [ + 'scope_opener' => T_OPEN_CURLY_BRACKET, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testOpenerMarker' => null, + 'testCloserMarker' => '/* testSwitchNormalSyntaxScopeCloser */', + ], + 'switch alternative syntax' => [ + 'testMarker' => '/* testSwitchAlternativeSyntax */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_ENDSWITCH, + ], + 'testOpenerMarker' => null, + 'testCloserMarker' => '/* testSwitchAlternativeSyntaxScopeCloser */', + ], + 'switch with closure in the condition' => [ + 'testMarker' => '/* testSwitchClosureWithinCondition */', + 'expectedTokens' => [ + 'scope_opener' => T_OPEN_CURLY_BRACKET, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testOpenerMarker' => '/* testSwitchClosureWithinConditionScopeOpener */', + 'testCloserMarker' => '/* testSwitchClosureWithinConditionScopeCloser */', + ], + 'switch alternative syntax with closure containing return type in the condition' => [ + 'testMarker' => '/* testSwitchClosureWithReturnTypeWithinCondition */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_ENDSWITCH, + ], + 'testOpenerMarker' => '/* testSwitchClosureWithReturnTypeWithinConditionScopeOpener */', + 'testCloserMarker' => '/* testSwitchClosureWithReturnTypeWithinConditionScopeCloser */', + ], + 'switch with arrow function in the condition' => [ + 'testMarker' => '/* testSwitchArrowFunctionWithinCondition */', + 'expectedTokens' => [ + 'scope_opener' => T_OPEN_CURLY_BRACKET, + 'scope_closer' => T_CLOSE_CURLY_BRACKET, + ], + 'testOpenerMarker' => '/* testSwitchArrowFunctionWithinConditionScopeOpener */', + 'testCloserMarker' => '/* testSwitchArrowFunctionWithinConditionScopeCloser */', + ], + 'switch alternative syntax with arrow function containing return type in the condition' => [ + 'testMarker' => '/* testSwitchArrowFunctionWithReturnTypeWithinCondition */', + 'expectedTokens' => [ + 'scope_opener' => T_COLON, + 'scope_closer' => T_ENDSWITCH, + ], + 'testOpenerMarker' => '/* testSwitchArrowFunctionWithReturnTypeWithinConditionScopeOpener */', + 'testCloserMarker' => '/* testSwitchArrowFunctionWithReturnTypeWithinConditionScopeCloser */', + ], + + ]; + + }//end dataSwitchScope() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ScopeSettingWithNamespaceOperatorTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapWithNamespaceOperatorTest.inc similarity index 100% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ScopeSettingWithNamespaceOperatorTest.inc rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapWithNamespaceOperatorTest.inc diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ScopeSettingWithNamespaceOperatorTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapWithNamespaceOperatorTest.php similarity index 93% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ScopeSettingWithNamespaceOperatorTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapWithNamespaceOperatorTest.php index 5359b7282..c6acda727 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizer/ScopeSettingWithNamespaceOperatorTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/RecurseScopeMapWithNamespaceOperatorTest.php @@ -7,9 +7,11 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Tokenizer; +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; -final class ScopeSettingWithNamespaceOperatorTest extends AbstractTokenizerTestCase +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +final class RecurseScopeMapWithNamespaceOperatorTest extends AbstractTokenizerTestCase { @@ -26,7 +28,7 @@ final class ScopeSettingWithNamespaceOperatorTest extends AbstractTokenizerTestC * * @return void */ - public function testScopeSetting($testMarker, $tokenTypes, $open=T_OPEN_CURLY_BRACKET, $close=T_CLOSE_CURLY_BRACKET) + public function testScopeSetting($testMarker, $tokenTypes, $open=[T_OPEN_CURLY_BRACKET], $close=[T_CLOSE_CURLY_BRACKET]) { $tokens = $this->phpcsFile->getTokens(); diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenMiscTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenMiscTest.php new file mode 100644 index 000000000..f4bd711a6 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenMiscTest.php @@ -0,0 +1,124 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use PHP_CodeSniffer\Files\DummyFile; +use PHP_CodeSniffer\Ruleset; +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHPUnit\Framework\TestCase; + +/** + * Miscellaneous tests for tab replacement. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::replaceTabsInToken + */ +final class ReplaceTabsInTokenMiscTest extends TestCase +{ + + + /** + * Test that when no tab width is set or passed, the tab width will be set to 1. + * + * @return void + */ + public function testTabWidthNotSet() + { + $config = new ConfigDouble(); + $ruleset = new Ruleset($config); + + $content = <<parse(); + + $tokens = $phpcsFile->getTokens(); + $target = $phpcsFile->findNext(T_WHITESPACE, 0); + + // Verify initial state. + $this->assertTrue(is_int($target), 'Target token was not found'); + $this->assertSame(' ', $tokens[$target]['content'], 'Content after initial parsing does not contain tabs'); + $this->assertSame(2, $tokens[$target]['length'], 'Length after initial parsing is not as expected'); + $this->assertArrayNotHasKey('orig_content', $tokens[$target], "Key 'orig_content' found in the initial token array."); + + $phpcsFile->tokenizer->replaceTabsInToken($tokens[$target]); + + // Verify tab replacement. + $this->assertSame(' ', $tokens[$target]['content'], 'Content after tab replacement is not as expected'); + $this->assertSame(2, $tokens[$target]['length'], 'Length after tab replacement is not as expected'); + $this->assertArrayHasKey('orig_content', $tokens[$target], "Key 'orig_content' not found in the token array."); + + }//end testTabWidthNotSet() + + + /** + * Test that the length calculation handles text in non-ascii encodings correctly. + * + * @requires extension iconv + * + * @return void + */ + public function testLengthSettingRespectsEncoding() + { + $config = new ConfigDouble(); + $config->tabWidth = 4; + $ruleset = new Ruleset($config); + + $content = <<parse(); + + $tokens = $phpcsFile->getTokens(); + $target = $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING, 0); + + $this->assertTrue(is_int($target), 'Target token was not found'); + $this->assertSame("'пасха пасха'", $tokens[$target]['content'], 'Content is not as expected'); + $this->assertSame(17, $tokens[$target]['length'], 'Length is not as expected'); + $this->assertArrayHasKey('orig_content', $tokens[$target], "Key 'orig_content' not found in the token array."); + $this->assertSame("'пасха пасха'", $tokens[$target]['orig_content'], 'Orig_content is not as expected'); + + }//end testLengthSettingRespectsEncoding() + + + /** + * Test that the length calculation falls back to byte length if iconv detects an illegal character. + * + * @requires extension iconv + * + * @return void + */ + public function testLengthSettingFallsBackToBytesWhenTextContainsIllegalChars() + { + $config = new ConfigDouble(); + $config->tabWidth = 4; + $ruleset = new Ruleset($config); + + $content = <<parse(); + + $tokens = $phpcsFile->getTokens(); + $target = $phpcsFile->findNext(T_CONSTANT_ENCAPSED_STRING, 0); + + $this->assertTrue(is_int($target), 'Target token was not found'); + $this->assertSame(11, $tokens[$target]['length'], 'Length is not as expected'); + $this->assertArrayHasKey('orig_content', $tokens[$target], "Key 'orig_content' not found in the token array."); + + }//end testLengthSettingFallsBackToBytesWhenTextContainsIllegalChars() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth1Test.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth1Test.php new file mode 100644 index 000000000..296215345 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth1Test.php @@ -0,0 +1,111 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +/** + * Tab replacement test using tab width 1. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::replaceTabsInToken + */ +final class ReplaceTabsInTokenTabWidth1Test extends ReplaceTabsInTokenTestCase +{ + + /** + * The tab width setting to use when tokenizing the file. + * + * @var integer + */ + protected $tabWidth = 1; + + + /** + * Data provider helper. + * + * @see ReplaceTabsInTokenTestCase::dataTabReplacement() + * + * @return array> + */ + public static function getTabReplacementExpected() + { + return [ + 'Tab indentation' => [ + 'length' => 2, + 'content' => ' ', + 'orig_content' => ' ', + ], + 'Mixed tab/space indentation' => [ + 'length' => 3, + 'content' => ' ', + 'orig_content' => ' ', + ], + 'Inline: single tab in text string' => [ + 'length' => 15, + 'content' => "'tab separated'", + 'orig_content' => "'tab separated'", + ], + 'Inline: single tab between each word in text string' => [ + 'length' => 24, + 'content' => '"tab $between each word"', + 'orig_content' => '"tab $between each word"', + ], + 'Inline: multiple tabs in heredoc' => [ + 'length' => 15, + 'content' => 'tab separated +', + 'orig_content' => 'tab separated +', + ], + 'Inline: multiple tabs between each word in nowdoc' => [ + 'length' => 27, + 'content' => 'tab between each word +', + 'orig_content' => 'tab between each word +', + ], + 'Inline: mixed spaces/tabs in text string' => [ + 'length' => 20, + 'content' => "'tab separated'", + 'orig_content' => "'tab separated'", + ], + 'Inline: mixed spaces/tabs between each word in text string' => [ + 'length' => 31, + 'content' => '"tab $between each word"', + 'orig_content' => '"tab $between each word"', + ], + 'Inline: tab becomes single space in comment (with tabwidth 4)' => [ + 'length' => 50, + 'content' => '// -123 With tabwidth 4, the tab size should be 1. +', + 'orig_content' => '// -123 With tabwidth 4, the tab size should be 1. +', + ], + 'Inline: tab becomes 2 spaces in comment (with tabwidth 4)' => [ + 'length' => 52, + 'content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + 'orig_content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + ], + 'Inline: tab becomes 3 spaces in doc comment string (with tabwidth 4)' => [ + 'length' => 45, + 'content' => '-1 With tabwidth 4, the tab size should be 3.', + 'orig_content' => '-1 With tabwidth 4, the tab size should be 3.', + ], + 'Inline: tab becomes 4 spaces in comment (with tabwidth 4)' => [ + 'length' => 47, + 'content' => '// - With tabwidth 4, the tab size should be 4. +', + 'orig_content' => '// - With tabwidth 4, the tab size should be 4. +', + ], + ]; + + }//end getTabReplacementExpected() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth2Test.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth2Test.php new file mode 100644 index 000000000..92de221d8 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth2Test.php @@ -0,0 +1,111 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +/** + * Tab replacement test using tab width 2. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::replaceTabsInToken + */ +final class ReplaceTabsInTokenTabWidth2Test extends ReplaceTabsInTokenTestCase +{ + + /** + * The tab width setting to use when tokenizing the file. + * + * @var integer + */ + protected $tabWidth = 2; + + + /** + * Data provider helper. + * + * @see ReplaceTabsInTokenTestCase::dataTabReplacement() + * + * @return array> + */ + public static function getTabReplacementExpected() + { + return [ + 'Tab indentation' => [ + 'length' => 4, + 'content' => ' ', + 'orig_content' => ' ', + ], + 'Mixed tab/space indentation' => [ + 'length' => 4, + 'content' => ' ', + 'orig_content' => ' ', + ], + 'Inline: single tab in text string' => [ + 'length' => 15, + 'content' => "'tab separated'", + 'orig_content' => "'tab separated'", + ], + 'Inline: single tab between each word in text string' => [ + 'length' => 26, + 'content' => '"tab $between each word"', + 'orig_content' => '"tab $between each word"', + ], + 'Inline: multiple tabs in heredoc' => [ + 'length' => 17, + 'content' => 'tab separated +', + 'orig_content' => 'tab separated +', + ], + 'Inline: multiple tabs between each word in nowdoc' => [ + 'length' => 34, + 'content' => 'tab between each word +', + 'orig_content' => 'tab between each word +', + ], + 'Inline: mixed spaces/tabs in text string' => [ + 'length' => 23, + 'content' => "'tab separated'", + 'orig_content' => "'tab separated'", + ], + 'Inline: mixed spaces/tabs between each word in text string' => [ + 'length' => 32, + 'content' => '"tab $between each word"', + 'orig_content' => '"tab $between each word"', + ], + 'Inline: tab becomes single space in comment (with tabwidth 4)' => [ + 'length' => 50, + 'content' => '// -123 With tabwidth 4, the tab size should be 1. +', + 'orig_content' => '// -123 With tabwidth 4, the tab size should be 1. +', + ], + 'Inline: tab becomes 2 spaces in comment (with tabwidth 4)' => [ + 'length' => 53, + 'content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + 'orig_content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + ], + 'Inline: tab becomes 3 spaces in doc comment string (with tabwidth 4)' => [ + 'length' => 45, + 'content' => '-1 With tabwidth 4, the tab size should be 3.', + 'orig_content' => '-1 With tabwidth 4, the tab size should be 3.', + ], + 'Inline: tab becomes 4 spaces in comment (with tabwidth 4)' => [ + 'length' => 48, + 'content' => '// - With tabwidth 4, the tab size should be 4. +', + 'orig_content' => '// - With tabwidth 4, the tab size should be 4. +', + ], + ]; + + }//end getTabReplacementExpected() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth4Test.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth4Test.php new file mode 100644 index 000000000..5f7418798 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth4Test.php @@ -0,0 +1,111 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +/** + * Tab replacement test using tab width 4. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::replaceTabsInToken + */ +final class ReplaceTabsInTokenTabWidth4Test extends ReplaceTabsInTokenTestCase +{ + + /** + * The tab width setting to use when tokenizing the file. + * + * @var integer + */ + protected $tabWidth = 4; + + + /** + * Data provider helper. + * + * @see ReplaceTabsInTokenTestCase::dataTabReplacement() + * + * @return array> + */ + public static function getTabReplacementExpected() + { + return [ + 'Tab indentation' => [ + 'length' => 8, + 'content' => ' ', + 'orig_content' => ' ', + ], + 'Mixed tab/space indentation' => [ + 'length' => 6, + 'content' => ' ', + 'orig_content' => ' ', + ], + 'Inline: single tab in text string' => [ + 'length' => 17, + 'content' => "'tab separated'", + 'orig_content' => "'tab separated'", + ], + 'Inline: single tab between each word in text string' => [ + 'length' => 32, + 'content' => '"tab $between each word"', + 'orig_content' => '"tab $between each word"', + ], + 'Inline: multiple tabs in heredoc' => [ + 'length' => 21, + 'content' => 'tab separated +', + 'orig_content' => 'tab separated +', + ], + 'Inline: multiple tabs between each word in nowdoc' => [ + 'length' => 48, + 'content' => 'tab between each word +', + 'orig_content' => 'tab between each word +', + ], + 'Inline: mixed spaces/tabs in text string' => [ + 'length' => 25, + 'content' => "'tab separated'", + 'orig_content' => "'tab separated'", + ], + 'Inline: mixed spaces/tabs between each word in text string' => [ + 'length' => 36, + 'content' => '"tab $between each word"', + 'orig_content' => '"tab $between each word"', + ], + 'Inline: tab becomes single space in comment (with tabwidth 4)' => [ + 'length' => 50, + 'content' => '// -123 With tabwidth 4, the tab size should be 1. +', + 'orig_content' => '// -123 With tabwidth 4, the tab size should be 1. +', + ], + 'Inline: tab becomes 2 spaces in comment (with tabwidth 4)' => [ + 'length' => 53, + 'content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + 'orig_content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + ], + 'Inline: tab becomes 3 spaces in doc comment string (with tabwidth 4)' => [ + 'length' => 47, + 'content' => '-1 With tabwidth 4, the tab size should be 3.', + 'orig_content' => '-1 With tabwidth 4, the tab size should be 3.', + ], + 'Inline: tab becomes 4 spaces in comment (with tabwidth 4)' => [ + 'length' => 50, + 'content' => '// - With tabwidth 4, the tab size should be 4. +', + 'orig_content' => '// - With tabwidth 4, the tab size should be 4. +', + ], + ]; + + }//end getTabReplacementExpected() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth5Test.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth5Test.php new file mode 100644 index 000000000..361894fb9 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTabWidth5Test.php @@ -0,0 +1,111 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +/** + * Tab replacement test using tab width 5. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::replaceTabsInToken + */ +final class ReplaceTabsInTokenTabWidth5Test extends ReplaceTabsInTokenTestCase +{ + + /** + * The tab width setting to use when tokenizing the file. + * + * @var integer + */ + protected $tabWidth = 5; + + + /** + * Data provider helper. + * + * @see ReplaceTabsInTokenTestCase::dataTabReplacement() + * + * @return array> + */ + public static function getTabReplacementExpected() + { + return [ + 'Tab indentation' => [ + 'length' => 10, + 'content' => ' ', + 'orig_content' => ' ', + ], + 'Mixed tab/space indentation' => [ + 'length' => 7, + 'content' => ' ', + 'orig_content' => ' ', + ], + 'Inline: single tab in text string' => [ + 'length' => 15, + 'content' => "'tab separated'", + 'orig_content' => "'tab separated'", + ], + 'Inline: single tab between each word in text string' => [ + 'length' => 25, + 'content' => '"tab $between each word"', + 'orig_content' => '"tab $between each word"', + ], + 'Inline: multiple tabs in heredoc' => [ + 'length' => 24, + 'content' => 'tab separated +', + 'orig_content' => 'tab separated +', + ], + 'Inline: multiple tabs between each word in nowdoc' => [ + 'length' => 54, + 'content' => 'tab between each word +', + 'orig_content' => 'tab between each word +', + ], + 'Inline: mixed spaces/tabs in text string' => [ + 'length' => 30, + 'content' => "'tab separated'", + 'orig_content' => "'tab separated'", + ], + 'Inline: mixed spaces/tabs between each word in text string' => [ + 'length' => 35, + 'content' => '"tab $between each word"', + 'orig_content' => '"tab $between each word"', + ], + 'Inline: tab becomes single space in comment (with tabwidth 4)' => [ + 'length' => 52, + 'content' => '// -123 With tabwidth 4, the tab size should be 1. +', + 'orig_content' => '// -123 With tabwidth 4, the tab size should be 1. +', + ], + 'Inline: tab becomes 2 spaces in comment (with tabwidth 4)' => [ + 'length' => 55, + 'content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + 'orig_content' => '/* -12 With tabwidth 4, the tab size should be 2. */', + ], + 'Inline: tab becomes 3 spaces in doc comment string (with tabwidth 4)' => [ + 'length' => 49, + 'content' => '-1 With tabwidth 4, the tab size should be 3.', + 'orig_content' => '-1 With tabwidth 4, the tab size should be 3.', + ], + 'Inline: tab becomes 4 spaces in comment (with tabwidth 4)' => [ + 'length' => 47, + 'content' => '// - With tabwidth 4, the tab size should be 4. +', + 'orig_content' => '// - With tabwidth 4, the tab size should be 4. +', + ], + ]; + + }//end getTabReplacementExpected() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTest.inc b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTest.inc new file mode 100644 index 000000000..e6046500e --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Tokenizers/Tokenizer/ReplaceTabsInTokenTest.inc @@ -0,0 +1,46 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Tokenizers\Tokenizer; + +use Exception; +use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase; + +/** + * Tab replacement test case. + * + * @covers PHP_CodeSniffer\Tokenizers\Tokenizer::replaceTabsInToken + */ +abstract class ReplaceTabsInTokenTestCase extends AbstractTokenizerTestCase +{ + + /** + * The name of the test case file used by this test. + * + * @var string + */ + private static $caseFileName; + + + /** + * Make a copy the test case file we want to use for this test (as the file will be used by multiple tests). + * + * @beforeClass + * + * @return void + * + * @throws \Exception In case the base test case file would not be available. + */ + public static function copyCaseFile() + { + $relativeCN = str_replace(__NAMESPACE__.'\\', '', get_called_class()); + self::$caseFileName = __DIR__.DIRECTORY_SEPARATOR.$relativeCN.'.inc'; + + $baseFileName = realpath(__DIR__.'/ReplaceTabsInTokenTest.inc'); + if (is_string($baseFileName) === false) { + throw new Exception('Base test case file "ReplaceTabsInTokenTest.inc" not found'); + } + + if (copy($baseFileName, self::$caseFileName) === false) { + throw new Exception(sprintf('Failed to copy test case file "ReplaceTabsInTokenTest.inc" to %s', self::$caseFileName)); + } + + }//end copyCaseFile() + + + /** + * Delete the copied test case file after use. + * + * @afterClass + * + * @return void + */ + public static function deleteCaseFile() + { + @unlink(self::$caseFileName); + + }//end deleteCaseFile() + + + /** + * Verify that if a token not containing tabs would be passed to the replaceTabsInToken() method, + * yes, the `orig_content` key is added, but no changes are made to the token `content` or `length` values. + * + * @param string $testMarker The comment prefacing the target token. + * @param int|string $testTarget Token code to look for. + * @param array $expected Expectations for the token array. + * @param int $offset Optional. Offset from the target token to get to the _real_ target. + * This is specifically needed to target indentation whitespace. + * + * @dataProvider dataNoReplacementsAreMadeWhenNoTabsAreFound + * + * @return void + */ + public function testNoReplacementsAreMadeWhenNoTabsAreFound($testMarker, $testTarget, $expected, $offset=0) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, $testTarget); + $target += $offset; + + foreach ($expected as $key => $value) { + if ($key === 'orig_content' && $value === null) { + $this->assertArrayNotHasKey($key, $tokens[$target], "Unexpected 'orig_content' key found in the token array."); + continue; + } + + $this->assertArrayHasKey($key, $tokens[$target], "Key $key not found in the token array."); + $this->assertSame($value, $tokens[$target][$key], "Value for key $key does not match expectation."); + } + + }//end testNoReplacementsAreMadeWhenNoTabsAreFound() + + + /** + * Data provider. + * + * @see testNoReplacementsAreMadeWhenNoTabsAreFound() + * + * @return array>> + */ + public static function dataNoReplacementsAreMadeWhenNoTabsAreFound() + { + return [ + 'Indentation whitespace, only spaces' => [ + 'testMarker' => '/* testNoReplacementNeeded */', + 'testTarget' => T_WHITESPACE, + 'expected' => [ + 'length' => 4, + 'content' => ' ', + 'orig_content' => null, + ], + 'offset' => 1, + ], + 'Trailing comment not containing any tabs' => [ + 'testMarker' => '/* testNoReplacementNeeded */', + 'testTarget' => T_COMMENT, + 'expected' => [ + 'length' => 35, + 'content' => '// Comment not containing any tabs. +', + 'orig_content' => null, + ], + ], + ]; + + }//end dataNoReplacementsAreMadeWhenNoTabsAreFound() + + + /** + * Test tab replacement in tokens. + * + * @param string $testMarker The comment prefacing the target token. + * @param int|string $testTarget Token code to look for. + * @param array $expected Expectations for the token array. + * @param int $offset Optional. Offset from the target token to get to the _real_ target. + * This is specifically needed to target indentation whitespace. + * + * @dataProvider dataTabReplacement + * + * @return void + */ + public function testTabReplacement($testMarker, $testTarget, $expected, $offset=0) + { + $tokens = $this->phpcsFile->getTokens(); + $target = $this->getTargetToken($testMarker, $testTarget); + $target += $offset; + + foreach ($expected as $key => $value) { + if ($key === 'orig_content' && $value === null) { + $this->assertArrayNotHasKey($key, $tokens[$target], "Unexpected 'orig_content' key found in the token array."); + continue; + } + + $this->assertArrayHasKey($key, $tokens[$target], "Key $key not found in the token array."); + $this->assertSame($value, $tokens[$target][$key], "Value for key $key does not match expectation."); + } + + }//end testTabReplacement() + + + /** + * Data provider. + * + * @see testTabReplacement() + * + * @return array>> + * + * @throws \Exception When the getTabReplacementExpected() method doesn't provide data in the correct format. + */ + public static function dataTabReplacement() + { + $data = [ + 'Tab indentation' => [ + 'testMarker' => '/* testTabIndentation */', + 'testTarget' => T_WHITESPACE, + ], + 'Mixed tab/space indentation' => [ + 'testMarker' => '/* testMixedIndentation */', + 'testTarget' => T_WHITESPACE, + ], + 'Inline: single tab in text string' => [ + 'testMarker' => '/* testInlineSingleTab */', + 'testTarget' => T_CONSTANT_ENCAPSED_STRING, + ], + 'Inline: single tab between each word in text string' => [ + 'testMarker' => '/* testInlineSingleTabBetweenEachWord */', + 'testTarget' => T_DOUBLE_QUOTED_STRING, + ], + 'Inline: multiple tabs in heredoc' => [ + 'testMarker' => '/* testInlineMultiTab */', + 'testTarget' => T_HEREDOC, + ], + 'Inline: multiple tabs between each word in nowdoc' => [ + 'testMarker' => '/* testInlineMultipleTabsBetweenEachWord */', + 'testTarget' => T_NOWDOC, + ], + 'Inline: mixed spaces/tabs in text string' => [ + 'testMarker' => '/* testInlineMixedSpacesTabs */', + 'testTarget' => T_CONSTANT_ENCAPSED_STRING, + ], + 'Inline: mixed spaces/tabs between each word in text string' => [ + 'testMarker' => '/* testInlineMixedSpacesTabsBetweenEachWord */', + 'testTarget' => T_DOUBLE_QUOTED_STRING, + ], + 'Inline: tab becomes single space in comment (with tabwidth 4)' => [ + 'testMarker' => '/* testInlineSize1 */', + 'testTarget' => T_COMMENT, + ], + 'Inline: tab becomes 2 spaces in comment (with tabwidth 4)' => [ + 'testMarker' => '/* testInlineSize2 */', + 'testTarget' => T_COMMENT, + ], + 'Inline: tab becomes 3 spaces in doc comment string (with tabwidth 4)' => [ + 'testMarker' => '/* testInlineSize3 */', + 'testTarget' => T_DOC_COMMENT_STRING, + ], + 'Inline: tab becomes 4 spaces in comment (with tabwidth 4)' => [ + 'testMarker' => '/* testInlineSize4 */', + 'testTarget' => T_COMMENT, + ], + ]; + + $expectations = static::getTabReplacementExpected(); + + foreach ($data as $key => $value) { + if (isset($expectations[$key]) === false || is_array($expectations[$key]) === false) { + throw new Exception( + sprintf('Invalid getTabReplacementExpected() method. Missing expectation array for the "%s" test case', $key) + ); + } + + if (isset($expectations[$key]['length'], $expectations[$key]['content']) === false + || array_key_exists('orig_content', $expectations[$key]) === false + ) { + throw new Exception( + sprintf('Invalid expectation array for the "%s" test case. The array must contain the "length", "content" and "orig_content" keys', $key) + ); + } + + $data[$key]['expected'] = $expectations[$key]; + } + + // Set offset for test cases targetting whitespace. + $data['Tab indentation']['offset'] = 1; + $data['Mixed tab/space indentation']['offset'] = 1; + + return $data; + + }//end dataTabReplacement() + + + /** + * Data provider helper. + * + * Should be declared in child classes to set the expectations for the token array. + * + * @see dataTabReplacement() + * + * @return array> + */ + abstract public static function getTabReplacementExpected(); + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/EscapeshellcmdTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/EscapeshellcmdTest.php new file mode 100644 index 000000000..2844c4a32 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/EscapeshellcmdTest.php @@ -0,0 +1,91 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Common; + +use PHP_CodeSniffer\Util\Common; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Util\Common::escapeshellcmd() method. + * + * @covers \PHP_CodeSniffer\Util\Common::escapeshellcmd + * @group Windows + */ +final class EscapeshellcmdTest extends TestCase +{ + + + /** + * Test escaping shell commands. + * + * @param string $command The command provided. + * @param string $expected Expected function output. + * @param string $expectedWin Optional. Expected function output on Windows. + * Only needs to be passed if the output on Windows would be different. + * + * @dataProvider dataEscapeshellcmd + * + * @return void + */ + public function testEscapeshellcmd($command, $expected, $expectedWin=null) + { + if (stripos(PHP_OS, 'WIN') === 0 && empty($expectedWin) === false) { + $expected = $expectedWin; + } + + $this->assertSame($expected, Common::escapeshellcmd($command)); + + }//end testEscapeshellcmd() + + + /** + * Data provider. + * + * Note: we're only testing the PHPCS functionality, not the PHP native `escapeshellcmd()` + * function (as that's not our responsibility). + * + * @see testEscapeshellcmd() + * + * @return array> + */ + public static function dataEscapeshellcmd() + { + return [ + 'Command is empty string' => [ + 'command' => '', + 'expected' => '', + ], + 'Command is simple string' => [ + 'command' => 'csslint', + 'expected' => 'csslint', + ], + 'Command containing characters which PHP escapes' => [ + 'command' => '&#;`|*?~<>^()[]{}$\,%!', + 'expected' => '\&\#\;\`\|\*\?\~\<\>\^\(\)\[\]\{\}\$\\\\,%!', + 'expectedWin' => '^&^#^;^`^|^*^?^~^<^>^^^(^)^[^]^{^}^$^\,^%^!', + ], + // @link https://github.com/squizlabs/PHP_CodeSniffer/pull/3214 + 'Command containing spaces, which can cause problems on Windows' => [ + 'command' => 'C:\Program Files\nodejs\csslint.cmd', + 'expected' => 'C:\\\\Program Files\\\\nodejs\\\\csslint.cmd', + 'expectedWin' => 'C:^\Program^ Files^\nodejs^\csslint.cmd', + ], + // @link https://github.com/php/doc-en/pull/511 + 'Command containing spaces with additional arguments' => [ + 'command' => 'php -f ./~home/path to/file.php', + 'expected' => 'php -f ./\~home/path to/file.php', + 'expectedWin' => 'php^ -f^ ./^~home/path^ to/file.php', + ], + ]; + + }//end dataEscapeshellcmd() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/GetSniffCodeTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/GetSniffCodeTest.php new file mode 100644 index 000000000..444ea5eb0 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/GetSniffCodeTest.php @@ -0,0 +1,212 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Common; + +use PHP_CodeSniffer\Util\Common; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Util\Common::getSniffCode() method. + * + * @covers \PHP_CodeSniffer\Util\Common::getSniffCode + */ +final class GetSniffCodeTest extends TestCase +{ + + + /** + * Test receiving an expected exception when the $sniffClass parameter is not passed a string value or is passed an empty string. + * + * @param mixed $input NOT a fully qualified sniff class name. + * + * @dataProvider dataGetSniffCodeThrowsExceptionOnInvalidInput + * + * @return void + */ + public function testGetSniffCodeThrowsExceptionOnInvalidInput($input) + { + $exception = 'InvalidArgumentException'; + $message = 'The $sniffClass parameter must be a non-empty string'; + + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException($exception); + $this->expectExceptionMessage($message); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $message); + } + + Common::getSniffCode($input); + + }//end testGetSniffCodeThrowsExceptionOnInvalidInput() + + + /** + * Data provider. + * + * @see testGetSniffCodeThrowsExceptionOnInvalidInput() + * + * @return array> + */ + public static function dataGetSniffCodeThrowsExceptionOnInvalidInput() + { + return [ + 'Class name is not a string' => [true], + 'Class name is empty' => [''], + ]; + + }//end dataGetSniffCodeThrowsExceptionOnInvalidInput() + + + /** + * Test receiving an expected exception when the $sniffClass parameter is not passed a value which + * could be a fully qualified sniff(test) class name. + * + * @param string $input String input which can not be a fully qualified sniff(test) class name. + * + * @dataProvider dataGetSniffCodeThrowsExceptionOnInputWhichIsNotASniffTestClass + * + * @return void + */ + public function testGetSniffCodeThrowsExceptionOnInputWhichIsNotASniffTestClass($input) + { + $exception = 'InvalidArgumentException'; + $message = 'The $sniffClass parameter was not passed a fully qualified sniff(test) class name. Received:'; + + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException($exception); + $this->expectExceptionMessage($message); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $message); + } + + Common::getSniffCode($input); + + }//end testGetSniffCodeThrowsExceptionOnInputWhichIsNotASniffTestClass() + + + /** + * Data provider. + * + * @see testGetSniffCodeThrowsExceptionOnInputWhichIsNotASniffTestClass() + * + * @return array> + */ + public static function dataGetSniffCodeThrowsExceptionOnInputWhichIsNotASniffTestClass() + { + return [ + 'Unqualified class name' => ['ClassName'], + 'Fully qualified class name, not enough parts' => ['Fully\\Qualified\\ClassName'], + 'Fully qualified class name, doesn\'t end on Sniff or UnitTest' => ['Fully\\Sniffs\\Qualified\\ClassName'], + ]; + + }//end dataGetSniffCodeThrowsExceptionOnInputWhichIsNotASniffTestClass() + + + /** + * Test transforming a sniff class name to a sniff code. + * + * @param string $fqnClass A fully qualified sniff class name. + * @param string $expected Expected function output. + * + * @dataProvider dataGetSniffCode + * + * @return void + */ + public function testGetSniffCode($fqnClass, $expected) + { + $this->assertSame($expected, Common::getSniffCode($fqnClass)); + + }//end testGetSniffCode() + + + /** + * Data provider. + * + * @see testGetSniffCode() + * + * @return array> + */ + public static function dataGetSniffCode() + { + return [ + 'PHPCS native sniff' => [ + 'fqnClass' => 'PHP_CodeSniffer\\Standards\\Generic\\Sniffs\\Arrays\\ArrayIndentSniff', + 'expected' => 'Generic.Arrays.ArrayIndent', + ], + 'Class is a PHPCS native test class' => [ + 'fqnClass' => 'PHP_CodeSniffer\\Standards\\Generic\\Tests\\Arrays\\ArrayIndentUnitTest', + 'expected' => 'Generic.Arrays.ArrayIndent', + ], + 'Sniff in external standard without namespace prefix' => [ + 'fqnClass' => 'MyStandard\\Sniffs\\PHP\\MyNameSniff', + 'expected' => 'MyStandard.PHP.MyName', + ], + 'Test in external standard without namespace prefix' => [ + 'fqnClass' => 'MyStandard\\Tests\\PHP\\MyNameUnitTest', + 'expected' => 'MyStandard.PHP.MyName', + ], + 'Sniff in external standard with namespace prefix' => [ + 'fqnClass' => 'Vendor\\Package\\MyStandard\\Sniffs\\Category\\AnalyzeMeSniff', + 'expected' => 'MyStandard.Category.AnalyzeMe', + ], + 'Test in external standard with namespace prefix' => [ + 'fqnClass' => 'Vendor\\Package\\MyStandard\\Tests\\Category\\AnalyzeMeUnitTest', + 'expected' => 'MyStandard.Category.AnalyzeMe', + ], + + /* + * These are not valid sniff codes and is an undesirable result, but can't be helped + * as changing this would be a BC-break. + * Supporting these to allow for tags directly including sniff files. + * See: https://github.com/PHPCSStandards/PHP_CodeSniffer/issues/675 + */ + + 'Fully qualified class name, ends on Sniff, but isn\'t' => [ + 'fqnClass' => 'Fully\\Sniffs\\AbstractSomethingSniff', + 'expected' => '.Sniffs.AbstractSomething', + ], + 'Sniff provided via file include and doesn\'t comply with naming conventions [1]' => [ + 'fqnClass' => 'CheckMeSniff', + 'expected' => '..CheckMe', + ], + 'Sniff provided via file include and doesn\'t comply with naming conventions [2]' => [ + 'fqnClass' => 'CompanyName\\CheckMeSniff', + 'expected' => '.CompanyName.CheckMe', + ], + 'Sniff provided via file include and doesn\'t comply with naming conventions [3]' => [ + 'fqnClass' => 'CompanyName\\Sniffs\\CheckMeSniff', + 'expected' => '.Sniffs.CheckMe', + ], + 'Sniff provided via file include and doesn\'t comply with naming conventions [4]' => [ + 'fqnClass' => 'CompanyName\\CustomSniffs\\Whatever\\CheckMeSniff', + 'expected' => 'CompanyName.Whatever.CheckMe', + ], + 'Sniff provided via file include and doesn\'t comply with naming conventions [5]' => [ + 'fqnClass' => 'CompanyName\\Sniffs\\Category\\Sniff', + 'expected' => 'CompanyName.Category.', + ], + 'Sniff provided via file include and doesn\'t comply with naming conventions [6]' => [ + 'fqnClass' => 'CompanyName\\Tests\\Category\\UnitTest', + 'expected' => 'CompanyName.Category.', + ], + 'Sniff provided via file include and doesn\'t comply with naming conventions [7]' => [ + 'fqnClass' => 'Sniffs\\Category\\NamedSniff', + 'expected' => '.Category.Named', + ], + ]; + + }//end dataGetSniffCode() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/IsCamelCapsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/IsCamelCapsTest.php similarity index 98% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Util/IsCamelCapsTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/IsCamelCapsTest.php index 4d15a41fe..951d76187 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/IsCamelCapsTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/IsCamelCapsTest.php @@ -7,7 +7,7 @@ * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Util; +namespace PHP_CodeSniffer\Tests\Core\Util\Common; use PHP_CodeSniffer\Util\Common; use PHPUnit\Framework\TestCase; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/PrepareForOutputTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/PrepareForOutputTest.php new file mode 100644 index 000000000..8eb2fc22f --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/PrepareForOutputTest.php @@ -0,0 +1,113 @@ +assertSame($expected, Common::prepareForOutput($content, $exclude)); + + }//end testPrepareForOutput() + + + /** + * Test formatting whitespace characters, on Windows. + * + * @param string $content The content to prepare. + * @param string[] $exclude A list of characters to leave invisible. + * @param string $expected Expected function output (unused in this test). + * @param string $expectedWin Expected function output on Windows. + * + * @requires OS ^WIN.*. + * @dataProvider dataPrepareForOutput + * + * @return void + */ + public function testPrepareForOutputWindows($content, $exclude, $expected, $expectedWin) + { + $this->assertSame($expectedWin, Common::prepareForOutput($content, $exclude)); + + }//end testPrepareForOutputWindows() + + + /** + * Data provider. + * + * @see testPrepareForOutput() + * @see testPrepareForOutputWindows() + * + * @return array> + */ + public static function dataPrepareForOutput() + { + return [ + 'Special characters are replaced with their escapes' => [ + 'content' => "\r\n\t", + 'exclude' => [], + 'expected' => "\033[30;1m\\r\033[0m\033[30;1m\\n\033[0m\033[30;1m\\t\033[0m", + 'expectedWin' => "\\r\\n\\t", + ], + 'Spaces are replaced with a unique mark' => [ + 'content' => " ", + 'exclude' => [], + 'expected' => "\033[30;1m·\033[0m\033[30;1m·\033[0m\033[30;1m·\033[0m\033[30;1m·\033[0m", + 'expectedWin' => " ", + ], + 'Other characters are unaffected' => [ + 'content' => "{echo 1;}", + 'exclude' => [], + 'expected' => "{echo\033[30;1m·\033[0m1;}", + 'expectedWin' => "{echo 1;}", + ], + 'No replacements' => [ + 'content' => 'nothing-should-be-replaced', + 'exclude' => [], + 'expected' => 'nothing-should-be-replaced', + 'expectedWin' => 'nothing-should-be-replaced', + ], + 'Excluded whitespace characters are unaffected' => [ + 'content' => "\r\n\t ", + 'exclude' => [ + "\r", + "\n", + ], + 'expected' => "\r\n\033[30;1m\\t\033[0m\033[30;1m·\033[0m", + 'expectedWin' => "\r\n\\t ", + ], + ]; + + }//end dataPrepareForOutput() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/StripColorsTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/StripColorsTest.php new file mode 100644 index 000000000..ff253b8b8 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/StripColorsTest.php @@ -0,0 +1,96 @@ + + * @copyright 2024 Juliette Reinders Folmer. All rights reserved. + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Common; + +use PHP_CodeSniffer\Util\Common; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Util\Common::stripColors() method. + * + * @covers \PHP_CodeSniffer\Util\Common::stripColors + */ +final class StripColorsTest extends TestCase +{ + + + /** + * Test stripping color codes from a text. + * + * @param string $text The text provided. + * @param string $expected Expected function output. + * + * @dataProvider dataStripColors + * + * @return void + */ + public function testStripColors($text, $expected) + { + $this->assertSame($expected, Common::stripColors($text)); + + }//end testStripColors() + + + /** + * Data provider. + * + * @see testStripColors() + * + * @return array> + */ + public static function dataStripColors() + { + return [ + 'Text is empty' => [ + 'text' => '', + 'expected' => '', + ], + 'Text enclosed in color code' => [ + 'text' => "\033[36mSome text\033[0m", + 'expected' => 'Some text', + ], + 'Text containing color code' => [ + 'text' => "Some text \033[33mSome other text", + 'expected' => 'Some text Some other text', + ], + 'Text enclosed in color code, bold' => [ + 'text' => "\033[1;32mSome text\033[0m", + 'expected' => 'Some text', + ], + 'Text enclosed in color code, with escaped text' => [ + 'text' => "\033[30;1m\\n\033[0m", + 'expected' => '\n', + ], + 'Text enclosed in color code, bold, dark, italic' => [ + 'text' => "\033[1;2;3mtext\033[0m", + 'expected' => 'text', + ], + 'Text enclosed in color code, foreground color' => [ + 'text' => "\033[38;5;255mtext\033[0m", + 'expected' => 'text', + ], + 'Text enclosed in color code, foreground color and background color' => [ + 'text' => "\033[38;5;200;48;5;255mtext\033[0m", + 'expected' => 'text', + ], + 'Multiline text containing multiple color codes' => [ + 'text' => "First \033[36mSecond\033[0m +Third \033[1;2;3mFourth +Next line\033[0m Last", + 'expected' => 'First Second +Third Fourth +Next line Last', + ], + ]; + + }//end dataStripColors() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/SuggestTypeTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/SuggestTypeTest.php similarity index 97% rename from app/vendor/squizlabs/php_codesniffer/tests/Core/Util/SuggestTypeTest.php rename to app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/SuggestTypeTest.php index 48790a888..48bb6df1d 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/SuggestTypeTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Common/SuggestTypeTest.php @@ -1,19 +1,19 @@ * @copyright 2019 Juliette Reinders Folmer. All rights reserved. * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence */ -namespace PHP_CodeSniffer\Tests\Core\Util; +namespace PHP_CodeSniffer\Tests\Core\Util\Common; use PHP_CodeSniffer\Util\Common; use PHPUnit\Framework\TestCase; /** - * Tests for the \PHP_CodeSniffer\Util\Sniffs\Comments::suggestType() method. + * Tests for the \PHP_CodeSniffer\Util\Common::suggestType() method. * * @covers \PHP_CodeSniffer\Util\Common::suggestType */ diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Help/HelpTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Help/HelpTest.php new file mode 100644 index 000000000..b3d51a5c7 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Help/HelpTest.php @@ -0,0 +1,769 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Help; + +use PHP_CodeSniffer\Tests\ConfigDouble; +use PHP_CodeSniffer\Util\Help; +use PHPUnit\Framework\TestCase; +use ReflectionMethod; +use ReflectionProperty; + +/** + * Test the Help class. + * + * @covers \PHP_CodeSniffer\Util\Help + */ +final class HelpTest extends TestCase +{ + + + /** + * QA check: verify that the category names are at most the minimum screen width + * and that option argument names are always at most half the length of the minimum screen width. + * + * If this test would start failing, either wrapping of argument info would need to be implemented + * or the minimum screen width needs to be upped. + * + * @coversNothing + * + * @return void + */ + public function testQaArgumentNamesAreWithinAcceptableBounds() + { + $help = new Help(new ConfigDouble(), []); + + $reflMethod = new ReflectionMethod($help, 'getAllOptions'); + $reflMethod->setAccessible(true); + $allOptions = $reflMethod->invoke($help); + $reflMethod->setAccessible(false); + + $this->assertGreaterThan(0, count($allOptions), 'No categories found'); + + $minScreenWidth = Help::MIN_WIDTH; + $maxArgWidth = ($minScreenWidth / 2); + + foreach ($allOptions as $category => $options) { + $this->assertLessThanOrEqual( + Help::MIN_WIDTH, + strlen($category), + "Category name $category is longer than the minimum screen width of $minScreenWidth" + ); + + foreach ($options as $option) { + if (isset($option['argument']) === false) { + continue; + } + + $this->assertLessThanOrEqual( + $maxArgWidth, + strlen($option['argument']), + "Option name {$option['argument']} is longer than the half the minimum screen width of $minScreenWidth" + ); + } + } + + }//end testQaArgumentNamesAreWithinAcceptableBounds() + + + /** + * QA check: verify that each option only contains a spacer, text or argument + description combo. + * + * @coversNothing + * + * @return void + */ + public function testQaValidCategoryOptionDefinitions() + { + $help = new Help(new ConfigDouble(), []); + + $reflMethod = new ReflectionMethod($help, 'getAllOptions'); + $reflMethod->setAccessible(true); + $allOptions = $reflMethod->invoke($help); + $reflMethod->setAccessible(false); + + $this->assertGreaterThan(0, count($allOptions), 'No categories found'); + + foreach ($allOptions as $category => $options) { + $this->assertGreaterThan(0, count($options), "No options found in category $category"); + + foreach ($options as $name => $option) { + if (isset($option['spacer']) === true) { + $this->assertStringStartsWith('blank-line', $name, 'The name for spacer items should start with "blank-line"'); + } + + $this->assertFalse( + isset($option['spacer'], $option['text']), + "Option $name: spacer and text should not be combined in one option" + ); + $this->assertFalse( + isset($option['spacer'], $option['argument']), + "Option $name: spacer and argument should not be combined in one option" + ); + $this->assertFalse( + isset($option['spacer'], $option['description']), + "Option $name: spacer and description should not be combined in one option" + ); + $this->assertFalse( + isset($option['text'], $option['argument']), + "Option $name: text and argument should not be combined in one option" + ); + $this->assertFalse( + isset($option['text'], $option['description']), + "Option $name: text and description should not be combined in one option" + ); + + if (isset($option['argument']) === true) { + $this->assertArrayHasKey( + 'description', + $option, + "Option $name: an argument should always be accompanied by a description" + ); + } + + if (isset($option['description']) === true) { + $this->assertArrayHasKey( + 'argument', + $option, + "Option $name: a description should always be accompanied by an argument" + ); + } + }//end foreach + }//end foreach + + }//end testQaValidCategoryOptionDefinitions() + + + /** + * Test receiving an expected exception when the shortOptions parameter is not passed a string value. + * + * @return void + */ + public function testConstructorInvalidArgumentException() + { + $exception = 'InvalidArgumentException'; + $message = 'The $shortOptions parameter must be a string'; + + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException($exception); + $this->expectExceptionMessage($message); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $message); + } + + new Help(new ConfigDouble(), [], []); + + }//end testConstructorInvalidArgumentException() + + + /** + * Test filtering of the options by requested options. + * + * Tests that: + * - Options not explicitly requested are removed. + * - Short options passed via the longOptions array are still respected. + * - A category gets removed if all options are removed, even if the category still has spacers. + * + * @param array $longOptions The long options which should be displayed. + * @param string $shortOptions The short options which should be displayed. + * @param array $expected The categories expected after filtering with the number + * of expected help items per category. + * + * @dataProvider dataOptionFiltering + * + * @return void + */ + public function testOptionFiltering($longOptions, $shortOptions, $expected) + { + $help = new Help(new ConfigDouble(), $longOptions, $shortOptions); + + $reflProperty = new ReflectionProperty($help, 'activeOptions'); + $reflProperty->setAccessible(true); + $activeOptions = $reflProperty->getValue($help); + $reflProperty->setAccessible(false); + + // Simplify the value to make it comparible. + foreach ($activeOptions as $category => $options) { + $activeOptions[$category] = count($options); + } + + $this->assertSame($expected, $activeOptions, 'Option count per category does not match'); + + }//end testOptionFiltering() + + + /** + * Data provider. + * + * @return array|array>> + */ + public static function dataOptionFiltering() + { + $allLongOptions = explode(',', Help::DEFAULT_LONG_OPTIONS); + $allLongOptions[] = 'cache'; + $allLongOptions[] = 'no-cache'; + $allLongOptions[] = 'report'; + $allLongOptions[] = 'report-file'; + $allLongOptions[] = 'report-report'; + $allLongOptions[] = 'runtime-set'; + $allLongOptions[] = 'config-explain'; + $allLongOptions[] = 'config-set'; + $allLongOptions[] = 'config-delete'; + $allLongOptions[] = 'config-show'; + $allLongOptions[] = 'generator'; + $allLongOptions[] = 'suffix'; + + $allShortOptions = Help::DEFAULT_SHORT_OPTIONS.'saem'; + + return [ + 'No options' => [ + 'longOptions' => [], + 'shortOptions' => '', + 'expected' => [], + ], + 'Invalid options have no influence' => [ + 'longOptions' => [ + 'doesnotexist', + 'invalid', + ], + 'shortOptions' => 'bjrz', + 'expected' => [], + ], + 'Short options passed as long options works fine' => [ + 'longOptions' => [ + 's', + 'suffix', + 'a', + 'e', + 'colors', + ], + 'shortOptions' => '', + 'expected' => [ + 'Rule Selection Options' => 1, + 'Run Options' => 2, + 'Reporting Options' => 2, + ], + ], + 'All options' => [ + 'longOptions' => $allLongOptions, + 'shortOptions' => $allShortOptions, + 'expected' => [ + 'Scan targets' => 8, + 'Rule Selection Options' => 7, + 'Run Options' => 8, + 'Reporting Options' => 19, + 'Configuration Options' => 8, + 'Miscellaneous Options' => 5, + ], + ], + 'Default options only' => [ + 'longOptions' => explode(',', Help::DEFAULT_LONG_OPTIONS), + 'shortOptions' => Help::DEFAULT_SHORT_OPTIONS, + 'expected' => [ + 'Scan targets' => 8, + 'Rule Selection Options' => 5, + 'Run Options' => 4, + 'Reporting Options' => 14, + 'Configuration Options' => 4, + 'Miscellaneous Options' => 5, + ], + ], + 'Only one category' => [ + 'longOptions' => [ + 'file', + 'stdin-path', + 'file-list', + 'filter', + 'ignore', + 'extensions', + ], + 'shortOptions' => '-l', + 'expected' => [ + 'Scan targets' => 8, + ], + ], + 'All except one category' => [ + 'longOptions' => array_diff($allLongOptions, ['version', 'vv', 'vvv']), + 'shortOptions' => str_replace(['h', 'v'], '', $allShortOptions), + 'expected' => [ + 'Scan targets' => 8, + 'Rule Selection Options' => 7, + 'Run Options' => 8, + 'Reporting Options' => 19, + 'Configuration Options' => 8, + ], + ], + ]; + + }//end dataOptionFiltering() + + + /** + * Test filtering of the options by requested options does not leave stray spacers at the start + * or end of a category and that a category does not contain two consecutive spacers. + * + * {@internal Careful! This test may need updates to still test what it is supposed to test + * if/when the defined options in Help::getAllOptions() change.} + * + * @param array $longOptions The long options which should be displayed. + * @param string $shortOptions The short options which should be displayed. + * + * @dataProvider dataOptionFilteringSpacerHandling + * + * @return void + */ + public function testOptionFilteringSpacerHandling($longOptions, $shortOptions) + { + $help = new Help(new ConfigDouble(), $longOptions, $shortOptions); + + $reflProperty = new ReflectionProperty($help, 'activeOptions'); + $reflProperty->setAccessible(true); + $activeOptions = $reflProperty->getValue($help); + $reflProperty->setAccessible(false); + + $this->assertNotEmpty($activeOptions, 'Active options is empty, test is invalid'); + + foreach ($activeOptions as $options) { + $first = reset($options); + $this->assertArrayNotHasKey('spacer', $first, 'Found spacer at start of category'); + + $last = end($options); + $this->assertArrayNotHasKey('spacer', $last, 'Found spacer at end of category'); + + $previousWasSpacer = false; + foreach ($options as $option) { + $this->assertFalse((isset($option['spacer']) && $previousWasSpacer === true), 'Consecutive spacers found'); + $previousWasSpacer = isset($option['spacer']); + } + } + + }//end testOptionFilteringSpacerHandling() + + + /** + * Data provider. + * + * @return array>> + */ + public static function dataOptionFilteringSpacerHandling() + { + return [ + 'No spacer at start of category' => [ + 'longOptions' => ['generator'], + 'shortOptions' => 'ie', + ], + 'No spacer at end of category' => [ + 'longOptions' => [ + 'encoding', + 'tab-width', + ], + 'shortOptions' => '', + ], + 'No consecutive spacers within category' => [ + 'longOptions' => [ + 'report', + 'report-file', + 'report-report', + 'report-width', + 'basepath', + 'ignore-annotations', + 'colors', + 'no-colors', + ], + 'shortOptions' => 'spqm', + ], + ]; + + }//end dataOptionFilteringSpacerHandling() + + + /** + * Test that if no short/long options are passed, only usage information is displayed (CS mode). + * + * @param array $cliArgs Command line arguments. + * @param string $expectedRegex Regex to validate expected output. + * + * @dataProvider dataDisplayUsage + * + * @return void + */ + public function testDisplayUsageCS($cliArgs, $expectedRegex) + { + if (PHP_CODESNIFFER_CBF === true) { + $this->markTestSkipped('This test needs CS mode to run'); + } + + $expectedRegex = str_replace('phpc(bf|s)', 'phpcs', $expectedRegex); + $this->verifyDisplayUsage($cliArgs, $expectedRegex); + + }//end testDisplayUsageCS() + + + /** + * Test that if no short/long options are passed, only usage information is displayed (CBF mode). + * + * @param array $cliArgs Command line arguments. + * @param string $expectedRegex Regex to validate expected output. + * + * @dataProvider dataDisplayUsage + * @group CBF + * + * @return void + */ + public function testDisplayUsageCBF($cliArgs, $expectedRegex) + { + if (PHP_CODESNIFFER_CBF === false) { + $this->markTestSkipped('This test needs CBF mode to run'); + } + + $expectedRegex = str_replace('phpc(bf|s)', 'phpcbf', $expectedRegex); + $this->verifyDisplayUsage($cliArgs, $expectedRegex); + + }//end testDisplayUsageCBF() + + + /** + * Helper method to test that if no short/long options are passed, only usage information is displayed + * (and displayed correctly). + * + * @param array $cliArgs Command line arguments. + * @param string $expectedRegex Regex to validate expected output. + * + * @return void + */ + private function verifyDisplayUsage($cliArgs, $expectedRegex) + { + $help = new Help(new ConfigDouble($cliArgs), []); + + $this->expectOutputRegex($expectedRegex); + + $help->display(); + + }//end verifyDisplayUsage() + + + /** + * Data provider. + * + * @return array>> + */ + public static function dataDisplayUsage() + { + return [ + 'Usage without colors' => [ + 'cliArgs' => ['--no-colors'], + 'expectedRegex' => '`^\s*Usage:\s+phpc(bf|s) \[options\] \\s+$`', + ], + 'Usage with colors' => [ + 'cliArgs' => ['--colors'], + 'expectedRegex' => '`^\s*\\033\[33mUsage:\\033\[0m\s+phpc(bf|s) \[options\] \\s+$`', + ], + ]; + + }//end dataDisplayUsage() + + + /** + * Test the column width calculations. + * + * This tests the following aspects: + * 1. That the report width is never less than Help::MIN_WIDTH, even when a smaller width is passed. + * 2. That the first column width is calculated correctly and is based on the longest argument. + * 3. That the word wrapping of the description respects the maximum report width. + * 4. That if the description is being wrapped, the indent for the second line is calculated correctly. + * + * @param int $reportWidth Report width for the test. + * @param array $longOptions The long options which should be displayed. + * @param string $expectedOutput Expected output. + * + * @dataProvider dataReportWidthCalculations + * + * @return void + */ + public function testReportWidthCalculations($reportWidth, $longOptions, $expectedOutput) + { + $config = new ConfigDouble(["--report-width=$reportWidth", '--no-colors']); + $help = new Help($config, $longOptions); + + $reflMethod = new ReflectionMethod($help, 'printCategories'); + $reflMethod->setAccessible(true); + $reflMethod->invoke($help); + $reflMethod->setAccessible(false); + + $this->expectOutputString($expectedOutput); + + }//end testReportWidthCalculations() + + + /** + * Data provider. + * + * @return array>> + */ + public static function dataReportWidthCalculations() + { + $longOptions = [ + 'e', + 'generator', + ]; + + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Test readability is more important. + return [ + 'Report width small: 40; forces report width to minimum width of 60' => [ + 'reportWidth' => 40, + 'longOptions' => $longOptions, + 'expectedOutput' => PHP_EOL.'Rule Selection Options:'.PHP_EOL + .' -e Explain a standard by showing the'.PHP_EOL + .' names of all the sniffs it'.PHP_EOL + .' includes.'.PHP_EOL + .' --generator= Show documentation for a standard.'.PHP_EOL + .' Use either the "HTML", "Markdown"'.PHP_EOL + .' or "Text" generator.'.PHP_EOL, + ], + 'Report width is minimum: 60 (= self::MIN_WIDTH)' => [ + 'reportWidth' => Help::MIN_WIDTH, + 'longOptions' => $longOptions, + 'expectedOutput' => PHP_EOL.'Rule Selection Options:'.PHP_EOL + .' -e Explain a standard by showing the'.PHP_EOL + .' names of all the sniffs it'.PHP_EOL + .' includes.'.PHP_EOL + .' --generator= Show documentation for a standard.'.PHP_EOL + .' Use either the "HTML", "Markdown"'.PHP_EOL + .' or "Text" generator.'.PHP_EOL, + ], + 'Report width matches length for one line, not the other: 96; only one should wrap' => [ + 'reportWidth' => 96, + 'longOptions' => $longOptions, + 'expectedOutput' => PHP_EOL.'Rule Selection Options:'.PHP_EOL + .' -e Explain a standard by showing the names of all the sniffs it includes.'.PHP_EOL + .' --generator= Show documentation for a standard. Use either the "HTML", "Markdown"'.PHP_EOL + .' or "Text" generator.'.PHP_EOL, + ], + 'Report width matches longest line: 119; the messages should not wrap and there should be no stray new line at the end' => [ + 'reportWidth' => 119, + 'longOptions' => $longOptions, + 'expectedOutput' => PHP_EOL.'Rule Selection Options:'.PHP_EOL + .' -e Explain a standard by showing the names of all the sniffs it includes.'.PHP_EOL + .' --generator= Show documentation for a standard. Use either the "HTML", "Markdown" or "Text" generator.'.PHP_EOL, + ], + ]; + // phpcs:enable + + }//end dataReportWidthCalculations() + + + /** + * Verify that variable elements in an argument specification get colorized correctly. + * + * @param string $input String to colorize. + * @param string $expected Expected function output. + * + * @dataProvider dataColorizeVariableInput + * + * @return void + */ + public function testColorizeVariableInput($input, $expected) + { + $help = new Help(new ConfigDouble(), []); + + $reflMethod = new ReflectionMethod($help, 'colorizeVariableInput'); + $reflMethod->setAccessible(true); + $result = $reflMethod->invoke($help, $input); + $reflMethod->setAccessible(false); + + $this->assertSame($expected, $result); + + }//end testColorizeVariableInput() + + + /** + * Data provider. + * + * @return array>> + */ + public static function dataColorizeVariableInput() + { + return [ + 'Empty string' => [ + 'input' => '', + 'expected' => '', + ], + 'String without variable element(s)' => [ + 'input' => 'This is text', + 'expected' => 'This is text', + ], + 'String with variable element' => [ + 'input' => 'This text', + 'expected' => "This \033[36m\033[32m text", + ], + 'String with multiple variable elements' => [ + 'input' => ' is ', + 'expected' => "\033[36m\033[32m is \033[36m\033[32m", + ], + 'String with unclosed variable element' => [ + 'input' => 'This 'This [ + 'input' => ' text>', + 'expected' => "\033[36m text>\033[32m", + ], + 'String with nested elements and surrounding text' => [ + 'input' => 'Start text> end', + 'expected' => "Start \033[36m text>\033[32m end", + ], + ]; + + }//end dataColorizeVariableInput() + + + /** + * Test the various option types within a category get displayed correctly. + * + * @param array> $input The options to print. + * @param array $expectedRegex Regexes to validate expected output. + * + * @dataProvider dataPrintCategoryOptions + * + * @return void + */ + public function testPrintCategoryOptionsNoColor($input, $expectedRegex) + { + $config = new ConfigDouble(['--no-colors']); + $help = new Help($config, []); + + $reflProperty = new ReflectionProperty($help, 'activeOptions'); + $reflProperty->setAccessible(true); + $reflProperty->setValue($help, ['cat' => $input]); + $reflProperty->setAccessible(false); + + $reflMethod = new ReflectionMethod($help, 'setMaxOptionNameLength'); + $reflMethod->setAccessible(true); + $reflMethod->invoke($help); + $reflMethod->setAccessible(false); + + $reflMethod = new ReflectionMethod($help, 'printCategoryOptions'); + $reflMethod->setAccessible(true); + $reflMethod->invoke($help, $input); + $reflMethod->setAccessible(false); + + $this->expectOutputRegex($expectedRegex['no-color']); + + }//end testPrintCategoryOptionsNoColor() + + + /** + * Test the various option types within a category get displayed correctly. + * + * @param array> $input The options to print. + * @param array $expectedRegex Regexes to validate expected output. + * + * @dataProvider dataPrintCategoryOptions + * + * @return void + */ + public function testPrintCategoryOptionsColor($input, $expectedRegex) + { + $config = new ConfigDouble(['--colors']); + $help = new Help($config, []); + + $reflProperty = new ReflectionProperty($help, 'activeOptions'); + $reflProperty->setAccessible(true); + $reflProperty->setValue($help, ['cat' => $input]); + $reflProperty->setAccessible(false); + + $reflMethod = new ReflectionMethod($help, 'setMaxOptionNameLength'); + $reflMethod->setAccessible(true); + $reflMethod->invoke($help); + $reflMethod->setAccessible(false); + + $reflMethod = new ReflectionMethod($help, 'printCategoryOptions'); + $reflMethod->setAccessible(true); + $reflMethod->invoke($help, $input); + $reflMethod->setAccessible(false); + + $this->expectOutputRegex($expectedRegex['color']); + + }//end testPrintCategoryOptionsColor() + + + /** + * Data provider. + * + * @return array>|array>> + */ + public static function dataPrintCategoryOptions() + { + $indentLength = strlen(Help::INDENT); + $gutterLength = strlen(Help::GUTTER); + + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Test readability is more important. + // phpcs:disable Generic.Strings.UnnecessaryStringConcat.Found -- Test readability is more important. + return [ + 'Input: arg, spacer, arg; new lines in description get preserved' => [ + 'input' => [ + 'short-option' => [ + 'argument' => '-a', + 'description' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + ], + 'blank-line' => [ + 'spacer' => '', + ], + 'long-option-multi-line-description' => [ + 'argument' => '--something=', + 'description' => 'Proin sit amet malesuada libero, finibus bibendum tortor. Nulla vitae quam nec orci finibus pharetra.' + ."\n".'Nam eget blandit dui.', + ], + ], + 'expectedRegex' => [ + 'no-color' => '`^ {'.$indentLength.'}-a {15} {'.$gutterLength.'}Lorem ipsum dolor sit amet, consectetur adipiscing elit\.\R' + .'\R' + .' {'.$indentLength.'}--something= {'.$gutterLength.'}Proin sit amet malesuada libero, finibus bibendum tortor\.\R' + .' {'.($indentLength + 17).'} {'.$gutterLength.'}Nulla vitae quam nec orci finibus pharetra\.\R' + .' {'.($indentLength + 17).'} {'.$gutterLength.'}Nam eget blandit dui\.\R$`', + 'color' => '`^ {'.$indentLength.'}\\033\[32m-a {15}\\033\[0m {'.$gutterLength.'}Lorem ipsum dolor sit amet, consectetur adipiscing elit\.\R' + .'\R' + .' {'.$indentLength.'}\\033\[32m--something=\\033\[36m\\033\[32m\\033\[0m {'.$gutterLength.'}Proin sit amet malesuada libero, finibus bibendum tortor\.\R' + .' {'.($indentLength + 17).'} {'.$gutterLength.'}Nulla vitae quam nec orci finibus pharetra\.\R' + .' {'.($indentLength + 17).'} {'.$gutterLength.'}Nam eget blandit dui\.\R$`', + ], + ], + 'Input: text, arg, text; multi-line text gets wrapped' => [ + 'input' => [ + 'single-line-text' => [ + 'text' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + ], + 'argument-description' => [ + 'argument' => '--something', + 'description' => 'Fusce dapibus sodales est eu sodales.', + ], + 'multi-line-text-gets-wrapped' => [ + 'text' => 'Maecenas vulputate ligula vel feugiat finibus. Mauris sem dui, pretium in turpis auctor, consectetur ultrices lorem.', + ], + ], + 'expectedRegex' => [ + 'no-color' => '`^ {'.$indentLength.'}Lorem ipsum dolor sit amet, consectetur adipiscing elit\.\R' + .' {'.$indentLength.'}--something {'.$gutterLength.'}Fusce dapibus sodales est eu sodales\.\R' + .' {'.$indentLength.'}Maecenas vulputate ligula vel feugiat finibus. Mauris sem dui, pretium in\R' + .' {'.$indentLength.'}turpis auctor, consectetur ultrices lorem\.\R$`', + 'color' => '`^ {'.$indentLength.'}Lorem ipsum dolor sit amet, consectetur adipiscing elit\.\R' + .' {'.$indentLength.'}\\033\[32m--something\\033\[0m {'.$gutterLength.'}Fusce dapibus sodales est eu sodales\.\R' + .' {'.$indentLength.'}Maecenas vulputate ligula vel feugiat finibus. Mauris sem dui, pretium in\R' + .' {'.$indentLength.'}turpis auctor, consectetur ultrices lorem\.\R$`', + ], + ], + ]; + // phpcs:enable + + }//end dataPrintCategoryOptions() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/MessageCollector/MessageCollectorTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/MessageCollector/MessageCollectorTest.php new file mode 100644 index 000000000..faa98ca41 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/MessageCollector/MessageCollectorTest.php @@ -0,0 +1,538 @@ +expectException($exception); + $this->expectExceptionMessage($exceptionMsg); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $exceptionMsg); + } + + $msgCollector = new MessageCollector(); + $msgCollector->add($message); + + }//end testAddingNonStringMessageResultsInException() + + + /** + * Data provider. + * + * @see testAddingNonStringMessageResultsInException() + * + * @return array> + */ + public static function dataAddingNonStringMessageResultsInException() + { + return [ + 'null' => [null], + 'boolean' => [true], + 'integer' => [10], + 'array' => [['something' => 'incorrect']], + ]; + + }//end dataAddingNonStringMessageResultsInException() + + + /** + * Verify that passing a message type which is not one of the predefined types is rejected with an exception. + * + * @param mixed $type The invalid "type" to pass. + * + * @dataProvider dataAddingMessageWithUnsupportedMessageTypeResultsInException + * + * @return void + */ + public function testAddingMessageWithUnsupportedMessageTypeResultsInException($type) + { + $exception = 'InvalidArgumentException'; + $exceptionMsg = 'The message $type should be one of the predefined MessageCollector constants. Received: '; + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException($exception); + $this->expectExceptionMessage($exceptionMsg); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $exceptionMsg); + } + + $msgCollector = new MessageCollector(); + $msgCollector->add('Message', $type); + + }//end testAddingMessageWithUnsupportedMessageTypeResultsInException() + + + /** + * Data provider. + * + * @see testAddingMessageWithUnsupportedMessageTypeResultsInException() + * + * @return array> + */ + public static function dataAddingMessageWithUnsupportedMessageTypeResultsInException() + { + return [ + 'null' => [null], + 'boolean' => [true], + 'string' => ['DEPRECATED'], + 'integer which doesn\'t match any of the message type constants: -235' => [-235], + 'integer which doesn\'t match any of the message type constants: 0' => [0], + 'integer which doesn\'t match any of the message type constants: 3' => [3], + 'integer which doesn\'t match any of the message type constants: 6' => [6], + 'integer which doesn\'t match any of the message type constants: 123' => [123], + 'integer which doesn\'t match any of the message type constants: PHP_INT_MAX' => [PHP_INT_MAX], + ]; + + }//end dataAddingMessageWithUnsupportedMessageTypeResultsInException() + + + /** + * Verify that the `containsBlockingErrors()` method correctly identifies whether the collected messages + * include messages which are blocking (errors), or only include non-blocking (warnings, notices, + * deprecations) messages. + * + * @param array $messages The messages to display. + * Key is the message, value is the error level. + * @param bool $expected The expected function output. + * + * @dataProvider dataContainsBlockingErrors + * + * @return void + */ + public function testContainsBlockingErrors($messages, $expected) + { + $msgCollector = new MessageCollector(); + $this->createErrorCache($msgCollector, $messages); + + $this->assertSame($expected, $msgCollector->containsBlockingErrors()); + + }//end testContainsBlockingErrors() + + + /** + * Data provider. + * + * @see testContainsBlockingErrors() + * + * @return array|bool>> + */ + public static function dataContainsBlockingErrors() + { + return [ + 'No messages' => [ + 'messages' => [], + 'expected' => false, + ], + 'Only non-blocking messages' => [ + 'messages' => [ + 'First message' => MessageCollector::WARNING, + 'Second message' => MessageCollector::NOTICE, + 'Third message' => MessageCollector::DEPRECATED, + ], + 'expected' => false, + ], + 'Only blocking messages' => [ + 'messages' => [ + 'First message' => MessageCollector::ERROR, + 'Second message' => MessageCollector::ERROR, + 'Third message' => MessageCollector::ERROR, + ], + 'expected' => true, + ], + 'Mix of blocking and non-blocking messages' => [ + 'messages' => [ + 'First message' => MessageCollector::DEPRECATED, + 'Second message' => MessageCollector::ERROR, + 'Third message' => MessageCollector::WARNING, + ], + 'expected' => true, + ], + ]; + + }//end dataContainsBlockingErrors() + + + /** + * Test displaying non-blocking messages only. + * + * Verifies that: + * - Each message is prefixed with the appropriate prefix. + * - The default message order is observed. + * - The messages use the appropriate OS-specific EOL character. + * + * @param array $messages The messages to display. + * Key is the message, value is the error level. + * @param string $expected The expected exception message. + * + * @dataProvider dataDisplayingNonBlockingMessages + * + * @return void + */ + public function testDisplayingNonBlockingMessages($messages, $expected) + { + $msgCollector = new MessageCollector(); + $this->createErrorCache($msgCollector, $messages); + + $this->expectOutputString($expected); + + $msgCollector->display(); + + }//end testDisplayingNonBlockingMessages() + + + /** + * Data provider. + * + * @see testDisplayingNonBlockingMessages() + * + * @return array|string>> + */ + public static function dataDisplayingNonBlockingMessages() + { + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Test readability is more important. + return [ + 'No messages' => [ + 'messages' => [], + 'expected' => '', + ], + 'One warning' => [ + 'messages' => [ + 'This is a warning' => MessageCollector::WARNING, + ], + 'expected' => 'WARNING: This is a warning'.PHP_EOL.PHP_EOL, + ], + 'One notice' => [ + 'messages' => [ + 'This is a notice' => MessageCollector::NOTICE, + ], + 'expected' => 'NOTICE: This is a notice'.PHP_EOL.PHP_EOL, + ], + 'One deprecation' => [ + 'messages' => [ + 'This is a deprecation' => MessageCollector::DEPRECATED, + ], + 'expected' => 'DEPRECATED: This is a deprecation'.PHP_EOL.PHP_EOL, + ], + 'Multiple warnings' => [ + 'messages' => [ + 'First warning' => MessageCollector::WARNING, + 'Second warning' => MessageCollector::WARNING, + ], + 'expected' => 'WARNING: First warning'.PHP_EOL + .'WARNING: Second warning'.PHP_EOL.PHP_EOL, + ], + 'Multiple notices' => [ + 'messages' => [ + 'First notice' => MessageCollector::NOTICE, + 'Second notice' => MessageCollector::NOTICE, + 'Third notice' => MessageCollector::NOTICE, + ], + 'expected' => 'NOTICE: First notice'.PHP_EOL + .'NOTICE: Second notice'.PHP_EOL + .'NOTICE: Third notice'.PHP_EOL.PHP_EOL, + ], + 'Multiple deprecations' => [ + 'messages' => [ + 'First deprecation' => MessageCollector::DEPRECATED, + 'Second deprecation' => MessageCollector::DEPRECATED, + ], + 'expected' => 'DEPRECATED: First deprecation'.PHP_EOL + .'DEPRECATED: Second deprecation'.PHP_EOL.PHP_EOL, + ], + 'All together now' => [ + 'messages' => [ + 'First deprecation' => MessageCollector::DEPRECATED, + 'Second warning' => MessageCollector::WARNING, + 'Third notice' => MessageCollector::NOTICE, + 'Fourth warning' => MessageCollector::WARNING, + ], + 'expected' => 'WARNING: Second warning'.PHP_EOL + .'WARNING: Fourth warning'.PHP_EOL + .'NOTICE: Third notice'.PHP_EOL + .'DEPRECATED: First deprecation'.PHP_EOL.PHP_EOL, + ], + ]; + // phpcs:enable + + }//end dataDisplayingNonBlockingMessages() + + + /** + * Test displaying message collections containing blocking messages. + * + * Verifies that: + * - Each message is prefixed with the appropriate prefix. + * - The default message order is observed. + * - The messages use the appropriate OS-specific EOL character. + * + * @param array $messages The messages to display. + * Key is the message, value is the error level. + * @param string $expected The expected exception message. + * + * @dataProvider dataDisplayingBlockingErrors + * + * @return void + */ + public function testDisplayingBlockingErrors($messages, $expected) + { + $exception = 'PHP_CodeSniffer\Exceptions\RuntimeException'; + if (method_exists($this, 'expectException') === true) { + // PHPUnit 5+. + $this->expectException($exception); + $this->expectExceptionMessage($expected); + } else { + // PHPUnit 4. + $this->setExpectedException($exception, $expected); + } + + $msgCollector = new MessageCollector(); + $this->createErrorCache($msgCollector, $messages); + $msgCollector->display(); + + }//end testDisplayingBlockingErrors() + + + /** + * Data provider. + * + * @see testDisplayingBlockingErrors() + * + * @return array|string>> + */ + public static function dataDisplayingBlockingErrors() + { + // phpcs:disable Squiz.Strings.ConcatenationSpacing.PaddingFound -- Test readability is more important. + return [ + 'Single error' => [ + 'messages' => [ + 'This is an error' => MessageCollector::ERROR, + ], + 'expected' => 'ERROR: This is an error'.PHP_EOL.PHP_EOL, + ], + 'Multiple errors' => [ + 'messages' => [ + 'First error' => MessageCollector::ERROR, + 'Second error' => MessageCollector::ERROR, + ], + 'expected' => 'ERROR: First error'.PHP_EOL + .'ERROR: Second error'.PHP_EOL.PHP_EOL, + ], + 'Errors mixed with non-blocking messages' => [ + 'messages' => [ + 'First deprecation' => MessageCollector::DEPRECATED, + 'Second warning' => MessageCollector::WARNING, + 'Third notice' => MessageCollector::NOTICE, + 'Fourth error' => MessageCollector::ERROR, + 'Fifth warning' => MessageCollector::WARNING, + 'Sixth error' => MessageCollector::ERROR, + 'Seventh deprecation' => MessageCollector::DEPRECATED, + ], + 'expected' => 'ERROR: Fourth error'.PHP_EOL + .'ERROR: Sixth error'.PHP_EOL + .'WARNING: Second warning'.PHP_EOL + .'WARNING: Fifth warning'.PHP_EOL + .'NOTICE: Third notice'.PHP_EOL + .'DEPRECATED: First deprecation'.PHP_EOL + .'DEPRECATED: Seventh deprecation'.PHP_EOL.PHP_EOL, + ], + ]; + // phpcs:enable + + }//end dataDisplayingBlockingErrors() + + + /** + * Verify and safeguard that adding the same message twice is accepted when messages have different error levels. + * + * Note: have multiple messages with the exact same text is not great for conveying information + * to the end-user, but that's not the concern of the MessageCollector class. + * + * @return void + */ + public function testNonUniqueMessagesWithDifferentErrorLevelAreAccepted() + { + $message = 'Trying to add the same message twice'; + $msgCollector = new MessageCollector(); + $msgCollector->add($message, MessageCollector::NOTICE); + $msgCollector->add($message, MessageCollector::WARNING); + + $expected = 'WARNING: Trying to add the same message twice'.PHP_EOL; + $expected .= 'NOTICE: Trying to add the same message twice'.PHP_EOL.PHP_EOL; + $this->expectOutputString($expected); + + $msgCollector->display(); + + }//end testNonUniqueMessagesWithDifferentErrorLevelAreAccepted() + + + /** + * Verify and safeguard that adding the same message twice is accepted when messages have the same error level. + * + * Note: have multiple messages with the exact same text is not great for conveying information + * to the end-user, but that's not the concern of the MessageCollector class. + * + * @return void + */ + public function testNonUniqueMessagesWithSameErrorLevelAreAccepted() + { + $message = 'Trying to add the same message twice'; + $msgCollector = new MessageCollector(); + $msgCollector->add($message, MessageCollector::NOTICE); + $msgCollector->add($message, MessageCollector::NOTICE); + + $expected = 'NOTICE: Trying to add the same message twice'.PHP_EOL; + $expected .= 'NOTICE: Trying to add the same message twice'.PHP_EOL.PHP_EOL; + $this->expectOutputString($expected); + + $msgCollector->display(); + + }//end testNonUniqueMessagesWithSameErrorLevelAreAccepted() + + + /** + * Ensure that the message cache is cleared when the collected messages are displayed. + * + * @return void + */ + public function testCallingDisplayTwiceWillNotShowMessagesTwice() + { + $messages = [ + 'First notice' => MessageCollector::NOTICE, + 'Second deprecation' => MessageCollector::DEPRECATED, + 'Third notice' => MessageCollector::NOTICE, + 'Fourth warning' => MessageCollector::WARNING, + ]; + + $msgCollector = new MessageCollector(); + $this->createErrorCache($msgCollector, $messages); + + $expected = 'WARNING: Fourth warning'.PHP_EOL; + $expected .= 'NOTICE: First notice'.PHP_EOL; + $expected .= 'NOTICE: Third notice'.PHP_EOL; + $expected .= 'DEPRECATED: Second deprecation'.PHP_EOL.PHP_EOL; + $this->expectOutputString($expected); + + $msgCollector->display(); + $msgCollector->display(); + + }//end testCallingDisplayTwiceWillNotShowMessagesTwice() + + + /** + * Test that messages are ordered correctly. + * + * @param string $order The display order. + * @param string $expected The expected output. + * + * @dataProvider dataDisplayOrderHandling + * + * @return void + */ + public function testDisplayOrderHandling($order, $expected) + { + $messages = [ + 'First notice' => MessageCollector::NOTICE, + 'Second deprecation' => MessageCollector::DEPRECATED, + 'Third notice' => MessageCollector::NOTICE, + 'Fourth warning' => MessageCollector::WARNING, + ]; + + $msgCollector = new MessageCollector(); + $this->createErrorCache($msgCollector, $messages); + + $this->expectOutputString($expected); + + $msgCollector->display($order); + + }//end testDisplayOrderHandling() + + + /** + * Data provider. + * + * @see testDisplayOrderHandling() + * + * @return array> + */ + public static function dataDisplayOrderHandling() + { + $expectedForSeverity = 'WARNING: Fourth warning'.PHP_EOL; + $expectedForSeverity .= 'NOTICE: First notice'.PHP_EOL; + $expectedForSeverity .= 'NOTICE: Third notice'.PHP_EOL; + $expectedForSeverity .= 'DEPRECATED: Second deprecation'.PHP_EOL.PHP_EOL; + + $expectedForReceived = 'NOTICE: First notice'.PHP_EOL; + $expectedForReceived .= 'DEPRECATED: Second deprecation'.PHP_EOL; + $expectedForReceived .= 'NOTICE: Third notice'.PHP_EOL; + $expectedForReceived .= 'WARNING: Fourth warning'.PHP_EOL.PHP_EOL; + + return [ + 'Order by severity' => [ + 'order' => MessageCollector::ORDERBY_SEVERITY, + 'expected' => $expectedForSeverity, + ], + 'Order by received' => [ + 'order' => MessageCollector::ORDERBY_RECEIVED, + 'expected' => $expectedForReceived, + ], + 'Invalid order defaults to severity' => [ + 'order' => 'unknown order', + 'expected' => $expectedForSeverity, + ], + ]; + + }//end dataDisplayOrderHandling() + + + /** + * Test helper. + * + * @param \PHP_CodeSniffer\Util\MessageCollector $collector The error cache object. + * @param array $messages The error messages to add to the cache. + * Key is the message, value is the error level. + * + * @return void + */ + private function createErrorCache(MessageCollector $collector, $messages) + { + foreach ($messages as $msg => $type) { + $collector->add($msg, $type); + } + + }//end createErrorCache() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Timing/GetHumanReadableDurationTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Timing/GetHumanReadableDurationTest.php new file mode 100644 index 000000000..93b3d05e1 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Timing/GetHumanReadableDurationTest.php @@ -0,0 +1,114 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Timing; + +use PHP_CodeSniffer\Util\Timing; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Util\Timing::getHumanReadableDuration() method. + * + * @covers \PHP_CodeSniffer\Util\Timing::getHumanReadableDuration + */ +final class GetHumanReadableDurationTest extends TestCase +{ + + + /** + * Test the method. + * + * @param int|float $duration A duration in milliseconds. + * @param string $expected The expected human readable string. + * + * @dataProvider dataGetHumanReadableDuration + * + * @return void + */ + public function testGetHumanReadableDuration($duration, $expected) + { + $this->assertSame($expected, Timing::getHumanReadableDuration($duration)); + + }//end testGetHumanReadableDuration() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataGetHumanReadableDuration() + { + return [ + 'Duration: 0' => [ + 'duration' => 0, + 'expected' => '0ms', + ], + 'Duration: 13 milliseconds' => [ + 'duration' => 13.232101565, + 'expected' => '13ms', + ], + 'Duration: 14 milliseconds' => [ + 'duration' => 13.916015625, + 'expected' => '14ms', + ], + 'Duration: 999 milliseconds' => [ + 'duration' => 999.2236, + 'expected' => '999ms', + ], + 'Duration: 999+ milliseconds' => [ + 'duration' => 999.89236, + 'expected' => '1000ms', + ], + 'Duration: 1 second' => [ + 'duration' => 1000, + 'expected' => '1 secs', + ], + 'Duration: slightly more than 1 second' => [ + 'duration' => 1001.178215, + 'expected' => '1 secs', + ], + 'Duration: just under a 1 minute' => [ + 'duration' => 59999.3851, + 'expected' => '60 secs', + ], + 'Duration: exactly 1 minute' => [ + 'duration' => 60000, + 'expected' => '1 mins', + ], + 'Duration: slightly more than 1 minute' => [ + 'duration' => 60001.7581235, + 'expected' => '1 mins', + ], + 'Duration: 1 minute, just under half a second' => [ + 'duration' => 60499.83639, + 'expected' => '1 mins, 0.5 secs', + ], + 'Duration: 1 minute, just over half a second' => [ + 'duration' => 60501.961238, + 'expected' => '1 mins, 0.5 secs', + ], + 'Duration: 1 minute, 1 second' => [ + 'duration' => 61000, + 'expected' => '1 mins, 1 secs', + ], + 'Duration: exactly 1 hour' => [ + 'duration' => 3600000, + 'expected' => '60 mins', + ], + 'Duration: 89.4 mins' => [ + 'duration' => 5364000, + 'expected' => '89 mins, 24 secs', + ], + ]; + + }//end dataGetHumanReadableDuration() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Timing/TimingTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Timing/TimingTest.php new file mode 100644 index 000000000..87c2a6495 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Timing/TimingTest.php @@ -0,0 +1,121 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Timing; + +use PHP_CodeSniffer\Util\Timing; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Util\Timing class. + * + * {@internal These tests need to run in separate processes as the Timing class uses static properties + * to keep track of the start time and whether or not the runtime has been printed and these + * can't be unset/reset once set.} + * + * @covers \PHP_CodeSniffer\Util\Timing + * + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + */ +final class TimingTest extends TestCase +{ + + + /** + * Verify that getDuration() returns 0 when the timer wasn't started. + * + * @return void + */ + public function testGetDurationWithoutStartReturnsZero() + { + $this->assertSame(0, Timing::getDuration()); + + }//end testGetDurationWithoutStartReturnsZero() + + + /** + * Verify that getDuration() returns the time in milliseconds. + * + * @return void + */ + public function testGetDurationWithStartReturnsMilliseconds() + { + Timing::startTiming(); + usleep(1500); + $duration = Timing::getDuration(); + + $this->assertTrue(is_float($duration)); + + }//end testGetDurationWithStartReturnsMilliseconds() + + + /** + * Verify that printRunTime() doesn't print anything if the timer wasn't started. + * + * @return void + */ + public function testTimeIsNotPrintedIfTimerWasNeverStarted() + { + $this->expectOutputString(''); + Timing::printRunTime(); + + }//end testTimeIsNotPrintedIfTimerWasNeverStarted() + + + /** + * Verify that printRunTime() doesn't print anything if the timer wasn't started. + * + * @return void + */ + public function testTimeIsNotPrintedIfTimerWasNeverStartedEvenWhenForced() + { + $this->expectOutputString(''); + Timing::printRunTime(true); + + }//end testTimeIsNotPrintedIfTimerWasNeverStartedEvenWhenForced() + + + /** + * Verify that printRunTime() when called multiple times only prints the runtime information once. + * + * @return void + */ + public function testTimeIsPrintedOnlyOnce() + { + $this->expectOutputRegex('`^Time: [0-9]+ms; Memory: [0-9\.]+MB'.PHP_EOL.PHP_EOL.'$`'); + + Timing::startTiming(); + usleep(2000); + Timing::printRunTime(); + Timing::printRunTime(); + Timing::printRunTime(); + + }//end testTimeIsPrintedOnlyOnce() + + + /** + * Verify that printRunTime() when called multiple times prints the runtime information multiple times if forced. + * + * @return void + */ + public function testTimeIsPrintedMultipleTimesOnlyIfForced() + { + $this->expectOutputRegex('`^(Time: [0-9]+ms; Memory: [0-9\.]+MB'.PHP_EOL.PHP_EOL.'){3}$`'); + + Timing::startTiming(); + usleep(2000); + Timing::printRunTime(true); + Timing::printRunTime(true); + Timing::printRunTime(true); + + }//end testTimeIsPrintedMultipleTimesOnlyIfForced() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Tokens/GetHighestWeightedTokenTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Tokens/GetHighestWeightedTokenTest.php new file mode 100644 index 000000000..e0bd014c9 --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Tokens/GetHighestWeightedTokenTest.php @@ -0,0 +1,162 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Tokens; + +use PHP_CodeSniffer\Util\Tokens; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Util\Tokens::getHighestWeightedToken() method. + * + * @covers \PHP_CodeSniffer\Util\Tokens::getHighestWeightedToken + */ +final class GetHighestWeightedTokenTest extends TestCase +{ + + + /** + * Test the method. + * + * @param array $tokens The tokens to find the heighest weighted one. + * @param int|false $expected The expected function return value. + * + * @dataProvider dataGetHighestWeightedToken + * + * @return void + */ + public function testGetHighestWeightedToken($tokens, $expected) + { + $this->assertSame($expected, Tokens::getHighestWeightedToken($tokens)); + + }//end testGetHighestWeightedToken() + + + /** + * Data provider. + * + * @return array>> + */ + public static function dataGetHighestWeightedToken() + { + $data = [ + 'Array of non-tokens passed, returns first' => [ + 'tokens' => [ + PHP_SAPI, + PHP_MAJOR_VERSION, + PHP_OS, + ], + 'expected' => PHP_SAPI, + ], + 'No weightings available for any of the selected tokens, first one wins' => [ + 'tokens' => [ + T_VARIABLE, + T_STRING, + T_EXTENDS, + T_IMPLEMENTS, + ], + 'expected' => T_VARIABLE, + ], + 'single token always returns that token' => [ + 'tokens' => [T_VARIABLE], + 'expected' => T_VARIABLE, + ], + 'Unknown and known token, known token wins' => [ + 'tokens' => [ + T_VARIABLE, + T_SELF, + ], + 'expected' => T_SELF, + ], + 'Known and unknown token, known token wins' => [ + 'tokens' => [ + T_CLOSURE, + T_STRING, + ], + 'expected' => T_CLOSURE, + ], + 'Two tokens with equal weights passed, first one wins' => [ + 'tokens' => [ + T_CLOSURE, + T_FUNCTION, + ], + 'expected' => T_CLOSURE, + ], + 'Five tokens with equal weights passed, first one wins' => [ + 'tokens' => [ + T_NAMESPACE, + T_TRAIT, + T_ENUM, + T_CLASS, + T_INTERFACE, + ], + 'expected' => T_NAMESPACE, + ], + 'Tokens with different weights passed, heightest (25) wins' => [ + 'tokens' => [ + T_BITWISE_OR, + T_SELF, + T_MUL_EQUAL, + ], + 'expected' => T_SELF, + ], + 'Tokens with different weights passed, heightest (50) wins' => [ + 'tokens' => [ + T_BITWISE_XOR, + T_CATCH, + T_SPACESHIP, + T_PARENT, + ], + 'expected' => T_CATCH, + ], + ]; + + $high100 = [ + T_MULTIPLY, + T_BITWISE_AND, + T_SELF, + T_FOREACH, + T_CLOSURE, + ]; + $data['Tokens with different weights passed, ordered low-high, heightest (100) wins'] = [ + 'tokens' => $high100, + 'expected' => T_CLOSURE, + ]; + + shuffle($high100); + $data['Tokens with different weights passed, order random, heightest (100) wins'] = [ + 'tokens' => $high100, + 'expected' => T_CLOSURE, + ]; + + $high1000 = [ + T_ENUM, + T_FUNCTION, + T_ELSEIF, + T_PARENT, + T_BITWISE_OR, + T_MODULUS, + ]; + $data['Tokens with different weights passed, ordered low-high, heightest (1000) wins'] = [ + 'tokens' => $high1000, + 'expected' => T_ENUM, + ]; + + shuffle($high1000); + $data['Tokens with different weights passed, order random, heightest (1000) wins'] = [ + 'tokens' => $high1000, + 'expected' => T_ENUM, + ]; + + return $data; + + }//end dataGetHighestWeightedToken() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Tokens/TokenNameTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Tokens/TokenNameTest.php new file mode 100644 index 000000000..43c6d695b --- /dev/null +++ b/app/vendor/squizlabs/php_codesniffer/tests/Core/Util/Tokens/TokenNameTest.php @@ -0,0 +1,197 @@ + + * @copyright 2024 PHPCSStandards and contributors + * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence + */ + +namespace PHP_CodeSniffer\Tests\Core\Util\Tokens; + +use PHP_CodeSniffer\Util\Tokens; +use PHPUnit\Framework\TestCase; + +/** + * Tests for the \PHP_CodeSniffer\Util\Tokens::tokenName() method. + * + * @covers \PHP_CodeSniffer\Util\Tokens::tokenName + */ +final class TokenNameTest extends TestCase +{ + + + /** + * Test the method. + * + * @param int|string $tokenCode The PHP/PHPCS token code to get the name for. + * @param string $expected The expected token name. + * + * @dataProvider dataTokenName + * @dataProvider dataPolyfilledPHPNativeTokens + * + * @return void + */ + public function testTokenName($tokenCode, $expected) + { + $this->assertSame($expected, Tokens::tokenName($tokenCode)); + + }//end testTokenName() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataTokenName() + { + return [ + 'PHP native token: T_ECHO' => [ + 'tokenCode' => T_ECHO, + 'expected' => 'T_ECHO', + ], + 'PHP native token: T_FUNCTION' => [ + 'tokenCode' => T_FUNCTION, + 'expected' => 'T_FUNCTION', + ], + 'PHPCS native token: T_CLOSURE' => [ + 'tokenCode' => T_CLOSURE, + 'expected' => 'T_CLOSURE', + ], + 'PHPCS native token: T_STRING_CONCAT' => [ + 'tokenCode' => T_STRING_CONCAT, + 'expected' => 'T_STRING_CONCAT', + ], + + // Document the current behaviour for invalid input. + // This behaviour is subject to change. + 'Non-token integer passed' => [ + 'tokenCode' => 100000, + 'expected' => 'UNKNOWN', + ], + 'Non-token string passed' => [ + 'tokenCode' => 'something', + 'expected' => 'ing', + ], + ]; + + }//end dataTokenName() + + + /** + * Data provider. + * + * @return array> + */ + public static function dataPolyfilledPHPNativeTokens() + { + return [ + 'PHP 5.5 native token, polyfilled: T_FINALLY' => [ + 'tokenCode' => T_FINALLY, + 'expected' => 'T_FINALLY', + ], + 'PHP 5.5 native token, polyfilled: T_YIELD' => [ + 'tokenCode' => T_YIELD, + 'expected' => 'T_YIELD', + ], + + 'PHP 5.6 native token, polyfilled: T_ELLIPSIS' => [ + 'tokenCode' => T_ELLIPSIS, + 'expected' => 'T_ELLIPSIS', + ], + 'PHP 5.6 native token, polyfilled: T_POW' => [ + 'tokenCode' => T_POW, + 'expected' => 'T_POW', + ], + 'PHP 5.6 native token, polyfilled: T_POW_EQUAL' => [ + 'tokenCode' => T_POW_EQUAL, + 'expected' => 'T_POW_EQUAL', + ], + + 'PHP 7.0 native token, polyfilled: T_SPACESHIP' => [ + 'tokenCode' => T_SPACESHIP, + 'expected' => 'T_SPACESHIP', + ], + 'PHP 7.0 native token, polyfilled: T_COALESCE' => [ + 'tokenCode' => T_COALESCE, + 'expected' => 'T_COALESCE', + ], + 'PHP 7.0 native token, polyfilled: T_YIELD_FROM' => [ + 'tokenCode' => T_YIELD_FROM, + 'expected' => 'T_YIELD_FROM', + ], + + 'PHP 7.4 native token, polyfilled: T_COALESCE_EQUAL' => [ + 'tokenCode' => T_COALESCE_EQUAL, + 'expected' => 'T_COALESCE_EQUAL', + ], + 'PHP 7.4 native token, polyfilled: T_BAD_CHARACTER' => [ + 'tokenCode' => T_BAD_CHARACTER, + 'expected' => 'T_BAD_CHARACTER', + ], + 'PHP 7.4 native token, polyfilled: T_FN' => [ + 'tokenCode' => T_FN, + 'expected' => 'T_FN', + ], + + 'PHP 8.0 native token, polyfilled: T_NULLSAFE_OBJECT_OPERATOR' => [ + 'tokenCode' => T_NULLSAFE_OBJECT_OPERATOR, + 'expected' => 'T_NULLSAFE_OBJECT_OPERATOR', + ], + 'PHP 8.0 native token, polyfilled: T_NAME_QUALIFIED' => [ + 'tokenCode' => T_NAME_QUALIFIED, + 'expected' => 'T_NAME_QUALIFIED', + ], + 'PHP 8.0 native token, polyfilled: T_NAME_FULLY_QUALIFIED' => [ + 'tokenCode' => T_NAME_FULLY_QUALIFIED, + 'expected' => 'T_NAME_FULLY_QUALIFIED', + ], + 'PHP 8.0 native token, polyfilled: T_NAME_RELATIVE' => [ + 'tokenCode' => T_NAME_RELATIVE, + 'expected' => 'T_NAME_RELATIVE', + ], + 'PHP 8.0 native token, polyfilled: T_MATCH' => [ + 'tokenCode' => T_MATCH, + 'expected' => 'T_MATCH', + ], + 'PHP 8.0 native token, polyfilled: T_ATTRIBUTE' => [ + 'tokenCode' => T_ATTRIBUTE, + 'expected' => 'T_ATTRIBUTE', + ], + + 'PHP 8.1 native token, polyfilled: T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG' => [ + 'tokenCode' => T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG, + 'expected' => 'T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG', + ], + 'PHP 8.1 native token, polyfilled: T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG' => [ + 'tokenCode' => T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG, + 'expected' => 'T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG', + ], + 'PHP 8.1 native token, polyfilled: T_READONLY' => [ + 'tokenCode' => T_READONLY, + 'expected' => 'T_READONLY', + ], + 'PHP 8.1 native token, polyfilled: T_ENUM' => [ + 'tokenCode' => T_ENUM, + 'expected' => 'T_ENUM', + ], + + 'PHP 8.4 native token, polyfilled: T_PUBLIC_SET' => [ + 'tokenCode' => T_PUBLIC_SET, + 'expected' => 'T_PUBLIC_SET', + ], + 'PHP 8.4 native token, polyfilled: T_PROTECTED_SET' => [ + 'tokenCode' => T_PROTECTED_SET, + 'expected' => 'T_PROTECTED_SET', + ], + 'PHP 8.4 native token, polyfilled: T_PRIVATE_SET' => [ + 'tokenCode' => T_PRIVATE_SET, + 'expected' => 'T_PRIVATE_SET', + ], + ]; + + }//end dataPolyfilledPHPNativeTokens() + + +}//end class diff --git a/app/vendor/squizlabs/php_codesniffer/tests/FileList.php b/app/vendor/squizlabs/php_codesniffer/tests/FileList.php index 1672411de..ac3c944f3 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/FileList.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/FileList.php @@ -9,6 +9,10 @@ namespace PHP_CodeSniffer\Tests; +use RecursiveDirectoryIterator; +use RecursiveIteratorIterator; +use RegexIterator; + class FileList { @@ -52,21 +56,21 @@ public function __construct($directory, $rootPath='', $filter='') { $this->rootPath = $rootPath; - $directory = new \RecursiveDirectoryIterator( + $directory = new RecursiveDirectoryIterator( $directory, - \RecursiveDirectoryIterator::UNIX_PATHS + RecursiveDirectoryIterator::UNIX_PATHS ); - $flattened = new \RecursiveIteratorIterator( + $flattened = new RecursiveIteratorIterator( $directory, - \RecursiveIteratorIterator::LEAVES_ONLY, - \RecursiveIteratorIterator::CATCH_GET_CHILD + RecursiveIteratorIterator::LEAVES_ONLY, + RecursiveIteratorIterator::CATCH_GET_CHILD ); if ($filter === '') { $filter = sprintf($this->baseRegex, preg_quote($this->rootPath)); } - $this->fileIterator = new \RegexIterator($flattened, $filter); + $this->fileIterator = new RegexIterator($flattened, $filter); return $this; diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Standards/AbstractSniffUnitTest.php b/app/vendor/squizlabs/php_codesniffer/tests/Standards/AbstractSniffUnitTest.php index c40075846..ccd90c513 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Standards/AbstractSniffUnitTest.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Standards/AbstractSniffUnitTest.php @@ -13,9 +13,10 @@ namespace PHP_CodeSniffer\Tests\Standards; +use DirectoryIterator; use PHP_CodeSniffer\Exceptions\RuntimeException; -use PHP_CodeSniffer\Ruleset; use PHP_CodeSniffer\Files\LocalFile; +use PHP_CodeSniffer\Ruleset; use PHP_CodeSniffer\Tests\ConfigDouble; use PHP_CodeSniffer\Util\Common; use PHPUnit\Framework\TestCase; @@ -78,7 +79,7 @@ protected function getTestFiles($testFileBase) $testFiles = []; $dir = substr($testFileBase, 0, strrpos($testFileBase, DIRECTORY_SEPARATOR)); - $di = new \DirectoryIterator($dir); + $di = new DirectoryIterator($dir); foreach ($di as $file) { $path = $file->getPathname(); @@ -192,10 +193,13 @@ final public function testSniff() $fixedFile = $testFile.'.fixed'; $filename = basename($testFile); if (file_exists($fixedFile) === true) { - $diff = $phpcsFile->fixer->generateDiff($fixedFile); - if (trim($diff) !== '') { - $fixedFilename = basename($fixedFile); - $failureMessages[] = "Fixed version of $filename does not match expected version in $fixedFilename; the diff is\n$diff"; + if ($phpcsFile->fixer->getContents() !== file_get_contents($fixedFile)) { + // Only generate the (expensive) diff if a difference is expected. + $diff = $phpcsFile->fixer->generateDiff($fixedFile); + if (trim($diff) !== '') { + $fixedFilename = basename($fixedFile); + $failureMessages[] = "Fixed version of $filename does not match expected version in $fixedFilename; the diff is\n$diff"; + } } } else if (is_callable([$this, 'addWarning']) === true) { $this->addWarning("Missing fixed version of $filename to verify the accuracy of fixes, while the sniff is making fixes against the test case file"); diff --git a/app/vendor/squizlabs/php_codesniffer/tests/Standards/AllSniffs.php b/app/vendor/squizlabs/php_codesniffer/tests/Standards/AllSniffs.php index e355d90da..1e273e28e 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/Standards/AllSniffs.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/Standards/AllSniffs.php @@ -9,10 +9,12 @@ namespace PHP_CodeSniffer\Tests\Standards; -use PHP_CodeSniffer\Util\Standards; use PHP_CodeSniffer\Autoload; -use PHPUnit\TextUI\TestRunner; +use PHP_CodeSniffer\Util\Standards; use PHPUnit\Framework\TestSuite; +use PHPUnit\TextUI\TestRunner; +use RecursiveDirectoryIterator; +use RecursiveIteratorIterator; class AllSniffs { @@ -46,8 +48,6 @@ public static function suite() $suite = new TestSuite('PHP CodeSniffer Standards'); - $isInstalled = !is_file(__DIR__.'/../../autoload.php'); - // Optionally allow for ignoring the tests for one or more standards. $ignoreTestsForStandards = getenv('PHPCS_IGNORE_TESTS'); if ($ignoreTestsForStandards === false) { @@ -71,7 +71,7 @@ public static function suite() continue; } - $di = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($testsDir)); + $di = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($testsDir)); foreach ($di as $file) { // Skip hidden files. diff --git a/app/vendor/squizlabs/php_codesniffer/tests/TestSuite.php b/app/vendor/squizlabs/php_codesniffer/tests/TestSuite.php index ff7bde7e4..4598a8562 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/TestSuite.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/TestSuite.php @@ -9,8 +9,8 @@ namespace PHP_CodeSniffer\Tests; -use PHPUnit\Framework\TestSuite as PHPUnit_TestSuite; use PHPUnit\Framework\TestResult; +use PHPUnit\Framework\TestSuite as PHPUnit_TestSuite; class TestSuite extends PHPUnit_TestSuite { diff --git a/app/vendor/squizlabs/php_codesniffer/tests/TestSuite7.php b/app/vendor/squizlabs/php_codesniffer/tests/TestSuite7.php index a4dabf5fc..ad0947c58 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/TestSuite7.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/TestSuite7.php @@ -9,8 +9,8 @@ namespace PHP_CodeSniffer\Tests; -use PHPUnit\Framework\TestSuite as PHPUnit_TestSuite; use PHPUnit\Framework\TestResult; +use PHPUnit\Framework\TestSuite as PHPUnit_TestSuite; class TestSuite extends PHPUnit_TestSuite { @@ -19,11 +19,11 @@ class TestSuite extends PHPUnit_TestSuite /** * Runs the tests and collects their result in a TestResult. * - * @param \PHPUnit\Framework\TestResult $result A test result. + * @param \PHPUnit\Framework\TestResult|null $result A test result. * * @return \PHPUnit\Framework\TestResult */ - public function run(TestResult $result=null): TestResult + public function run(?TestResult $result=null): TestResult { $result = parent::run($result); printPHPCodeSnifferTestOutput(); diff --git a/app/vendor/squizlabs/php_codesniffer/tests/bootstrap.php b/app/vendor/squizlabs/php_codesniffer/tests/bootstrap.php index 8d91b156f..e8ebdbbdd 100644 --- a/app/vendor/squizlabs/php_codesniffer/tests/bootstrap.php +++ b/app/vendor/squizlabs/php_codesniffer/tests/bootstrap.php @@ -11,19 +11,34 @@ define('PHP_CODESNIFFER_IN_TESTS', true); } +/* + * Determine whether the test suite should be run in CBF mode. + * + * Use `` in a `phpunit.xml` file + * or set the ENV variable at an OS-level to enable CBF mode. + * + * To run the CBF specific tests, use the following command: + * vendor/bin/phpunit --group CBF --exclude-group nothing + * + * If the ENV variable has not been set, or is set to "false", the tests will run in CS mode. + */ + if (defined('PHP_CODESNIFFER_CBF') === false) { - define('PHP_CODESNIFFER_CBF', false); + $cbfMode = getenv('PHP_CODESNIFFER_CBF'); + if ($cbfMode === '1') { + define('PHP_CODESNIFFER_CBF', true); + echo 'Note: Tests are running in "CBF" mode'.PHP_EOL.PHP_EOL; + } else { + define('PHP_CODESNIFFER_CBF', false); + echo 'Note: Tests are running in "CS" mode'.PHP_EOL.PHP_EOL; + } } if (defined('PHP_CODESNIFFER_VERBOSITY') === false) { define('PHP_CODESNIFFER_VERBOSITY', 0); } -if (is_file(__DIR__.'/../autoload.php') === true) { - include_once __DIR__.'/../autoload.php'; -} else { - include_once 'PHP/CodeSniffer/autoload.php'; -} +require_once __DIR__.'/../autoload.php'; $tokens = new \PHP_CodeSniffer\Util\Tokens(); diff --git a/app/vendor/symfony/config/Builder/ClassBuilder.php b/app/vendor/symfony/config/Builder/ClassBuilder.php index 619ebd857..c4fd9bc0f 100644 --- a/app/vendor/symfony/config/Builder/ClassBuilder.php +++ b/app/vendor/symfony/config/Builder/ClassBuilder.php @@ -63,11 +63,11 @@ public function build(): string } unset($path[$key]); } - $require .= sprintf('require_once __DIR__.\DIRECTORY_SEPARATOR.\'%s\';', implode('\'.\DIRECTORY_SEPARATOR.\'', $path))."\n"; + $require .= \sprintf('require_once __DIR__.\DIRECTORY_SEPARATOR.\'%s\';', implode('\'.\DIRECTORY_SEPARATOR.\'', $path))."\n"; } $use = $require ? "\n" : ''; foreach (array_keys($this->use) as $statement) { - $use .= sprintf('use %s;', $statement)."\n"; + $use .= \sprintf('use %s;', $statement)."\n"; } $implements = [] === $this->implements ? '' : 'implements '.implode(', ', $this->implements); @@ -126,8 +126,8 @@ public function addProperty(string $name, ?string $classType = null, ?string $de $property->setType($classType); } $this->properties[] = $property; - $defaultValue = null !== $defaultValue ? sprintf(' = %s', $defaultValue) : ''; - $property->setContent(sprintf('private $%s%s;', $property->getName(), $defaultValue)); + $defaultValue = null !== $defaultValue ? \sprintf(' = %s', $defaultValue) : ''; + $property->setContent(\sprintf('private $%s%s;', $property->getName(), $defaultValue)); return $property; } diff --git a/app/vendor/symfony/config/Builder/ConfigBuilderGenerator.php b/app/vendor/symfony/config/Builder/ConfigBuilderGenerator.php index d43d814eb..cfd2810f7 100644 --- a/app/vendor/symfony/config/Builder/ConfigBuilderGenerator.php +++ b/app/vendor/symfony/config/Builder/ConfigBuilderGenerator.php @@ -115,7 +115,7 @@ private function buildNode(NodeInterface $node, ClassBuilder $class, string $nam $child instanceof PrototypedArrayNode => $this->handlePrototypedArrayNode($child, $class, $namespace), $child instanceof VariableNode => $this->handleVariableNode($child, $class), $child instanceof ArrayNode => $this->handleArrayNode($child, $class, $namespace), - default => throw new \RuntimeException(sprintf('Unknown node "%s".', $child::class)), + default => throw new \RuntimeException(\sprintf('Unknown node "%s".', $child::class)), }; } } @@ -127,12 +127,15 @@ private function handleArrayNode(ArrayNode $node, ClassBuilder $class, string $n $class->addRequire($childClass); $this->classes[] = $childClass; + $nodeTypes = $this->getParameterTypes($node); + $paramType = $this->getParamType($nodeTypes); + $hasNormalizationClosures = $this->hasNormalizationClosures($node); $comment = $this->getComment($node); - if ($hasNormalizationClosures) { - $comment = sprintf(" * @template TValue\n * @param TValue \$value\n%s", $comment); - $comment .= sprintf(' * @return %s|$this'."\n", $childClass->getFqcn()); - $comment .= sprintf(' * @psalm-return (TValue is array ? %s : static)'."\n ", $childClass->getFqcn()); + if ($hasNormalizationClosures && 'array' !== $paramType) { + $comment = \sprintf(" * @template TValue of %s\n * @param TValue \$value\n%s", $paramType, $comment); + $comment .= \sprintf(' * @return %s|$this'."\n", $childClass->getFqcn()); + $comment .= \sprintf(' * @psalm-return (TValue is array ? %s : static)'."\n ", $childClass->getFqcn()); } if ('' !== $comment) { $comment = "/**\n$comment*/\n"; @@ -142,8 +145,7 @@ private function handleArrayNode(ArrayNode $node, ClassBuilder $class, string $n $node->getName(), $this->getType($childClass->getFqcn(), $hasNormalizationClosures) ); - $nodeTypes = $this->getParameterTypes($node); - $body = $hasNormalizationClosures ? ' + $body = $hasNormalizationClosures && 'array' !== $paramType ? ' COMMENTpublic function NAME(PARAM_TYPE $value = []): CLASS|static { if (!\is_array($value)) { @@ -178,7 +180,7 @@ private function handleArrayNode(ArrayNode $node, ClassBuilder $class, string $n 'COMMENT' => $comment, 'PROPERTY' => $property->getName(), 'CLASS' => $childClass->getFqcn(), - 'PARAM_TYPE' => \in_array('mixed', $nodeTypes, true) ? 'mixed' : implode('|', $nodeTypes), + 'PARAM_TYPE' => $paramType, ]); $this->buildNode($node, $childClass, $this->getSubNamespace($childClass)); @@ -218,10 +220,11 @@ private function handlePrototypedArrayNode(PrototypedArrayNode $node, ClassBuild $nodeParameterTypes = $this->getParameterTypes($node); $prototypeParameterTypes = $this->getParameterTypes($prototype); + $noKey = null === $key = $node->getKeyAttribute(); if (!$prototype instanceof ArrayNode || ($prototype instanceof PrototypedArrayNode && $prototype->getPrototype() instanceof ScalarNode)) { $class->addUse(ParamConfigurator::class); $property = $class->addProperty($node->getName()); - if (null === $key = $node->getKeyAttribute()) { + if ($noKey) { // This is an array of values; don't use singular name $nodeTypesWithoutArray = array_filter($nodeParameterTypes, static fn ($type) => 'array' !== $type); $body = ' @@ -242,7 +245,7 @@ public function NAME(PARAM_TYPE $value): static 'PROPERTY' => $property->getName(), 'PROTOTYPE_TYPE' => implode('|', $prototypeParameterTypes), 'EXTRA_TYPE' => $nodeTypesWithoutArray ? '|'.implode('|', $nodeTypesWithoutArray) : '', - 'PARAM_TYPE' => \in_array('mixed', $nodeParameterTypes, true) ? 'mixed' : 'ParamConfigurator|'.implode('|', $nodeParameterTypes), + 'PARAM_TYPE' => $this->getParamType($nodeParameterTypes, true), ]); } else { $body = ' @@ -259,7 +262,7 @@ public function NAME(string $VAR, TYPE $VALUE): static $class->addMethod($methodName, $body, [ 'PROPERTY' => $property->getName(), - 'TYPE' => \in_array('mixed', $prototypeParameterTypes, true) ? 'mixed' : 'ParamConfigurator|'.implode('|', $prototypeParameterTypes), + 'TYPE' => $this->getParamType($prototypeParameterTypes, true), 'VAR' => '' === $key ? 'key' : $key, 'VALUE' => 'value' === $key ? 'data' : 'value', ]); @@ -280,18 +283,20 @@ public function NAME(string $VAR, TYPE $VALUE): static $this->getType($childClass->getFqcn().'[]', $hasNormalizationClosures) ); + $paramType = $this->getParamType($noKey ? $nodeParameterTypes : $prototypeParameterTypes); + $comment = $this->getComment($node); - if ($hasNormalizationClosures) { - $comment = sprintf(" * @template TValue\n * @param TValue \$value\n%s", $comment); - $comment .= sprintf(' * @return %s|$this'."\n", $childClass->getFqcn()); - $comment .= sprintf(' * @psalm-return (TValue is array ? %s : static)'."\n ", $childClass->getFqcn()); + if ($hasNormalizationClosures && 'array' !== $paramType) { + $comment = \sprintf(" * @template TValue of %s\n * @param TValue \$value\n%s", $paramType, $comment); + $comment .= \sprintf(' * @return %s|$this'."\n", $childClass->getFqcn()); + $comment .= \sprintf(' * @psalm-return (TValue is array ? %s : static)'."\n ", $childClass->getFqcn()); } if ('' !== $comment) { $comment = "/**\n$comment*/\n"; } - if (null === $key = $node->getKeyAttribute()) { - $body = $hasNormalizationClosures ? ' + if ($noKey) { + $body = $hasNormalizationClosures && 'array' !== $paramType ? ' COMMENTpublic function NAME(PARAM_TYPE $value = []): CLASS|static { $this->_usedProperties[\'PROPERTY\'] = true; @@ -313,10 +318,10 @@ public function NAME(string $VAR, TYPE $VALUE): static 'COMMENT' => $comment, 'PROPERTY' => $property->getName(), 'CLASS' => $childClass->getFqcn(), - 'PARAM_TYPE' => \in_array('mixed', $nodeParameterTypes, true) ? 'mixed' : implode('|', $nodeParameterTypes), + 'PARAM_TYPE' => $paramType, ]); } else { - $body = $hasNormalizationClosures ? ' + $body = $hasNormalizationClosures && 'array' !== $paramType ? ' COMMENTpublic function NAME(string $VAR, PARAM_TYPE $VALUE = []): CLASS|static { if (!\is_array($VALUE)) { @@ -352,7 +357,7 @@ public function NAME(string $VAR, TYPE $VALUE): static 'CLASS' => $childClass->getFqcn(), 'VAR' => '' === $key ? 'key' : $key, 'VALUE' => 'value' === $key ? 'data' : 'value', - 'PARAM_TYPE' => \in_array('mixed', $prototypeParameterTypes, true) ? 'mixed' : implode('|', $prototypeParameterTypes), + 'PARAM_TYPE' => $paramType, ]); } @@ -413,39 +418,39 @@ private function getComment(BaseNode $node): string { $comment = ''; if ('' !== $info = (string) $node->getInfo()) { - $comment .= ' * '.$info."\n"; + $comment .= $info."\n"; } if (!$node instanceof ArrayNode) { foreach ((array) ($node->getExample() ?? []) as $example) { - $comment .= ' * @example '.$example."\n"; + $comment .= '@example '.$example."\n"; } if ('' !== $default = $node->getDefaultValue()) { - $comment .= ' * @default '.(null === $default ? 'null' : var_export($default, true))."\n"; + $comment .= '@default '.(null === $default ? 'null' : var_export($default, true))."\n"; } if ($node instanceof EnumNode) { - $comment .= sprintf(' * @param ParamConfigurator|%s $value', implode('|', array_unique(array_map(fn ($a) => !$a instanceof \UnitEnum ? var_export($a, true) : '\\'.ltrim(var_export($a, true), '\\'), $node->getValues()))))."\n"; + $comment .= \sprintf('@param ParamConfigurator|%s $value', implode('|', array_unique(array_map(fn ($a) => !$a instanceof \UnitEnum ? var_export($a, true) : '\\'.ltrim(var_export($a, true), '\\'), $node->getValues()))))."\n"; } else { $parameterTypes = $this->getParameterTypes($node); - $comment .= ' * @param ParamConfigurator|'.implode('|', $parameterTypes).' $value'."\n"; + $comment .= '@param ParamConfigurator|'.implode('|', $parameterTypes).' $value'."\n"; } } else { foreach ((array) ($node->getExample() ?? []) as $example) { - $comment .= ' * @example '.json_encode($example)."\n"; + $comment .= '@example '.json_encode($example)."\n"; } if ($node->hasDefaultValue() && [] != $default = $node->getDefaultValue()) { - $comment .= ' * @default '.json_encode($default)."\n"; + $comment .= '@default '.json_encode($default)."\n"; } } if ($node->isDeprecated()) { - $comment .= ' * @deprecated '.$node->getDeprecation($node->getName(), $node->getParent()->getName())['message']."\n"; + $comment .= '@deprecated '.$node->getDeprecation($node->getName(), $node->getParent()->getName())['message']."\n"; } - return $comment; + return $comment ? ' * '.str_replace("\n", "\n * ", rtrim($comment, "\n"))."\n" : ''; } /** @@ -579,7 +584,7 @@ public function NAME(string $key, mixed $value): static private function getSubNamespace(ClassBuilder $rootClass): string { - return sprintf('%s\\%s', $rootClass->getNamespace(), substr($rootClass->getName(), 0, -6)); + return \sprintf('%s\\%s', $rootClass->getNamespace(), substr($rootClass->getName(), 0, -6)); } private function hasNormalizationClosures(NodeInterface $node): bool @@ -597,4 +602,9 @@ private function getType(string $classType, bool $hasNormalizationClosures): str { return $classType.($hasNormalizationClosures ? '|scalar' : ''); } + + private function getParamType(array $types, bool $withParamConfigurator = false): string + { + return \in_array('mixed', $types, true) ? 'mixed' : ($withParamConfigurator ? 'ParamConfigurator|' : '').implode('|', $types); + } } diff --git a/app/vendor/symfony/config/Definition/ArrayNode.php b/app/vendor/symfony/config/Definition/ArrayNode.php index 1448220cd..44912da41 100644 --- a/app/vendor/symfony/config/Definition/ArrayNode.php +++ b/app/vendor/symfony/config/Definition/ArrayNode.php @@ -177,7 +177,7 @@ public function hasDefaultValue(): bool public function getDefaultValue(): mixed { if (!$this->hasDefaultValue()) { - throw new \RuntimeException(sprintf('The node at path "%s" has no default value.', $this->getPath())); + throw new \RuntimeException(\sprintf('The node at path "%s" has no default value.', $this->getPath())); } $defaults = []; @@ -205,7 +205,7 @@ public function addChild(NodeInterface $node) throw new \InvalidArgumentException('Child nodes must be named.'); } if (isset($this->children[$name])) { - throw new \InvalidArgumentException(sprintf('A child node named "%s" already exists.', $name)); + throw new \InvalidArgumentException(\sprintf('A child node named "%s" already exists.', $name)); } $this->children[$name] = $node; @@ -218,15 +218,15 @@ public function addChild(NodeInterface $node) protected function finalizeValue(mixed $value): mixed { if (false === $value) { - throw new UnsetKeyException(sprintf('Unsetting key for path "%s", value: %s.', $this->getPath(), json_encode($value))); + throw new UnsetKeyException(\sprintf('Unsetting key for path "%s", value: %s.', $this->getPath(), json_encode($value))); } foreach ($this->children as $name => $child) { if (!\array_key_exists($name, $value)) { if ($child->isRequired()) { - $message = sprintf('The child config "%s" under "%s" must be configured', $name, $this->getPath()); + $message = \sprintf('The child config "%s" under "%s" must be configured', $name, $this->getPath()); if ($child->getInfo()) { - $message .= sprintf(': %s', $child->getInfo()); + $message .= \sprintf(': %s', $child->getInfo()); } else { $message .= '.'; } @@ -264,7 +264,7 @@ protected function finalizeValue(mixed $value): mixed protected function validateType(mixed $value) { if (!\is_array($value) && (!$this->allowFalse || false !== $value)) { - $ex = new InvalidTypeException(sprintf('Invalid type for path "%s". Expected "array", but got "%s"', $this->getPath(), get_debug_type($value))); + $ex = new InvalidTypeException(\sprintf('Invalid type for path "%s". Expected "array", but got "%s"', $this->getPath(), get_debug_type($value))); if ($hint = $this->getInfo()) { $ex->addHint($hint); } @@ -315,13 +315,13 @@ protected function normalizeValue(mixed $value): mixed } } - $msg = sprintf('Unrecognized option%s "%s" under "%s"', 1 === \count($value) ? '' : 's', implode(', ', array_keys($value)), $this->getPath()); + $msg = \sprintf('Unrecognized option%s "%s" under "%s"', 1 === \count($value) ? '' : 's', implode(', ', array_keys($value)), $this->getPath()); if (\count($guesses)) { asort($guesses); - $msg .= sprintf('. Did you mean "%s"?', implode('", "', array_keys($guesses))); + $msg .= \sprintf('. Did you mean "%s"?', implode('", "', array_keys($guesses))); } else { - $msg .= sprintf('. Available option%s %s "%s".', 1 === \count($proposals) ? '' : 's', 1 === \count($proposals) ? 'is' : 'are', implode('", "', $proposals)); + $msg .= \sprintf('. Available option%s %s "%s".', 1 === \count($proposals) ? '' : 's', 1 === \count($proposals) ? 'is' : 'are', implode('", "', $proposals)); } $ex = new InvalidConfigurationException($msg); @@ -370,7 +370,7 @@ protected function mergeValues(mixed $leftSide, mixed $rightSide): mixed // no conflict if (!\array_key_exists($k, $leftSide)) { if (!$this->allowNewKeys) { - $ex = new InvalidConfigurationException(sprintf('You are not allowed to define new elements for path "%s". Please define all elements for this path in one config file. If you are trying to overwrite an element, make sure you redefine it with the same name.', $this->getPath())); + $ex = new InvalidConfigurationException(\sprintf('You are not allowed to define new elements for path "%s". Please define all elements for this path in one config file. If you are trying to overwrite an element, make sure you redefine it with the same name.', $this->getPath())); $ex->setPath($this->getPath()); throw $ex; diff --git a/app/vendor/symfony/config/Definition/BaseNode.php b/app/vendor/symfony/config/Definition/BaseNode.php index 6e2a19227..e8b6bf1ff 100644 --- a/app/vendor/symfony/config/Definition/BaseNode.php +++ b/app/vendor/symfony/config/Definition/BaseNode.php @@ -313,7 +313,7 @@ public function getPath(): string final public function merge(mixed $leftSide, mixed $rightSide): mixed { if (!$this->allowOverwrite) { - throw new ForbiddenOverwriteException(sprintf('Configuration path "%s" cannot be overwritten. You have to define all options for this path, and any of its sub-paths in one configuration section.', $this->getPath())); + throw new ForbiddenOverwriteException(\sprintf('Configuration path "%s" cannot be overwritten. You have to define all options for this path, and any of its sub-paths in one configuration section.', $this->getPath())); } if ($leftSide !== $leftPlaceholders = self::resolvePlaceholderValue($leftSide)) { @@ -432,7 +432,7 @@ final public function finalize(mixed $value): mixed throw $e; } catch (\Exception $e) { - throw new InvalidConfigurationException(sprintf('Invalid configuration for path "%s": ', $this->getPath()).$e->getMessage(), $e->getCode(), $e); + throw new InvalidConfigurationException(\sprintf('Invalid configuration for path "%s": ', $this->getPath()).$e->getMessage(), $e->getCode(), $e); } } @@ -507,7 +507,7 @@ private static function resolvePlaceholderValue(mixed $value): mixed private function doValidateType(mixed $value): void { if (null !== $this->handlingPlaceholder && !$this->allowPlaceholders()) { - $e = new InvalidTypeException(sprintf('A dynamic value is not compatible with a "%s" node type at path "%s".', static::class, $this->getPath())); + $e = new InvalidTypeException(\sprintf('A dynamic value is not compatible with a "%s" node type at path "%s".', static::class, $this->getPath())); $e->setPath($this->getPath()); throw $e; @@ -523,7 +523,7 @@ private function doValidateType(mixed $value): void $validTypes = $this->getValidPlaceholderTypes(); if ($validTypes && array_diff($knownTypes, $validTypes)) { - $e = new InvalidTypeException(sprintf( + $e = new InvalidTypeException(\sprintf( 'Invalid type for path "%s". Expected %s, but got %s.', $this->getPath(), 1 === \count($validTypes) ? '"'.reset($validTypes).'"' : 'one of "'.implode('", "', $validTypes).'"', diff --git a/app/vendor/symfony/config/Definition/BooleanNode.php b/app/vendor/symfony/config/Definition/BooleanNode.php index 7ec903cd6..5d7c573e9 100644 --- a/app/vendor/symfony/config/Definition/BooleanNode.php +++ b/app/vendor/symfony/config/Definition/BooleanNode.php @@ -26,7 +26,7 @@ class BooleanNode extends ScalarNode protected function validateType(mixed $value) { if (!\is_bool($value)) { - $ex = new InvalidTypeException(sprintf('Invalid type for path "%s". Expected "bool", but got "%s".', $this->getPath(), get_debug_type($value))); + $ex = new InvalidTypeException(\sprintf('Invalid type for path "%s". Expected "bool", but got "%s".', $this->getPath(), get_debug_type($value))); if ($hint = $this->getInfo()) { $ex->addHint($hint); } diff --git a/app/vendor/symfony/config/Definition/Builder/ArrayNodeDefinition.php b/app/vendor/symfony/config/Definition/Builder/ArrayNodeDefinition.php index 7a82334ee..ec0e12ab6 100644 --- a/app/vendor/symfony/config/Definition/Builder/ArrayNodeDefinition.php +++ b/app/vendor/symfony/config/Definition/Builder/ArrayNodeDefinition.php @@ -374,7 +374,7 @@ protected function createNode(): NodeInterface if ($this->default) { if (!\is_array($this->defaultValue)) { - throw new \InvalidArgumentException(sprintf('%s: the default value of an array node has to be an array.', $node->getPath())); + throw new \InvalidArgumentException(\sprintf('%s: the default value of an array node has to be an array.', $node->getPath())); } $node->setDefaultValue($this->defaultValue); @@ -434,23 +434,23 @@ protected function validateConcreteNode(ArrayNode $node) $path = $node->getPath(); if (null !== $this->key) { - throw new InvalidDefinitionException(sprintf('->useAttributeAsKey() is not applicable to concrete nodes at path "%s".', $path)); + throw new InvalidDefinitionException(\sprintf('->useAttributeAsKey() is not applicable to concrete nodes at path "%s".', $path)); } if (false === $this->allowEmptyValue) { - throw new InvalidDefinitionException(sprintf('->cannotBeEmpty() is not applicable to concrete nodes at path "%s".', $path)); + throw new InvalidDefinitionException(\sprintf('->cannotBeEmpty() is not applicable to concrete nodes at path "%s".', $path)); } if (true === $this->atLeastOne) { - throw new InvalidDefinitionException(sprintf('->requiresAtLeastOneElement() is not applicable to concrete nodes at path "%s".', $path)); + throw new InvalidDefinitionException(\sprintf('->requiresAtLeastOneElement() is not applicable to concrete nodes at path "%s".', $path)); } if ($this->default) { - throw new InvalidDefinitionException(sprintf('->defaultValue() is not applicable to concrete nodes at path "%s".', $path)); + throw new InvalidDefinitionException(\sprintf('->defaultValue() is not applicable to concrete nodes at path "%s".', $path)); } if (false !== $this->addDefaultChildren) { - throw new InvalidDefinitionException(sprintf('->addDefaultChildrenIfNoneSet() is not applicable to concrete nodes at path "%s".', $path)); + throw new InvalidDefinitionException(\sprintf('->addDefaultChildrenIfNoneSet() is not applicable to concrete nodes at path "%s".', $path)); } } @@ -466,20 +466,20 @@ protected function validatePrototypeNode(PrototypedArrayNode $node) $path = $node->getPath(); if ($this->addDefaults) { - throw new InvalidDefinitionException(sprintf('->addDefaultsIfNotSet() is not applicable to prototype nodes at path "%s".', $path)); + throw new InvalidDefinitionException(\sprintf('->addDefaultsIfNotSet() is not applicable to prototype nodes at path "%s".', $path)); } if (false !== $this->addDefaultChildren) { if ($this->default) { - throw new InvalidDefinitionException(sprintf('A default value and default children might not be used together at path "%s".', $path)); + throw new InvalidDefinitionException(\sprintf('A default value and default children might not be used together at path "%s".', $path)); } if (null !== $this->key && (null === $this->addDefaultChildren || \is_int($this->addDefaultChildren) && $this->addDefaultChildren > 0)) { - throw new InvalidDefinitionException(sprintf('->addDefaultChildrenIfNoneSet() should set default children names as ->useAttributeAsKey() is used at path "%s".', $path)); + throw new InvalidDefinitionException(\sprintf('->addDefaultChildrenIfNoneSet() should set default children names as ->useAttributeAsKey() is used at path "%s".', $path)); } if (null === $this->key && (\is_string($this->addDefaultChildren) || \is_array($this->addDefaultChildren))) { - throw new InvalidDefinitionException(sprintf('->addDefaultChildrenIfNoneSet() might not set default children names as ->useAttributeAsKey() is not used at path "%s".', $path)); + throw new InvalidDefinitionException(\sprintf('->addDefaultChildrenIfNoneSet() might not set default children names as ->useAttributeAsKey() is not used at path "%s".', $path)); } } } @@ -504,7 +504,7 @@ public function find(string $nodePath): NodeDefinition : substr($nodePath, 0, $pathSeparatorPos); if (null === $node = ($this->children[$firstPathSegment] ?? null)) { - throw new \RuntimeException(sprintf('Node with name "%s" does not exist in the current node "%s".', $firstPathSegment, $this->name)); + throw new \RuntimeException(\sprintf('Node with name "%s" does not exist in the current node "%s".', $firstPathSegment, $this->name)); } if (false === $pathSeparatorPos) { diff --git a/app/vendor/symfony/config/Definition/Builder/ExprBuilder.php b/app/vendor/symfony/config/Definition/Builder/ExprBuilder.php index 93cdb49dd..0323428f7 100644 --- a/app/vendor/symfony/config/Definition/Builder/ExprBuilder.php +++ b/app/vendor/symfony/config/Definition/Builder/ExprBuilder.php @@ -196,7 +196,7 @@ public function thenEmptyArray(): static */ public function thenInvalid(string $message): static { - $this->thenPart = static fn ($v) => throw new \InvalidArgumentException(sprintf($message, json_encode($v))); + $this->thenPart = static fn ($v) => throw new \InvalidArgumentException(\sprintf($message, json_encode($v))); return $this; } diff --git a/app/vendor/symfony/config/Definition/Builder/NodeBuilder.php b/app/vendor/symfony/config/Definition/Builder/NodeBuilder.php index 93069d437..d9c03dd9d 100644 --- a/app/vendor/symfony/config/Definition/Builder/NodeBuilder.php +++ b/app/vendor/symfony/config/Definition/Builder/NodeBuilder.php @@ -190,13 +190,13 @@ protected function getNodeClass(string $type): string $type = strtolower($type); if (!isset($this->nodeMapping[$type])) { - throw new \RuntimeException(sprintf('The node type "%s" is not registered.', $type)); + throw new \RuntimeException(\sprintf('The node type "%s" is not registered.', $type)); } $class = $this->nodeMapping[$type]; if (!class_exists($class)) { - throw new \RuntimeException(sprintf('The node class "%s" does not exist.', $class)); + throw new \RuntimeException(\sprintf('The node class "%s" does not exist.', $class)); } return $class; diff --git a/app/vendor/symfony/config/Definition/Builder/NumericNodeDefinition.php b/app/vendor/symfony/config/Definition/Builder/NumericNodeDefinition.php index 890910c95..fc89df55b 100644 --- a/app/vendor/symfony/config/Definition/Builder/NumericNodeDefinition.php +++ b/app/vendor/symfony/config/Definition/Builder/NumericNodeDefinition.php @@ -33,7 +33,7 @@ abstract class NumericNodeDefinition extends ScalarNodeDefinition public function max(int|float $max): static { if (isset($this->min) && $this->min > $max) { - throw new \InvalidArgumentException(sprintf('You cannot define a max(%s) as you already have a min(%s).', $max, $this->min)); + throw new \InvalidArgumentException(\sprintf('You cannot define a max(%s) as you already have a min(%s).', $max, $this->min)); } $this->max = $max; @@ -50,7 +50,7 @@ public function max(int|float $max): static public function min(int|float $min): static { if (isset($this->max) && $this->max < $min) { - throw new \InvalidArgumentException(sprintf('You cannot define a min(%s) as you already have a max(%s).', $min, $this->max)); + throw new \InvalidArgumentException(\sprintf('You cannot define a min(%s) as you already have a max(%s).', $min, $this->max)); } $this->min = $min; diff --git a/app/vendor/symfony/config/Definition/Dumper/XmlReferenceDumper.php b/app/vendor/symfony/config/Definition/Dumper/XmlReferenceDumper.php index aac2d8456..32317b1db 100644 --- a/app/vendor/symfony/config/Definition/Dumper/XmlReferenceDumper.php +++ b/app/vendor/symfony/config/Definition/Dumper/XmlReferenceDumper.php @@ -151,7 +151,7 @@ private function writeNode(NodeInterface $node, int $depth = 0, bool $root = fal if ($child instanceof BaseNode && $child->isDeprecated()) { $deprecation = $child->getDeprecation($child->getName(), $node->getPath()); - $comments[] = sprintf('Deprecated (%s)', ($deprecation['package'] || $deprecation['version'] ? "Since {$deprecation['package']} {$deprecation['version']}: " : '').$deprecation['message']); + $comments[] = \sprintf('Deprecated (%s)', ($deprecation['package'] || $deprecation['version'] ? "Since {$deprecation['package']} {$deprecation['version']}: " : '').$deprecation['message']); } if ($child instanceof EnumNode) { @@ -205,7 +205,7 @@ private function writeNode(NodeInterface $node, int $depth = 0, bool $root = fal $rootOpenTag = '<'.$rootName; if (1 >= ($attributesCount = \count($rootAttributes))) { if (1 === $attributesCount) { - $rootOpenTag .= sprintf(' %s="%s"', current(array_keys($rootAttributes)), $this->writeValue(current($rootAttributes))); + $rootOpenTag .= \sprintf(' %s="%s"', current(array_keys($rootAttributes)), $this->writeValue(current($rootAttributes))); } $rootOpenTag .= $rootIsEmptyTag ? ' />' : '>'; @@ -221,7 +221,7 @@ private function writeNode(NodeInterface $node, int $depth = 0, bool $root = fal $i = 1; foreach ($rootAttributes as $attrName => $attrValue) { - $attr = sprintf('%s="%s"', $attrName, $this->writeValue($attrValue)); + $attr = \sprintf('%s="%s"', $attrName, $this->writeValue($attrValue)); $this->writeLine($attr, $depth + 4); @@ -258,7 +258,7 @@ private function writeLine(string $text, int $indent = 0): void $indent = \strlen($text) + $indent; $format = '%'.$indent.'s'; - $this->reference .= sprintf($format, $text).\PHP_EOL; + $this->reference .= \sprintf($format, $text).\PHP_EOL; } /** diff --git a/app/vendor/symfony/config/Definition/Dumper/YamlReferenceDumper.php b/app/vendor/symfony/config/Definition/Dumper/YamlReferenceDumper.php index 67caa05a5..0813ab1e5 100644 --- a/app/vendor/symfony/config/Definition/Dumper/YamlReferenceDumper.php +++ b/app/vendor/symfony/config/Definition/Dumper/YamlReferenceDumper.php @@ -18,7 +18,6 @@ use Symfony\Component\Config\Definition\NodeInterface; use Symfony\Component\Config\Definition\PrototypedArrayNode; use Symfony\Component\Config\Definition\ScalarNode; -use Symfony\Component\Config\Definition\VariableNode; use Symfony\Component\Yaml\Inline; /** @@ -47,7 +46,7 @@ public function dumpAtPath(ConfigurationInterface $configuration, string $path) foreach (explode('.', $path) as $step) { if (!$node instanceof ArrayNode) { - throw new \UnexpectedValueException(sprintf('Unable to find node at path "%s.%s".', $rootNode->getName(), $path)); + throw new \UnexpectedValueException(\sprintf('Unable to find node at path "%s.%s".', $rootNode->getName(), $path)); } /** @var NodeInterface[] $children */ @@ -61,7 +60,7 @@ public function dumpAtPath(ConfigurationInterface $configuration, string $path) } } - throw new \UnexpectedValueException(sprintf('Unable to find node at path "%s.%s".', $rootNode->getName(), $path)); + throw new \UnexpectedValueException(\sprintf('Unable to find node at path "%s.%s".', $rootNode->getName(), $path)); } return $this->dumpNode($node); @@ -99,19 +98,12 @@ private function writeNode(NodeInterface $node, ?NodeInterface $parentNode = nul $children = $this->getPrototypeChildren($node); } - if (!$children) { - if ($node->hasDefaultValue() && \count($defaultArray = $node->getDefaultValue())) { - $default = ''; - } elseif (!\is_array($example)) { - $default = '[]'; - } + if (!$children && !($node->hasDefaultValue() && \count($defaultArray = $node->getDefaultValue()))) { + $default = '[]'; } } elseif ($node instanceof EnumNode) { $comments[] = 'One of '.$node->getPermissibleValues('; '); $default = $node->hasDefaultValue() ? Inline::dump($node->getDefaultValue()) : '~'; - } elseif (VariableNode::class === $node::class && \is_array($example)) { - // If there is an array example, we are sure we dont need to print a default value - $default = ''; } else { $default = '~'; @@ -138,7 +130,7 @@ private function writeNode(NodeInterface $node, ?NodeInterface $parentNode = nul // deprecated? if ($node instanceof BaseNode && $node->isDeprecated()) { $deprecation = $node->getDeprecation($node->getName(), $parentNode ? $parentNode->getPath() : $node->getPath()); - $comments[] = sprintf('Deprecated (%s)', ($deprecation['package'] || $deprecation['version'] ? "Since {$deprecation['package']} {$deprecation['version']}: " : '').$deprecation['message']); + $comments[] = \sprintf('Deprecated (%s)', ($deprecation['package'] || $deprecation['version'] ? "Since {$deprecation['package']} {$deprecation['version']}: " : '').$deprecation['message']); } // example @@ -150,12 +142,12 @@ private function writeNode(NodeInterface $node, ?NodeInterface $parentNode = nul $comments = \count($comments) ? '# '.implode(', ', $comments) : ''; $key = $prototypedArray ? '-' : $node->getName().':'; - $text = rtrim(sprintf('%-21s%s %s', $key, $default, $comments), ' '); + $text = rtrim(\sprintf('%-21s%s %s', $key, $default, $comments), ' '); if ($node instanceof BaseNode && $info = $node->getInfo()) { $this->writeLine(''); // indenting multi-line info - $info = str_replace("\n", sprintf("\n%".($depth * 4).'s# ', ' '), $info); + $info = str_replace("\n", \sprintf("\n%".($depth * 4).'s# ', ' '), $info); $this->writeLine('# '.$info, $depth * 4); } @@ -179,7 +171,7 @@ private function writeNode(NodeInterface $node, ?NodeInterface $parentNode = nul $this->writeLine('# '.$message.':', $depth * 4 + 4); - $this->writeArray(array_map(Inline::dump(...), $example), $depth + 1); + $this->writeArray(array_map(Inline::dump(...), $example), $depth + 1, true); } if ($children) { @@ -197,10 +189,10 @@ private function writeLine(string $text, int $indent = 0): void $indent = \strlen($text) + $indent; $format = '%'.$indent.'s'; - $this->reference .= sprintf($format, $text)."\n"; + $this->reference .= \sprintf($format, $text)."\n"; } - private function writeArray(array $array, int $depth): void + private function writeArray(array $array, int $depth, bool $asComment = false): void { $isIndexed = array_is_list($array); @@ -211,14 +203,16 @@ private function writeArray(array $array, int $depth): void $val = $value; } + $prefix = $asComment ? '# ' : ''; + if ($isIndexed) { - $this->writeLine('- '.$val, $depth * 4); + $this->writeLine($prefix.'- '.$val, $depth * 4); } else { - $this->writeLine(sprintf('%-20s %s', $key.':', $val), $depth * 4); + $this->writeLine(\sprintf('%s%-20s %s', $prefix, $key.':', $val), $depth * 4); } if (\is_array($value)) { - $this->writeArray($value, $depth + 1); + $this->writeArray($value, $depth + 1, $asComment); } } } diff --git a/app/vendor/symfony/config/Definition/EnumNode.php b/app/vendor/symfony/config/Definition/EnumNode.php index f5acbe906..afe509d9a 100644 --- a/app/vendor/symfony/config/Definition/EnumNode.php +++ b/app/vendor/symfony/config/Definition/EnumNode.php @@ -34,11 +34,11 @@ public function __construct(?string $name, ?NodeInterface $parent = null, array } if (!$value instanceof \UnitEnum) { - throw new \InvalidArgumentException(sprintf('"%s" only supports scalar, enum, or null values, "%s" given.', __CLASS__, get_debug_type($value))); + throw new \InvalidArgumentException(\sprintf('"%s" only supports scalar, enum, or null values, "%s" given.', __CLASS__, get_debug_type($value))); } if ($value::class !== ($enumClass ??= $value::class)) { - throw new \InvalidArgumentException(sprintf('"%s" only supports one type of enum, "%s" and "%s" passed.', __CLASS__, $enumClass, $value::class)); + throw new \InvalidArgumentException(\sprintf('"%s" only supports one type of enum, "%s" and "%s" passed.', __CLASS__, $enumClass, $value::class)); } } @@ -85,7 +85,7 @@ protected function finalizeValue(mixed $value): mixed $value = parent::finalizeValue($value); if (!\in_array($value, $this->values, true)) { - $ex = new InvalidConfigurationException(sprintf('The value %s is not allowed for path "%s". Permissible values: %s', json_encode($value), $this->getPath(), $this->getPermissibleValues(', '))); + $ex = new InvalidConfigurationException(\sprintf('The value %s is not allowed for path "%s". Permissible values: %s', json_encode($value), $this->getPath(), $this->getPermissibleValues(', '))); $ex->setPath($this->getPath()); throw $ex; diff --git a/app/vendor/symfony/config/Definition/FloatNode.php b/app/vendor/symfony/config/Definition/FloatNode.php index ce4193e09..9da243427 100644 --- a/app/vendor/symfony/config/Definition/FloatNode.php +++ b/app/vendor/symfony/config/Definition/FloatNode.php @@ -31,7 +31,7 @@ protected function validateType(mixed $value) } if (!\is_float($value)) { - $ex = new InvalidTypeException(sprintf('Invalid type for path "%s". Expected "float", but got "%s".', $this->getPath(), get_debug_type($value))); + $ex = new InvalidTypeException(\sprintf('Invalid type for path "%s". Expected "float", but got "%s".', $this->getPath(), get_debug_type($value))); if ($hint = $this->getInfo()) { $ex->addHint($hint); } diff --git a/app/vendor/symfony/config/Definition/IntegerNode.php b/app/vendor/symfony/config/Definition/IntegerNode.php index 4a3e3253c..f5a500605 100644 --- a/app/vendor/symfony/config/Definition/IntegerNode.php +++ b/app/vendor/symfony/config/Definition/IntegerNode.php @@ -26,7 +26,7 @@ class IntegerNode extends NumericNode protected function validateType(mixed $value) { if (!\is_int($value)) { - $ex = new InvalidTypeException(sprintf('Invalid type for path "%s". Expected "int", but got "%s".', $this->getPath(), get_debug_type($value))); + $ex = new InvalidTypeException(\sprintf('Invalid type for path "%s". Expected "int", but got "%s".', $this->getPath(), get_debug_type($value))); if ($hint = $this->getInfo()) { $ex->addHint($hint); } diff --git a/app/vendor/symfony/config/Definition/Loader/DefinitionFileLoader.php b/app/vendor/symfony/config/Definition/Loader/DefinitionFileLoader.php index 940b894f7..09147f791 100644 --- a/app/vendor/symfony/config/Definition/Loader/DefinitionFileLoader.php +++ b/app/vendor/symfony/config/Definition/Loader/DefinitionFileLoader.php @@ -81,7 +81,7 @@ private function executeCallback(callable $callback, DefinitionConfigurator $con $reflectionType = $parameter->getType(); if (!$reflectionType instanceof \ReflectionNamedType) { - throw new \InvalidArgumentException(sprintf('Could not resolve argument "$%s" for "%s". You must typehint it (for example with "%s").', $parameter->getName(), $path, DefinitionConfigurator::class)); + throw new \InvalidArgumentException(\sprintf('Could not resolve argument "$%s" for "%s". You must typehint it (for example with "%s").', $parameter->getName(), $path, DefinitionConfigurator::class)); } $arguments[] = match ($reflectionType->getName()) { diff --git a/app/vendor/symfony/config/Definition/NumericNode.php b/app/vendor/symfony/config/Definition/NumericNode.php index 22359fd25..98c99c01e 100644 --- a/app/vendor/symfony/config/Definition/NumericNode.php +++ b/app/vendor/symfony/config/Definition/NumericNode.php @@ -36,10 +36,10 @@ protected function finalizeValue(mixed $value): mixed $errorMsg = null; if (isset($this->min) && $value < $this->min) { - $errorMsg = sprintf('The value %s is too small for path "%s". Should be greater than or equal to %s', $value, $this->getPath(), $this->min); + $errorMsg = \sprintf('The value %s is too small for path "%s". Should be greater than or equal to %s', $value, $this->getPath(), $this->min); } if (isset($this->max) && $value > $this->max) { - $errorMsg = sprintf('The value %s is too big for path "%s". Should be less than or equal to %s', $value, $this->getPath(), $this->max); + $errorMsg = \sprintf('The value %s is too big for path "%s". Should be less than or equal to %s', $value, $this->getPath(), $this->max); } if (isset($errorMsg)) { $ex = new InvalidConfigurationException($errorMsg); diff --git a/app/vendor/symfony/config/Definition/PrototypedArrayNode.php b/app/vendor/symfony/config/Definition/PrototypedArrayNode.php index c105ac1f3..781408b28 100644 --- a/app/vendor/symfony/config/Definition/PrototypedArrayNode.php +++ b/app/vendor/symfony/config/Definition/PrototypedArrayNode.php @@ -168,7 +168,7 @@ public function addChild(NodeInterface $node) protected function finalizeValue(mixed $value): mixed { if (false === $value) { - throw new UnsetKeyException(sprintf('Unsetting key for path "%s", value: %s.', $this->getPath(), json_encode($value))); + throw new UnsetKeyException(\sprintf('Unsetting key for path "%s", value: %s.', $this->getPath(), json_encode($value))); } foreach ($value as $k => $v) { @@ -181,7 +181,7 @@ protected function finalizeValue(mixed $value): mixed } if (\count($value) < $this->minNumberOfElements) { - $ex = new InvalidConfigurationException(sprintf('The path "%s" should have at least %d element(s) defined.', $this->getPath(), $this->minNumberOfElements)); + $ex = new InvalidConfigurationException(\sprintf('The path "%s" should have at least %d element(s) defined.', $this->getPath(), $this->minNumberOfElements)); $ex->setPath($this->getPath()); throw $ex; @@ -206,7 +206,7 @@ protected function normalizeValue(mixed $value): mixed foreach ($value as $k => $v) { if (null !== $this->keyAttribute && \is_array($v)) { if (!isset($v[$this->keyAttribute]) && \is_int($k) && $isList) { - $ex = new InvalidConfigurationException(sprintf('The attribute "%s" must be set for path "%s".', $this->keyAttribute, $this->getPath())); + $ex = new InvalidConfigurationException(\sprintf('The attribute "%s" must be set for path "%s".', $this->keyAttribute, $this->getPath())); $ex->setPath($this->getPath()); throw $ex; @@ -239,7 +239,7 @@ protected function normalizeValue(mixed $value): mixed } if (\array_key_exists($k, $normalized)) { - $ex = new DuplicateKeyException(sprintf('Duplicate key "%s" for path "%s".', $k, $this->getPath())); + $ex = new DuplicateKeyException(\sprintf('Duplicate key "%s" for path "%s".', $k, $this->getPath())); $ex->setPath($this->getPath()); throw $ex; @@ -280,7 +280,7 @@ protected function mergeValues(mixed $leftSide, mixed $rightSide): mixed // no conflict if (!\array_key_exists($k, $leftSide)) { if (!$this->allowNewKeys) { - $ex = new InvalidConfigurationException(sprintf('You are not allowed to define new elements for path "%s". Please define all elements for this path in one config file.', $this->getPath())); + $ex = new InvalidConfigurationException(\sprintf('You are not allowed to define new elements for path "%s". Please define all elements for this path in one config file.', $this->getPath())); $ex->setPath($this->getPath()); throw $ex; diff --git a/app/vendor/symfony/config/Definition/ScalarNode.php b/app/vendor/symfony/config/Definition/ScalarNode.php index e11fa1ee1..3e348672d 100644 --- a/app/vendor/symfony/config/Definition/ScalarNode.php +++ b/app/vendor/symfony/config/Definition/ScalarNode.php @@ -33,7 +33,7 @@ class ScalarNode extends VariableNode protected function validateType(mixed $value) { if (!\is_scalar($value) && null !== $value) { - $ex = new InvalidTypeException(sprintf('Invalid type for path "%s". Expected "scalar", but got "%s".', $this->getPath(), get_debug_type($value))); + $ex = new InvalidTypeException(\sprintf('Invalid type for path "%s". Expected "scalar", but got "%s".', $this->getPath(), get_debug_type($value))); if ($hint = $this->getInfo()) { $ex->addHint($hint); } diff --git a/app/vendor/symfony/config/Definition/VariableNode.php b/app/vendor/symfony/config/Definition/VariableNode.php index 6bdc65b4e..094962aa1 100644 --- a/app/vendor/symfony/config/Definition/VariableNode.php +++ b/app/vendor/symfony/config/Definition/VariableNode.php @@ -80,7 +80,7 @@ protected function finalizeValue(mixed $value): mixed // deny environment variables only when using custom validators // this avoids ever passing an empty value to final validation closures if (!$this->allowEmptyValue && $this->isHandlingPlaceholder() && $this->finalValidationClosures) { - $e = new InvalidConfigurationException(sprintf('The path "%s" cannot contain an environment variable when empty values are not allowed by definition and are validated.', $this->getPath())); + $e = new InvalidConfigurationException(\sprintf('The path "%s" cannot contain an environment variable when empty values are not allowed by definition and are validated.', $this->getPath())); if ($hint = $this->getInfo()) { $e->addHint($hint); } @@ -90,7 +90,7 @@ protected function finalizeValue(mixed $value): mixed } if (!$this->allowEmptyValue && $this->isValueEmpty($value)) { - $ex = new InvalidConfigurationException(sprintf('The path "%s" cannot contain an empty value, but got %s.', $this->getPath(), json_encode($value))); + $ex = new InvalidConfigurationException(\sprintf('The path "%s" cannot contain an empty value, but got %s.', $this->getPath(), json_encode($value))); if ($hint = $this->getInfo()) { $ex->addHint($hint); } diff --git a/app/vendor/symfony/config/Exception/FileLoaderImportCircularReferenceException.php b/app/vendor/symfony/config/Exception/FileLoaderImportCircularReferenceException.php index 2d2a4de00..d39bde046 100644 --- a/app/vendor/symfony/config/Exception/FileLoaderImportCircularReferenceException.php +++ b/app/vendor/symfony/config/Exception/FileLoaderImportCircularReferenceException.php @@ -20,7 +20,7 @@ class FileLoaderImportCircularReferenceException extends LoaderLoadException { public function __construct(array $resources, int $code = 0, ?\Throwable $previous = null) { - $message = sprintf('Circular reference detected in "%s" ("%s" > "%s").', $this->varToString($resources[0]), implode('" > "', $resources), $resources[0]); + $message = \sprintf('Circular reference detected in "%s" ("%s" > "%s").', $this->varToString($resources[0]), implode('" > "', $resources), $resources[0]); \Exception::__construct($message, $code, $previous); } diff --git a/app/vendor/symfony/config/Exception/LoaderLoadException.php b/app/vendor/symfony/config/Exception/LoaderLoadException.php index 2b40688a5..89f7fd719 100644 --- a/app/vendor/symfony/config/Exception/LoaderLoadException.php +++ b/app/vendor/symfony/config/Exception/LoaderLoadException.php @@ -31,7 +31,7 @@ public function __construct(mixed $resource, ?string $sourceResource = null, int try { $resource = json_encode($resource, \JSON_THROW_ON_ERROR); } catch (\JsonException) { - $resource = sprintf('resource of type "%s"', get_debug_type($resource)); + $resource = \sprintf('resource of type "%s"', get_debug_type($resource)); } } @@ -42,35 +42,35 @@ public function __construct(mixed $resource, ?string $sourceResource = null, int // Trim the trailing period of the previous message. We only want 1 period remove so no rtrim... if (str_ends_with($previous->getMessage(), '.')) { $trimmedMessage = substr($previous->getMessage(), 0, -1); - $message .= sprintf('%s', $trimmedMessage).' in '; + $message .= \sprintf('%s', $trimmedMessage).' in '; } else { - $message .= sprintf('%s', $previous->getMessage()).' in '; + $message .= \sprintf('%s', $previous->getMessage()).' in '; } $message .= $resource.' '; // show tweaked trace to complete the human readable sentence if (null === $sourceResource) { - $message .= sprintf('(which is loaded in resource "%s")', $resource); + $message .= \sprintf('(which is loaded in resource "%s")', $resource); } else { - $message .= sprintf('(which is being imported from "%s")', $sourceResource); + $message .= \sprintf('(which is being imported from "%s")', $sourceResource); } $message .= '.'; // if there's no previous message, present it the default way } elseif (null === $sourceResource) { - $message .= sprintf('Cannot load resource "%s".', $resource); + $message .= \sprintf('Cannot load resource "%s".', $resource); } else { - $message .= sprintf('Cannot import resource "%s" from "%s".', $resource, $sourceResource); + $message .= \sprintf('Cannot import resource "%s" from "%s".', $resource, $sourceResource); } // Is the resource located inside a bundle? if ('@' === $resource[0]) { $parts = explode(\DIRECTORY_SEPARATOR, $resource); $bundle = substr($parts[0], 1); - $message .= sprintf(' Make sure the "%s" bundle is correctly registered and loaded in the application kernel class.', $bundle); - $message .= sprintf(' If the bundle is registered, make sure the bundle path "%s" is not empty.', $resource); + $message .= \sprintf(' Make sure the "%s" bundle is correctly registered and loaded in the application kernel class.', $bundle); + $message .= \sprintf(' If the bundle is registered, make sure the bundle path "%s" is not empty.', $resource); } elseif (null !== $type) { - $message .= sprintf(' Make sure there is a loader supporting the "%s" type.', $type); + $message .= \sprintf(' Make sure there is a loader supporting the "%s" type.', $type); } parent::__construct($message, $code, $previous); @@ -82,20 +82,20 @@ public function __construct(mixed $resource, ?string $sourceResource = null, int protected function varToString(mixed $var) { if (\is_object($var)) { - return sprintf('Object(%s)', $var::class); + return \sprintf('Object(%s)', $var::class); } if (\is_array($var)) { $a = []; foreach ($var as $k => $v) { - $a[] = sprintf('%s => %s', $k, $this->varToString($v)); + $a[] = \sprintf('%s => %s', $k, $this->varToString($v)); } - return sprintf('Array(%s)', implode(', ', $a)); + return \sprintf('Array(%s)', implode(', ', $a)); } if (\is_resource($var)) { - return sprintf('Resource(%s)', get_resource_type($var)); + return \sprintf('Resource(%s)', get_resource_type($var)); } if (null === $var) { diff --git a/app/vendor/symfony/config/FileLocator.php b/app/vendor/symfony/config/FileLocator.php index 99c35bd26..6e08a5fb0 100644 --- a/app/vendor/symfony/config/FileLocator.php +++ b/app/vendor/symfony/config/FileLocator.php @@ -43,7 +43,7 @@ public function locate(string $name, ?string $currentPath = null, bool $first = if ($this->isAbsolutePath($name)) { if (!file_exists($name)) { - throw new FileLocatorFileNotFoundException(sprintf('The file "%s" does not exist.', $name), 0, null, [$name]); + throw new FileLocatorFileNotFoundException(\sprintf('The file "%s" does not exist.', $name), 0, null, [$name]); } return $name; @@ -70,7 +70,7 @@ public function locate(string $name, ?string $currentPath = null, bool $first = } if (!$filepaths) { - throw new FileLocatorFileNotFoundException(sprintf('The file "%s" does not exist (in: "%s").', $name, implode('", "', $paths)), 0, null, $notfound); + throw new FileLocatorFileNotFoundException(\sprintf('The file "%s" does not exist (in: "%s").', $name, implode('", "', $paths)), 0, null, $notfound); } return $filepaths; @@ -86,7 +86,8 @@ private function isAbsolutePath(string $file): bool && ':' === $file[1] && ('\\' === $file[2] || '/' === $file[2]) ) - || null !== parse_url($file, \PHP_URL_SCHEME) + || parse_url($file, \PHP_URL_SCHEME) + || str_starts_with($file, 'phar:///') // "parse_url()" doesn't handle absolute phar path, despite being valid ) { return true; } diff --git a/app/vendor/symfony/config/FileLocatorInterface.php b/app/vendor/symfony/config/FileLocatorInterface.php index 755cf018a..32d10d0cb 100644 --- a/app/vendor/symfony/config/FileLocatorInterface.php +++ b/app/vendor/symfony/config/FileLocatorInterface.php @@ -27,10 +27,10 @@ interface FileLocatorInterface * * @return string|string[] The full path to the file or an array of file paths * + * @psalm-return ($first is true ? string : string[]) + * * @throws \InvalidArgumentException If $name is empty * @throws FileLocatorFileNotFoundException If a file is not found - * - * @psalm-return ($first is true ? string : string[]) */ public function locate(string $name, ?string $currentPath = null, bool $first = true); } diff --git a/app/vendor/symfony/config/Resource/ClassExistenceResource.php b/app/vendor/symfony/config/Resource/ClassExistenceResource.php index eab04b8d0..aa9177d29 100644 --- a/app/vendor/symfony/config/Resource/ClassExistenceResource.php +++ b/app/vendor/symfony/config/Resource/ClassExistenceResource.php @@ -158,10 +158,10 @@ public static function throwOnRequiredClass(string $class, ?\Exception $previous throw $previous; } - $message = sprintf('Class "%s" not found.', $class); + $message = \sprintf('Class "%s" not found.', $class); if ($class !== (self::$autoloadedClass ?? $class)) { - $message = substr_replace($message, sprintf(' while loading "%s"', self::$autoloadedClass), -1, 0); + $message = substr_replace($message, \sprintf(' while loading "%s"', self::$autoloadedClass), -1, 0); } if (null !== $previous) { diff --git a/app/vendor/symfony/config/Resource/DirectoryResource.php b/app/vendor/symfony/config/Resource/DirectoryResource.php index df486a085..dd43742b7 100644 --- a/app/vendor/symfony/config/Resource/DirectoryResource.php +++ b/app/vendor/symfony/config/Resource/DirectoryResource.php @@ -35,7 +35,7 @@ public function __construct(string $resource, ?string $pattern = null) $this->pattern = $pattern; if (false === $resolvedResource || !is_dir($resolvedResource)) { - throw new \InvalidArgumentException(sprintf('The directory "%s" does not exist.', $resource)); + throw new \InvalidArgumentException(\sprintf('The directory "%s" does not exist.', $resource)); } $this->resource = $resolvedResource; diff --git a/app/vendor/symfony/config/Resource/FileResource.php b/app/vendor/symfony/config/Resource/FileResource.php index 6e8f9bdb3..44e5bbc57 100644 --- a/app/vendor/symfony/config/Resource/FileResource.php +++ b/app/vendor/symfony/config/Resource/FileResource.php @@ -34,7 +34,7 @@ public function __construct(string $resource) $resolvedResource = realpath($resource) ?: (file_exists($resource) ? $resource : false); if (false === $resolvedResource) { - throw new \InvalidArgumentException(sprintf('The file "%s" does not exist.', $resource)); + throw new \InvalidArgumentException(\sprintf('The file "%s" does not exist.', $resource)); } $this->resource = $resolvedResource; diff --git a/app/vendor/symfony/config/Resource/GlobResource.php b/app/vendor/symfony/config/Resource/GlobResource.php index 2aedc84b3..3e381a411 100644 --- a/app/vendor/symfony/config/Resource/GlobResource.php +++ b/app/vendor/symfony/config/Resource/GlobResource.php @@ -53,7 +53,7 @@ public function __construct(string $prefix, string $pattern, bool $recursive, bo $this->globBrace = \defined('GLOB_BRACE') ? \GLOB_BRACE : 0; if (false === $resolvedPrefix) { - throw new \InvalidArgumentException(sprintf('The path "%s" does not exist.', $prefix)); + throw new \InvalidArgumentException(\sprintf('The path "%s" does not exist.', $prefix)); } $this->prefix = $resolvedPrefix; diff --git a/app/vendor/symfony/config/Resource/ReflectionClassResource.php b/app/vendor/symfony/config/Resource/ReflectionClassResource.php index dbd47e66d..cfd96135d 100644 --- a/app/vendor/symfony/config/Resource/ReflectionClassResource.php +++ b/app/vendor/symfony/config/Resource/ReflectionClassResource.php @@ -123,7 +123,7 @@ private function generateSignature(\ReflectionClass $class): iterable yield print_r($attributes, true); $attributes = []; - yield $class->getDocComment(); + yield $class->getDocComment() ?: ''; yield (int) $class->isFinal(); yield (int) $class->isAbstract(); @@ -135,6 +135,14 @@ private function generateSignature(\ReflectionClass $class): iterable yield print_r($class->getConstants(), true); } + foreach ($class->getReflectionConstants() as $constant) { + foreach ($constant->getAttributes() as $a) { + $attributes[] = [$a->getName(), (string) $a]; + } + yield $constant->name.print_r($attributes, true); + $attributes = []; + } + if (!$class->isInterface()) { $defaults = $class->getDefaultProperties(); @@ -145,7 +153,7 @@ private function generateSignature(\ReflectionClass $class): iterable yield print_r($attributes, true); $attributes = []; - yield $p->getDocComment(); + yield $p->getDocComment() ?: ''; yield $p->isDefault() ? '' : ''; yield $p->isPublic() ? 'public' : 'protected'; yield $p->isStatic() ? 'static' : ''; diff --git a/app/vendor/symfony/config/Util/XmlUtils.php b/app/vendor/symfony/config/Util/XmlUtils.php index eb6f0f51a..7a6ef9acc 100644 --- a/app/vendor/symfony/config/Util/XmlUtils.php +++ b/app/vendor/symfony/config/Util/XmlUtils.php @@ -84,7 +84,7 @@ public static function parse(string $content, string|callable|null $schemaOrCall } else { libxml_use_internal_errors($internalErrors); - throw new XmlParsingException(sprintf('Invalid XSD file: "%s".', $schemaOrCallable)); + throw new XmlParsingException(\sprintf('Invalid XSD file: "%s".', $schemaOrCallable)); } if (!$valid) { @@ -115,23 +115,23 @@ public static function parse(string $content, string|callable|null $schemaOrCall public static function loadFile(string $file, string|callable|null $schemaOrCallable = null): \DOMDocument { if (!is_file($file)) { - throw new \InvalidArgumentException(sprintf('Resource "%s" is not a file.', $file)); + throw new \InvalidArgumentException(\sprintf('Resource "%s" is not a file.', $file)); } if (!is_readable($file)) { - throw new \InvalidArgumentException(sprintf('File "%s" is not readable.', $file)); + throw new \InvalidArgumentException(\sprintf('File "%s" is not readable.', $file)); } $content = @file_get_contents($file); if ('' === trim($content)) { - throw new \InvalidArgumentException(sprintf('File "%s" does not contain valid XML, it is empty.', $file)); + throw new \InvalidArgumentException(\sprintf('File "%s" does not contain valid XML, it is empty.', $file)); } try { return static::parse($content, $schemaOrCallable); } catch (InvalidXmlException $e) { - throw new XmlParsingException(sprintf('The XML file "%s" is not valid.', $file), 0, $e->getPrevious()); + throw new XmlParsingException(\sprintf('The XML file "%s" is not valid.', $file), 0, $e->getPrevious()); } } @@ -245,7 +245,7 @@ protected static function getXmlErrors(bool $internalErrors) { $errors = []; foreach (libxml_get_errors() as $error) { - $errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)', + $errors[] = \sprintf('[%s %s] %s (in %s - line %d, column %d)', \LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR', $error->code, trim($error->message), diff --git a/app/vendor/symfony/console/Application.php b/app/vendor/symfony/console/Application.php index b97d0872f..c18d482b4 100644 --- a/app/vendor/symfony/console/Application.php +++ b/app/vendor/symfony/console/Application.php @@ -169,9 +169,9 @@ public function run(?InputInterface $input = null, ?OutputInterface $output = nu } } - $this->configureIO($input, $output); - try { + $this->configureIO($input, $output); + $exitCode = $this->doRun($input, $output); } catch (\Throwable $e) { if ($e instanceof \Exception && !$this->catchExceptions) { @@ -270,9 +270,9 @@ public function doRun(InputInterface $input, OutputInterface $output) $style = new SymfonyStyle($input, $output); $output->writeln(''); - $formattedBlock = (new FormatterHelper())->formatBlock(sprintf('Command "%s" is not defined.', $name), 'error', true); + $formattedBlock = (new FormatterHelper())->formatBlock(\sprintf('Command "%s" is not defined.', $name), 'error', true); $output->writeln($formattedBlock); - if (!$style->confirm(sprintf('Do you want to run "%s" instead? ', $alternative), false)) { + if (!$style->confirm(\sprintf('Do you want to run "%s" instead? ', $alternative), false)) { if (null !== $this->dispatcher) { $event = new ConsoleErrorEvent($input, $output, $e); $this->dispatcher->dispatch($event, ConsoleEvents::ERROR); @@ -502,7 +502,7 @@ public function getLongVersion() { if ('UNKNOWN' !== $this->getName()) { if ('UNKNOWN' !== $this->getVersion()) { - return sprintf('%s %s', $this->getName(), $this->getVersion()); + return \sprintf('%s %s', $this->getName(), $this->getVersion()); } return $this->getName(); @@ -561,7 +561,7 @@ public function add(Command $command) } if (!$command->getName()) { - throw new LogicException(sprintf('The command defined in "%s" cannot have an empty name.', get_debug_type($command))); + throw new LogicException(\sprintf('The command defined in "%s" cannot have an empty name.', get_debug_type($command))); } $this->commands[$command->getName()] = $command; @@ -585,12 +585,12 @@ public function get(string $name) $this->init(); if (!$this->has($name)) { - throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $name)); + throw new CommandNotFoundException(\sprintf('The command "%s" does not exist.', $name)); } // When the command has a different name than the one used at the command loader level if (!isset($this->commands[$name])) { - throw new CommandNotFoundException(sprintf('The "%s" command cannot be found because it is registered under multiple names. Make sure you don\'t set a different name via constructor or "setName()".', $name)); + throw new CommandNotFoundException(\sprintf('The "%s" command cannot be found because it is registered under multiple names. Make sure you don\'t set a different name via constructor or "setName()".', $name)); } $command = $this->commands[$name]; @@ -654,7 +654,7 @@ public function findNamespace(string $namespace): string $namespaces = preg_grep('{^'.$expr.'}', $allNamespaces); if (empty($namespaces)) { - $message = sprintf('There are no commands defined in the "%s" namespace.', $namespace); + $message = \sprintf('There are no commands defined in the "%s" namespace.', $namespace); if ($alternatives = $this->findAlternatives($namespace, $allNamespaces)) { if (1 == \count($alternatives)) { @@ -671,7 +671,7 @@ public function findNamespace(string $namespace): string $exact = \in_array($namespace, $namespaces, true); if (\count($namespaces) > 1 && !$exact) { - throw new NamespaceNotFoundException(sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces)); + throw new NamespaceNotFoundException(\sprintf("The namespace \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $namespace, $this->getAbbreviationSuggestions(array_values($namespaces))), array_values($namespaces)); } return $exact ? $namespace : reset($namespaces); @@ -720,7 +720,7 @@ public function find(string $name) $this->findNamespace(substr($name, 0, $pos)); } - $message = sprintf('Command "%s" is not defined.', $name); + $message = \sprintf('Command "%s" is not defined.', $name); if ($alternatives = $this->findAlternatives($name, $allCommands)) { // remove hidden commands @@ -775,14 +775,14 @@ public function find(string $name) if (\count($commands) > 1) { $suggestions = $this->getAbbreviationSuggestions(array_filter($abbrevs)); - throw new CommandNotFoundException(sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $name, $suggestions), array_values($commands)); + throw new CommandNotFoundException(\sprintf("Command \"%s\" is ambiguous.\nDid you mean one of these?\n%s.", $name, $suggestions), array_values($commands)); } } $command = $this->get(reset($commands)); if ($command->isHidden()) { - throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $name)); + throw new CommandNotFoundException(\sprintf('The command "%s" does not exist.', $name)); } return $command; @@ -857,7 +857,7 @@ public function renderThrowable(\Throwable $e, OutputInterface $output): void $this->doRenderThrowable($e, $output); if (null !== $this->runningCommand) { - $output->writeln(sprintf('%s', OutputFormatter::escape(sprintf($this->runningCommand->getSynopsis(), $this->getName()))), OutputInterface::VERBOSITY_QUIET); + $output->writeln(\sprintf('%s', OutputFormatter::escape(\sprintf($this->runningCommand->getSynopsis(), $this->getName()))), OutputInterface::VERBOSITY_QUIET); $output->writeln('', OutputInterface::VERBOSITY_QUIET); } } @@ -868,14 +868,14 @@ protected function doRenderThrowable(\Throwable $e, OutputInterface $output): vo $message = trim($e->getMessage()); if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { $class = get_debug_type($e); - $title = sprintf(' [%s%s] ', $class, 0 !== ($code = $e->getCode()) ? ' ('.$code.')' : ''); + $title = \sprintf(' [%s%s] ', $class, 0 !== ($code = $e->getCode()) ? ' ('.$code.')' : ''); $len = Helper::width($title); } else { $len = 0; } if (str_contains($message, "@anonymous\0")) { - $message = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', fn ($m) => class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0], $message); + $message = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)?[0-9a-fA-F]++/', fn ($m) => class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0], $message); } $width = $this->terminal->getWidth() ? $this->terminal->getWidth() - 1 : \PHP_INT_MAX; @@ -892,14 +892,14 @@ protected function doRenderThrowable(\Throwable $e, OutputInterface $output): vo $messages = []; if (!$e instanceof ExceptionInterface || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { - $messages[] = sprintf('%s', OutputFormatter::escape(sprintf('In %s line %s:', basename($e->getFile()) ?: 'n/a', $e->getLine() ?: 'n/a'))); + $messages[] = \sprintf('%s', OutputFormatter::escape(\sprintf('In %s line %s:', basename($e->getFile()) ?: 'n/a', $e->getLine() ?: 'n/a'))); } - $messages[] = $emptyLine = sprintf('%s', str_repeat(' ', $len)); + $messages[] = $emptyLine = \sprintf('%s', str_repeat(' ', $len)); if ('' === $message || OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) { - $messages[] = sprintf('%s%s', $title, str_repeat(' ', max(0, $len - Helper::width($title)))); + $messages[] = \sprintf('%s%s', $title, str_repeat(' ', max(0, $len - Helper::width($title)))); } foreach ($lines as $line) { - $messages[] = sprintf(' %s %s', OutputFormatter::escape($line[0]), str_repeat(' ', $len - $line[1])); + $messages[] = \sprintf(' %s %s', OutputFormatter::escape($line[0]), str_repeat(' ', $len - $line[1])); } $messages[] = $emptyLine; $messages[] = ''; @@ -926,7 +926,7 @@ protected function doRenderThrowable(\Throwable $e, OutputInterface $output): vo $file = $trace[$i]['file'] ?? 'n/a'; $line = $trace[$i]['line'] ?? 'n/a'; - $output->writeln(sprintf(' %s%s at %s:%s', $class, $function ? $type.$function.'()' : '', $file, $line), OutputInterface::VERBOSITY_QUIET); + $output->writeln(\sprintf(' %s%s at %s:%s', $class, $function ? $type.$function.'()' : '', $file, $line), OutputInterface::VERBOSITY_QUIET); } $output->writeln('', OutputInterface::VERBOSITY_QUIET); @@ -1278,7 +1278,7 @@ private function splitStringByWidth(string $string, int $width): array foreach (preg_split('//u', $m[0]) as $char) { // test if $char could be appended to current line - if (mb_strwidth($line.$char, 'utf8') <= $width) { + if (Helper::width($line.$char) <= $width) { $line .= $char; continue; } diff --git a/app/vendor/symfony/console/CI/GithubActionReporter.php b/app/vendor/symfony/console/CI/GithubActionReporter.php index 2cae6fd8b..28112c2a2 100644 --- a/app/vendor/symfony/console/CI/GithubActionReporter.php +++ b/app/vendor/symfony/console/CI/GithubActionReporter.php @@ -89,11 +89,11 @@ private function log(string $type, string $message, ?string $file = null, ?int $ if (!$file) { // No file provided, output the message solely: - $this->output->writeln(sprintf('::%s::%s', $type, $message)); + $this->output->writeln(\sprintf('::%s::%s', $type, $message)); return; } - $this->output->writeln(sprintf('::%s file=%s,line=%s,col=%s::%s', $type, strtr($file, self::ESCAPED_PROPERTIES), strtr($line ?? 1, self::ESCAPED_PROPERTIES), strtr($col ?? 0, self::ESCAPED_PROPERTIES), $message)); + $this->output->writeln(\sprintf('::%s file=%s,line=%s,col=%s::%s', $type, strtr($file, self::ESCAPED_PROPERTIES), strtr($line ?? 1, self::ESCAPED_PROPERTIES), strtr($col ?? 0, self::ESCAPED_PROPERTIES), $message)); } } diff --git a/app/vendor/symfony/console/Color.php b/app/vendor/symfony/console/Color.php index 60ed046a6..b1914c19a 100644 --- a/app/vendor/symfony/console/Color.php +++ b/app/vendor/symfony/console/Color.php @@ -60,7 +60,7 @@ public function __construct(string $foreground = '', string $background = '', ar foreach ($options as $option) { if (!isset(self::AVAILABLE_OPTIONS[$option])) { - throw new InvalidArgumentException(sprintf('Invalid option specified: "%s". Expected one of (%s).', $option, implode(', ', array_keys(self::AVAILABLE_OPTIONS)))); + throw new InvalidArgumentException(\sprintf('Invalid option specified: "%s". Expected one of (%s).', $option, implode(', ', array_keys(self::AVAILABLE_OPTIONS)))); } $this->options[$option] = self::AVAILABLE_OPTIONS[$option]; @@ -88,7 +88,7 @@ public function set(): string return ''; } - return sprintf("\033[%sm", implode(';', $setCodes)); + return \sprintf("\033[%sm", implode(';', $setCodes)); } public function unset(): string @@ -107,7 +107,7 @@ public function unset(): string return ''; } - return sprintf("\033[%sm", implode(';', $unsetCodes)); + return \sprintf("\033[%sm", implode(';', $unsetCodes)); } private function parseColor(string $color, bool $background = false): string @@ -128,6 +128,6 @@ private function parseColor(string $color, bool $background = false): string return ($background ? '10' : '9').self::BRIGHT_COLORS[$color]; } - throw new InvalidArgumentException(sprintf('Invalid "%s" color; expected one of (%s).', $color, implode(', ', array_merge(array_keys(self::COLORS), array_keys(self::BRIGHT_COLORS))))); + throw new InvalidArgumentException(\sprintf('Invalid "%s" color; expected one of (%s).', $color, implode(', ', array_merge(array_keys(self::COLORS), array_keys(self::BRIGHT_COLORS))))); } } diff --git a/app/vendor/symfony/console/Command/Command.php b/app/vendor/symfony/console/Command/Command.php index 9f9cb2f53..3ede6ca6b 100644 --- a/app/vendor/symfony/console/Command/Command.php +++ b/app/vendor/symfony/console/Command/Command.php @@ -326,7 +326,7 @@ public function run(InputInterface $input, OutputInterface $output): int $statusCode = $this->execute($input, $output); if (!\is_int($statusCode)) { - throw new \TypeError(sprintf('Return value of "%s::execute()" must be of the type int, "%s" returned.', static::class, get_debug_type($statusCode))); + throw new \TypeError(\sprintf('Return value of "%s::execute()" must be of the type int, "%s" returned.', static::class, get_debug_type($statusCode))); } } @@ -446,7 +446,7 @@ public function getDefinition(): InputDefinition */ public function getNativeDefinition(): InputDefinition { - return $this->definition ?? throw new LogicException(sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', static::class)); + return $this->definition ?? throw new LogicException(\sprintf('Command class "%s" is not correctly initialized. You probably forgot to call the parent constructor.', static::class)); } /** @@ -464,7 +464,7 @@ public function addArgument(string $name, ?int $mode = null, string $description { $suggestedValues = 5 <= \func_num_args() ? func_get_arg(4) : []; if (!\is_array($suggestedValues) && !$suggestedValues instanceof \Closure) { - throw new \TypeError(sprintf('Argument 5 passed to "%s()" must be array or \Closure, "%s" given.', __METHOD__, get_debug_type($suggestedValues))); + throw new \TypeError(\sprintf('Argument 5 passed to "%s()" must be array or \Closure, "%s" given.', __METHOD__, get_debug_type($suggestedValues))); } $this->definition->addArgument(new InputArgument($name, $mode, $description, $default, $suggestedValues)); $this->fullDefinition?->addArgument(new InputArgument($name, $mode, $description, $default, $suggestedValues)); @@ -488,7 +488,7 @@ public function addOption(string $name, string|array|null $shortcut = null, ?int { $suggestedValues = 6 <= \func_num_args() ? func_get_arg(5) : []; if (!\is_array($suggestedValues) && !$suggestedValues instanceof \Closure) { - throw new \TypeError(sprintf('Argument 5 passed to "%s()" must be array or \Closure, "%s" given.', __METHOD__, get_debug_type($suggestedValues))); + throw new \TypeError(\sprintf('Argument 5 passed to "%s()" must be array or \Closure, "%s" given.', __METHOD__, get_debug_type($suggestedValues))); } $this->definition->addOption(new InputOption($name, $shortcut, $mode, $description, $default, $suggestedValues)); $this->fullDefinition?->addOption(new InputOption($name, $shortcut, $mode, $description, $default, $suggestedValues)); @@ -662,7 +662,7 @@ public function getSynopsis(bool $short = false): string $key = $short ? 'short' : 'long'; if (!isset($this->synopsis[$key])) { - $this->synopsis[$key] = trim(sprintf('%s %s', $this->name, $this->definition->getSynopsis($short))); + $this->synopsis[$key] = trim(\sprintf('%s %s', $this->name, $this->definition->getSynopsis($short))); } return $this->synopsis[$key]; @@ -676,7 +676,7 @@ public function getSynopsis(bool $short = false): string public function addUsage(string $usage): static { if (!str_starts_with($usage, $this->name)) { - $usage = sprintf('%s %s', $this->name, $usage); + $usage = \sprintf('%s %s', $this->name, $usage); } $this->usages[] = $usage; @@ -703,7 +703,7 @@ public function getUsages(): array public function getHelper(string $name): mixed { if (null === $this->helperSet) { - throw new LogicException(sprintf('Cannot retrieve helper "%s" because there is no HelperSet defined. Did you forget to add your command to the application or to set the application on the command using the setApplication() method? You can also set the HelperSet directly using the setHelperSet() method.', $name)); + throw new LogicException(\sprintf('Cannot retrieve helper "%s" because there is no HelperSet defined. Did you forget to add your command to the application or to set the application on the command using the setApplication() method? You can also set the HelperSet directly using the setHelperSet() method.', $name)); } return $this->helperSet->get($name); @@ -719,7 +719,7 @@ public function getHelper(string $name): mixed private function validateName(string $name): void { if (!preg_match('/^[^\:]++(\:[^\:]++)*$/', $name)) { - throw new InvalidArgumentException(sprintf('Command name "%s" is invalid.', $name)); + throw new InvalidArgumentException(\sprintf('Command name "%s" is invalid.', $name)); } } } diff --git a/app/vendor/symfony/console/Command/CompleteCommand.php b/app/vendor/symfony/console/Command/CompleteCommand.php index 23be5577b..33f7f93c8 100644 --- a/app/vendor/symfony/console/Command/CompleteCommand.php +++ b/app/vendor/symfony/console/Command/CompleteCommand.php @@ -85,7 +85,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int // "symfony" must be kept for compat with the shell scripts generated by Symfony Console 5.4 - 6.1 $version = $input->getOption('symfony') ? '1' : $input->getOption('api-version'); if ($version && version_compare($version, self::COMPLETION_API_VERSION, '<')) { - $message = sprintf('Completion script version is not supported ("%s" given, ">=%s" required).', $version, self::COMPLETION_API_VERSION); + $message = \sprintf('Completion script version is not supported ("%s" given, ">=%s" required).', $version, self::COMPLETION_API_VERSION); $this->log($message); $output->writeln($message.' Install the Symfony completion script again by using the "completion" command.'); @@ -99,7 +99,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int } if (!$completionOutput = $this->completionOutputs[$shell] ?? false) { - throw new \RuntimeException(sprintf('Shell completion is not supported for your shell: "%s" (supported: "%s").', $shell, implode('", "', array_keys($this->completionOutputs)))); + throw new \RuntimeException(\sprintf('Shell completion is not supported for your shell: "%s" (supported: "%s").', $shell, implode('", "', array_keys($this->completionOutputs)))); } $completionInput = $this->createCompletionInput($input); diff --git a/app/vendor/symfony/console/Command/DumpCompletionCommand.php b/app/vendor/symfony/console/Command/DumpCompletionCommand.php index 51b613a14..571425b88 100644 --- a/app/vendor/symfony/console/Command/DumpCompletionCommand.php +++ b/app/vendor/symfony/console/Command/DumpCompletionCommand.php @@ -108,9 +108,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int $output = $output->getErrorOutput(); } if ($shell) { - $output->writeln(sprintf('Detected shell "%s", which is not supported by Symfony shell completion (supported shells: "%s").', $shell, implode('", "', $supportedShells))); + $output->writeln(\sprintf('Detected shell "%s", which is not supported by Symfony shell completion (supported shells: "%s").', $shell, implode('", "', $supportedShells))); } else { - $output->writeln(sprintf('Shell not detected, Symfony shell completion only supports "%s").', implode('", "', $supportedShells))); + $output->writeln(\sprintf('Shell not detected, Symfony shell completion only supports "%s").', implode('", "', $supportedShells))); } return 2; diff --git a/app/vendor/symfony/console/Command/SignalableCommandInterface.php b/app/vendor/symfony/console/Command/SignalableCommandInterface.php index f8eb8e522..74d59b086 100644 --- a/app/vendor/symfony/console/Command/SignalableCommandInterface.php +++ b/app/vendor/symfony/console/Command/SignalableCommandInterface.php @@ -30,5 +30,5 @@ public function getSubscribedSignals(): array; * * @return int|false The exit code to return or false to continue the normal execution */ - public function handleSignal(int $signal, /* int|false $previousExitCode = 0 */); + public function handleSignal(int $signal/* , int|false $previousExitCode = 0 */); } diff --git a/app/vendor/symfony/console/Command/TraceableCommand.php b/app/vendor/symfony/console/Command/TraceableCommand.php index 9ffb68da3..9df467b0d 100644 --- a/app/vendor/symfony/console/Command/TraceableCommand.php +++ b/app/vendor/symfony/console/Command/TraceableCommand.php @@ -283,7 +283,7 @@ public function run(InputInterface $input, OutputInterface $output): int $event = $this->stopwatch->start($this->getName(), 'command'); try { - $this->exitCode = parent::run($input, $output); + $this->exitCode = $this->command->run($input, $output); } finally { $event->stop(); diff --git a/app/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php b/app/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php index bfa0ac467..1638f2fd0 100644 --- a/app/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php +++ b/app/vendor/symfony/console/CommandLoader/ContainerCommandLoader.php @@ -37,7 +37,7 @@ public function __construct(ContainerInterface $container, array $commandMap) public function get(string $name): Command { if (!$this->has($name)) { - throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name)); + throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name)); } return $this->container->get($this->commandMap[$name]); diff --git a/app/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php b/app/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php index 9ced75aeb..ffe1b520c 100644 --- a/app/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php +++ b/app/vendor/symfony/console/CommandLoader/FactoryCommandLoader.php @@ -39,7 +39,7 @@ public function has(string $name): bool public function get(string $name): Command { if (!isset($this->factories[$name])) { - throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name)); + throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name)); } $factory = $this->factories[$name]; diff --git a/app/vendor/symfony/console/Completion/CompletionInput.php b/app/vendor/symfony/console/Completion/CompletionInput.php index 7ba41c083..79c2f659a 100644 --- a/app/vendor/symfony/console/Completion/CompletionInput.php +++ b/app/vendor/symfony/console/Completion/CompletionInput.php @@ -53,7 +53,7 @@ public static function fromString(string $inputStr, int $currentIndex): self * Create an input based on an COMP_WORDS token list. * * @param string[] $tokens the set of split tokens (e.g. COMP_WORDS or argv) - * @param $currentIndex the index of the cursor (e.g. COMP_CWORD) + * @param int $currentIndex the index of the cursor (e.g. COMP_CWORD) */ public static function fromTokens(array $tokens, int $currentIndex): self { diff --git a/app/vendor/symfony/console/Completion/Suggestion.php b/app/vendor/symfony/console/Completion/Suggestion.php index 7392965a2..3251b079f 100644 --- a/app/vendor/symfony/console/Completion/Suggestion.php +++ b/app/vendor/symfony/console/Completion/Suggestion.php @@ -20,7 +20,7 @@ class Suggestion implements \Stringable { public function __construct( private readonly string $value, - private readonly string $description = '' + private readonly string $description = '', ) { } diff --git a/app/vendor/symfony/console/Cursor.php b/app/vendor/symfony/console/Cursor.php index 69fd3821c..45243c796 100644 --- a/app/vendor/symfony/console/Cursor.php +++ b/app/vendor/symfony/console/Cursor.php @@ -36,7 +36,7 @@ public function __construct(OutputInterface $output, $input = null) */ public function moveUp(int $lines = 1): static { - $this->output->write(sprintf("\x1b[%dA", $lines)); + $this->output->write(\sprintf("\x1b[%dA", $lines)); return $this; } @@ -46,7 +46,7 @@ public function moveUp(int $lines = 1): static */ public function moveDown(int $lines = 1): static { - $this->output->write(sprintf("\x1b[%dB", $lines)); + $this->output->write(\sprintf("\x1b[%dB", $lines)); return $this; } @@ -56,7 +56,7 @@ public function moveDown(int $lines = 1): static */ public function moveRight(int $columns = 1): static { - $this->output->write(sprintf("\x1b[%dC", $columns)); + $this->output->write(\sprintf("\x1b[%dC", $columns)); return $this; } @@ -66,7 +66,7 @@ public function moveRight(int $columns = 1): static */ public function moveLeft(int $columns = 1): static { - $this->output->write(sprintf("\x1b[%dD", $columns)); + $this->output->write(\sprintf("\x1b[%dD", $columns)); return $this; } @@ -76,7 +76,7 @@ public function moveLeft(int $columns = 1): static */ public function moveToColumn(int $column): static { - $this->output->write(sprintf("\x1b[%dG", $column)); + $this->output->write(\sprintf("\x1b[%dG", $column)); return $this; } @@ -86,7 +86,7 @@ public function moveToColumn(int $column): static */ public function moveToPosition(int $column, int $row): static { - $this->output->write(sprintf("\x1b[%d;%dH", $row + 1, $column)); + $this->output->write(\sprintf("\x1b[%d;%dH", $row + 1, $column)); return $this; } @@ -195,7 +195,7 @@ public function getCurrentPosition(): array $code = trim(fread($this->input, 1024)); - shell_exec(sprintf('stty %s', $sttyMode)); + shell_exec(\sprintf('stty %s', $sttyMode)); sscanf($code, "\033[%d;%dR", $row, $col); diff --git a/app/vendor/symfony/console/DataCollector/CommandDataCollector.php b/app/vendor/symfony/console/DataCollector/CommandDataCollector.php index 45138c7dc..3cbe72b59 100644 --- a/app/vendor/symfony/console/DataCollector/CommandDataCollector.php +++ b/app/vendor/symfony/console/DataCollector/CommandDataCollector.php @@ -118,7 +118,7 @@ public function getCommand(): array public function getInterruptedBySignal(): ?string { if (isset($this->data['interrupted_by_signal'])) { - return sprintf('%s (%d)', SignalMap::getSignalName($this->data['interrupted_by_signal']), $this->data['interrupted_by_signal']); + return \sprintf('%s (%d)', SignalMap::getSignalName($this->data['interrupted_by_signal']), $this->data['interrupted_by_signal']); } return null; @@ -204,7 +204,7 @@ public function getInteractiveInputs(): array public function getSignalable(): array { return array_map( - static fn (int $signal): string => sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal), + static fn (int $signal): string => \sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal), $this->data['signalable'] ); } @@ -212,7 +212,7 @@ public function getSignalable(): array public function getHandledSignals(): array { $keys = array_map( - static fn (int $signal): string => sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal), + static fn (int $signal): string => \sprintf('%s (%d)', SignalMap::getSignalName($signal), $signal), array_keys($this->data['handled_signals']) ); diff --git a/app/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php b/app/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php index 27705ddb6..3cf05734b 100644 --- a/app/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php +++ b/app/vendor/symfony/console/DependencyInjection/AddConsoleCommandPass.php @@ -48,10 +48,10 @@ public function process(ContainerBuilder $container) $aliases = $tags[0]['command']; } else { if (!$r = $container->getReflectionClass($class)) { - throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); + throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); } if (!$r->isSubclassOf(Command::class)) { - throw new InvalidArgumentException(sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, 'console.command', Command::class)); + throw new InvalidArgumentException(\sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, 'console.command', Command::class)); } $aliases = str_replace('%', '%%', $class::getDefaultName() ?? ''); } @@ -105,10 +105,10 @@ public function process(ContainerBuilder $container) if (!$description) { if (!$r = $container->getReflectionClass($class)) { - throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); + throw new InvalidArgumentException(\sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); } if (!$r->isSubclassOf(Command::class)) { - throw new InvalidArgumentException(sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, 'console.command', Command::class)); + throw new InvalidArgumentException(\sprintf('The service "%s" tagged "%s" must be a subclass of "%s".', $id, 'console.command', Command::class)); } $description = str_replace('%', '%%', $class::getDefaultDescription() ?? ''); } diff --git a/app/vendor/symfony/console/Descriptor/ApplicationDescription.php b/app/vendor/symfony/console/Descriptor/ApplicationDescription.php index ef9e8a63b..3f38379c9 100644 --- a/app/vendor/symfony/console/Descriptor/ApplicationDescription.php +++ b/app/vendor/symfony/console/Descriptor/ApplicationDescription.php @@ -73,7 +73,7 @@ public function getCommands(): array public function getCommand(string $name): Command { if (!isset($this->commands[$name]) && !isset($this->aliases[$name])) { - throw new CommandNotFoundException(sprintf('Command "%s" does not exist.', $name)); + throw new CommandNotFoundException(\sprintf('Command "%s" does not exist.', $name)); } return $this->commands[$name] ?? $this->aliases[$name]; diff --git a/app/vendor/symfony/console/Descriptor/Descriptor.php b/app/vendor/symfony/console/Descriptor/Descriptor.php index 7b2509c60..2143a17c3 100644 --- a/app/vendor/symfony/console/Descriptor/Descriptor.php +++ b/app/vendor/symfony/console/Descriptor/Descriptor.php @@ -38,7 +38,7 @@ public function describe(OutputInterface $output, object $object, array $options $object instanceof InputDefinition => $this->describeInputDefinition($object, $options), $object instanceof Command => $this->describeCommand($object, $options), $object instanceof Application => $this->describeApplication($object, $options), - default => throw new InvalidArgumentException(sprintf('Object of type "%s" is not describable.', get_debug_type($object))), + default => throw new InvalidArgumentException(\sprintf('Object of type "%s" is not describable.', get_debug_type($object))), }; } diff --git a/app/vendor/symfony/console/Descriptor/JsonDescriptor.php b/app/vendor/symfony/console/Descriptor/JsonDescriptor.php index 956303709..9a8e696cd 100644 --- a/app/vendor/symfony/console/Descriptor/JsonDescriptor.php +++ b/app/vendor/symfony/console/Descriptor/JsonDescriptor.php @@ -108,7 +108,7 @@ private function getInputOptionData(InputOption $option, bool $negated = false): 'is_value_required' => false, 'is_multiple' => false, 'description' => 'Negate the "--'.$option->getName().'" option', - 'default' => false, + 'default' => null === $option->getDefault() ? null : !$option->getDefault(), ] : [ 'name' => '--'.$option->getName(), 'shortcut' => $option->getShortcut() ? '-'.str_replace('|', '|-', $option->getShortcut()) : '', diff --git a/app/vendor/symfony/console/Descriptor/MarkdownDescriptor.php b/app/vendor/symfony/console/Descriptor/MarkdownDescriptor.php index b3f16ee90..8b7075943 100644 --- a/app/vendor/symfony/console/Descriptor/MarkdownDescriptor.php +++ b/app/vendor/symfony/console/Descriptor/MarkdownDescriptor.php @@ -149,7 +149,7 @@ protected function describeApplication(Application $application, array $options } $this->write("\n\n"); - $this->write(implode("\n", array_map(fn ($commandName) => sprintf('* [`%s`](#%s)', $commandName, str_replace(':', '', $description->getCommand($commandName)->getName())), $namespace['commands']))); + $this->write(implode("\n", array_map(fn ($commandName) => \sprintf('* [`%s`](#%s)', $commandName, str_replace(':', '', $description->getCommand($commandName)->getName())), $namespace['commands']))); } foreach ($description->getCommands() as $command) { @@ -162,7 +162,7 @@ private function getApplicationTitle(Application $application): string { if ('UNKNOWN' !== $application->getName()) { if ('UNKNOWN' !== $application->getVersion()) { - return sprintf('%s %s', $application->getName(), $application->getVersion()); + return \sprintf('%s %s', $application->getName(), $application->getVersion()); } return $application->getName(); diff --git a/app/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php b/app/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php index d4423fd34..a2b754276 100644 --- a/app/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php +++ b/app/vendor/symfony/console/Descriptor/ReStructuredTextDescriptor.php @@ -167,7 +167,7 @@ private function getApplicationTitle(Application $application): string return 'Console Tool'; } if ('UNKNOWN' !== $application->getVersion()) { - return sprintf('%s %s', $application->getName(), $application->getVersion()); + return \sprintf('%s %s', $application->getName(), $application->getVersion()); } return $application->getName(); @@ -209,7 +209,7 @@ private function createTableOfContents(ApplicationDescription $description, Appl $commands = $this->removeAliasesAndHiddenCommands($commands); $this->write("\n\n"); - $this->write(implode("\n", array_map(static fn ($commandName) => sprintf('- `%s`_', $commandName), array_keys($commands)))); + $this->write(implode("\n", array_map(static fn ($commandName) => \sprintf('- `%s`_', $commandName), array_keys($commands)))); } } diff --git a/app/vendor/symfony/console/Descriptor/TextDescriptor.php b/app/vendor/symfony/console/Descriptor/TextDescriptor.php index d04d10238..51c411f46 100644 --- a/app/vendor/symfony/console/Descriptor/TextDescriptor.php +++ b/app/vendor/symfony/console/Descriptor/TextDescriptor.php @@ -31,7 +31,7 @@ class TextDescriptor extends Descriptor protected function describeInputArgument(InputArgument $argument, array $options = []): void { if (null !== $argument->getDefault() && (!\is_array($argument->getDefault()) || \count($argument->getDefault()))) { - $default = sprintf(' [default: %s]', $this->formatDefaultValue($argument->getDefault())); + $default = \sprintf(' [default: %s]', $this->formatDefaultValue($argument->getDefault())); } else { $default = ''; } @@ -39,7 +39,7 @@ protected function describeInputArgument(InputArgument $argument, array $options $totalWidth = $options['total_width'] ?? Helper::width($argument->getName()); $spacingWidth = $totalWidth - \strlen($argument->getName()); - $this->writeText(sprintf(' %s %s%s%s', + $this->writeText(\sprintf(' %s %s%s%s', $argument->getName(), str_repeat(' ', $spacingWidth), // + 4 = 2 spaces before , 2 spaces after @@ -51,7 +51,7 @@ protected function describeInputArgument(InputArgument $argument, array $options protected function describeInputOption(InputOption $option, array $options = []): void { if ($option->acceptValue() && null !== $option->getDefault() && (!\is_array($option->getDefault()) || \count($option->getDefault()))) { - $default = sprintf(' [default: %s]', $this->formatDefaultValue($option->getDefault())); + $default = \sprintf(' [default: %s]', $this->formatDefaultValue($option->getDefault())); } else { $default = ''; } @@ -66,14 +66,14 @@ protected function describeInputOption(InputOption $option, array $options = []) } $totalWidth = $options['total_width'] ?? $this->calculateTotalWidthForOptions([$option]); - $synopsis = sprintf('%s%s', - $option->getShortcut() ? sprintf('-%s, ', $option->getShortcut()) : ' ', - sprintf($option->isNegatable() ? '--%1$s|--no-%1$s' : '--%1$s%2$s', $option->getName(), $value) + $synopsis = \sprintf('%s%s', + $option->getShortcut() ? \sprintf('-%s, ', $option->getShortcut()) : ' ', + \sprintf($option->isNegatable() ? '--%1$s|--no-%1$s' : '--%1$s%2$s', $option->getName(), $value) ); $spacingWidth = $totalWidth - Helper::width($synopsis); - $this->writeText(sprintf(' %s %s%s%s%s', + $this->writeText(\sprintf(' %s %s%s%s%s', $synopsis, str_repeat(' ', $spacingWidth), // + 4 = 2 spaces before , 2 spaces after @@ -166,7 +166,7 @@ protected function describeApplication(Application $application, array $options $width = $this->getColumnWidth($description->getCommands()); foreach ($description->getCommands() as $command) { - $this->writeText(sprintf("%-{$width}s %s", $command->getName(), $command->getDescription()), $options); + $this->writeText(\sprintf("%-{$width}s %s", $command->getName(), $command->getDescription()), $options); $this->writeText("\n"); } } else { @@ -196,7 +196,7 @@ protected function describeApplication(Application $application, array $options $width = $this->getColumnWidth(array_merge(...array_values(array_map(fn ($namespace) => array_intersect($namespace['commands'], array_keys($commands)), array_values($namespaces))))); if ($describedNamespace) { - $this->writeText(sprintf('Available commands for the "%s" namespace:', $describedNamespace), $options); + $this->writeText(\sprintf('Available commands for the "%s" namespace:', $describedNamespace), $options); } else { $this->writeText('Available commands:', $options); } @@ -218,7 +218,7 @@ protected function describeApplication(Application $application, array $options $spacingWidth = $width - Helper::width($name); $command = $commands[$name]; $commandAliases = $name === $command->getName() ? $this->getCommandAliasesText($command) : ''; - $this->writeText(sprintf(' %s%s%s', $name, str_repeat(' ', $spacingWidth), $commandAliases.$command->getDescription()), $options); + $this->writeText(\sprintf(' %s%s%s', $name, str_repeat(' ', $spacingWidth), $commandAliases.$command->getDescription()), $options); } } diff --git a/app/vendor/symfony/console/Formatter/OutputFormatter.php b/app/vendor/symfony/console/Formatter/OutputFormatter.php index 3e4897c33..c37a4d452 100644 --- a/app/vendor/symfony/console/Formatter/OutputFormatter.php +++ b/app/vendor/symfony/console/Formatter/OutputFormatter.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Console\Formatter; use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Helper\Helper; use function Symfony\Component\String\b; @@ -112,7 +113,7 @@ public function hasStyle(string $name): bool public function getStyle(string $name): OutputFormatterStyleInterface { if (!$this->hasStyle($name)) { - throw new InvalidArgumentException(sprintf('Undefined style: "%s".', $name)); + throw new InvalidArgumentException(\sprintf('Undefined style: "%s".', $name)); } return $this->styles[strtolower($name)]; @@ -146,9 +147,11 @@ public function formatAndWrap(?string $message, int $width) continue; } + // convert byte position to character position. + $pos = Helper::length(substr($message, 0, $pos)); // add the text up to the next tag - $output .= $this->applyCurrentStyle(substr($message, $offset, $pos - $offset), $output, $width, $currentLineLength); - $offset = $pos + \strlen($text); + $output .= $this->applyCurrentStyle(Helper::substr($message, $offset, $pos - $offset), $output, $width, $currentLineLength); + $offset = $pos + Helper::length($text); // opening tag? if ($open = '/' !== $text[1]) { @@ -169,7 +172,7 @@ public function formatAndWrap(?string $message, int $width) } } - $output .= $this->applyCurrentStyle(substr($message, $offset), $output, $width, $currentLineLength); + $output .= $this->applyCurrentStyle(Helper::substr($message, $offset), $output, $width, $currentLineLength); return strtr($output, ["\0" => '\\', '\\<' => '<', '\\>' => '>']); } @@ -236,8 +239,18 @@ private function applyCurrentStyle(string $text, string $current, int $width, in } if ($currentLineLength) { - $prefix = substr($text, 0, $i = $width - $currentLineLength)."\n"; - $text = substr($text, $i); + $lines = explode("\n", $text, 2); + $prefix = Helper::substr($lines[0], 0, $i = $width - $currentLineLength)."\n"; + $text = Helper::substr($lines[0], $i); + + if (isset($lines[1])) { + // $prefix may contain the full first line in which the \n is already a part of $prefix. + if ('' !== $text) { + $text .= "\n"; + } + + $text .= $lines[1]; + } } else { $prefix = ''; } @@ -252,8 +265,8 @@ private function applyCurrentStyle(string $text, string $current, int $width, in $lines = explode("\n", $text); - foreach ($lines as $line) { - $currentLineLength += \strlen($line); + foreach ($lines as $i => $line) { + $currentLineLength = 0 === $i ? $currentLineLength + Helper::length($line) : Helper::length($line); if ($width <= $currentLineLength) { $currentLineLength = 0; } diff --git a/app/vendor/symfony/console/Helper/DebugFormatterHelper.php b/app/vendor/symfony/console/Helper/DebugFormatterHelper.php index 9ea7fb914..dfdb8a82c 100644 --- a/app/vendor/symfony/console/Helper/DebugFormatterHelper.php +++ b/app/vendor/symfony/console/Helper/DebugFormatterHelper.php @@ -31,7 +31,7 @@ public function start(string $id, string $message, string $prefix = 'RUN'): stri { $this->started[$id] = ['border' => ++$this->count % \count(self::COLORS)]; - return sprintf("%s %s %s\n", $this->getBorder($id), $prefix, $message); + return \sprintf("%s %s %s\n", $this->getBorder($id), $prefix, $message); } /** @@ -47,22 +47,22 @@ public function progress(string $id, string $buffer, bool $error = false, string unset($this->started[$id]['out']); } if (!isset($this->started[$id]['err'])) { - $message .= sprintf('%s %s ', $this->getBorder($id), $errorPrefix); + $message .= \sprintf('%s %s ', $this->getBorder($id), $errorPrefix); $this->started[$id]['err'] = true; } - $message .= str_replace("\n", sprintf("\n%s %s ", $this->getBorder($id), $errorPrefix), $buffer); + $message .= str_replace("\n", \sprintf("\n%s %s ", $this->getBorder($id), $errorPrefix), $buffer); } else { if (isset($this->started[$id]['err'])) { $message .= "\n"; unset($this->started[$id]['err']); } if (!isset($this->started[$id]['out'])) { - $message .= sprintf('%s %s ', $this->getBorder($id), $prefix); + $message .= \sprintf('%s %s ', $this->getBorder($id), $prefix); $this->started[$id]['out'] = true; } - $message .= str_replace("\n", sprintf("\n%s %s ", $this->getBorder($id), $prefix), $buffer); + $message .= str_replace("\n", \sprintf("\n%s %s ", $this->getBorder($id), $prefix), $buffer); } return $message; @@ -76,10 +76,10 @@ public function stop(string $id, string $message, bool $successful, string $pref $trailingEOL = isset($this->started[$id]['out']) || isset($this->started[$id]['err']) ? "\n" : ''; if ($successful) { - return sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); + return \sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); } - $message = sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); + $message = \sprintf("%s%s %s %s\n", $trailingEOL, $this->getBorder($id), $prefix, $message); unset($this->started[$id]['out'], $this->started[$id]['err']); @@ -88,7 +88,7 @@ public function stop(string $id, string $message, bool $successful, string $pref private function getBorder(string $id): string { - return sprintf(' ', self::COLORS[$this->started[$id]['border']]); + return \sprintf(' ', self::COLORS[$this->started[$id]['border']]); } public function getName(): string diff --git a/app/vendor/symfony/console/Helper/DescriptorHelper.php b/app/vendor/symfony/console/Helper/DescriptorHelper.php index eb32bce8f..fda6779b9 100644 --- a/app/vendor/symfony/console/Helper/DescriptorHelper.php +++ b/app/vendor/symfony/console/Helper/DescriptorHelper.php @@ -62,7 +62,7 @@ public function describe(OutputInterface $output, ?object $object, array $option ], $options); if (!isset($this->descriptors[$options['format']])) { - throw new InvalidArgumentException(sprintf('Unsupported format "%s".', $options['format'])); + throw new InvalidArgumentException(\sprintf('Unsupported format "%s".', $options['format'])); } $descriptor = $this->descriptors[$options['format']]; diff --git a/app/vendor/symfony/console/Helper/FormatterHelper.php b/app/vendor/symfony/console/Helper/FormatterHelper.php index 279e4c799..3646b3d6f 100644 --- a/app/vendor/symfony/console/Helper/FormatterHelper.php +++ b/app/vendor/symfony/console/Helper/FormatterHelper.php @@ -25,7 +25,7 @@ class FormatterHelper extends Helper */ public function formatSection(string $section, string $message, string $style = 'info'): string { - return sprintf('<%s>[%s] %s', $style, $section, $style, $message); + return \sprintf('<%s>[%s] %s', $style, $section, $style, $message); } /** @@ -41,7 +41,7 @@ public function formatBlock(string|array $messages, string $style, bool $large = $lines = []; foreach ($messages as $message) { $message = OutputFormatter::escape($message); - $lines[] = sprintf($large ? ' %s ' : ' %s ', $message); + $lines[] = \sprintf($large ? ' %s ' : ' %s ', $message); $len = max(self::width($message) + ($large ? 4 : 2), $len); } @@ -54,7 +54,7 @@ public function formatBlock(string|array $messages, string $style, bool $large = } for ($i = 0; isset($messages[$i]); ++$i) { - $messages[$i] = sprintf('<%s>%s', $style, $messages[$i], $style); + $messages[$i] = \sprintf('<%s>%s', $style, $messages[$i], $style); } return implode("\n", $messages); diff --git a/app/vendor/symfony/console/Helper/Helper.php b/app/vendor/symfony/console/Helper/Helper.php index 05be64787..468d06689 100644 --- a/app/vendor/symfony/console/Helper/Helper.php +++ b/app/vendor/symfony/console/Helper/Helper.php @@ -48,7 +48,9 @@ public static function width(?string $string): int $string ??= ''; if (preg_match('//u', $string)) { - return (new UnicodeString($string))->width(false); + $string = preg_replace('/[\p{Cc}\x7F]++/u', '', $string, -1, $count); + + return (new UnicodeString($string))->width(false) + $count; } if (false === $encoding = mb_detect_encoding($string, null, true)) { @@ -84,6 +86,10 @@ public static function substr(?string $string, int $from, ?int $length = null): { $string ??= ''; + if (preg_match('//u', $string)) { + return (new UnicodeString($string))->slice($from, $length); + } + if (false === $encoding = mb_detect_encoding($string, null, true)) { return substr($string, $from, $length); } @@ -140,18 +146,18 @@ public static function formatTime(int|float $secs, int $precision = 1) public static function formatMemory(int $memory) { if ($memory >= 1024 * 1024 * 1024) { - return sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024); + return \sprintf('%.1f GiB', $memory / 1024 / 1024 / 1024); } if ($memory >= 1024 * 1024) { - return sprintf('%.1f MiB', $memory / 1024 / 1024); + return \sprintf('%.1f MiB', $memory / 1024 / 1024); } if ($memory >= 1024) { - return sprintf('%d KiB', $memory / 1024); + return \sprintf('%d KiB', $memory / 1024); } - return sprintf('%d B', $memory); + return \sprintf('%d B', $memory); } /** diff --git a/app/vendor/symfony/console/Helper/HelperSet.php b/app/vendor/symfony/console/Helper/HelperSet.php index f8c74ca2c..8deb22ee7 100644 --- a/app/vendor/symfony/console/Helper/HelperSet.php +++ b/app/vendor/symfony/console/Helper/HelperSet.php @@ -64,7 +64,7 @@ public function has(string $name): bool public function get(string $name): HelperInterface { if (!$this->has($name)) { - throw new InvalidArgumentException(sprintf('The helper "%s" is not defined.', $name)); + throw new InvalidArgumentException(\sprintf('The helper "%s" is not defined.', $name)); } return $this->helpers[$name]; diff --git a/app/vendor/symfony/console/Helper/OutputWrapper.php b/app/vendor/symfony/console/Helper/OutputWrapper.php index 2ec819c74..a615ed2f9 100644 --- a/app/vendor/symfony/console/Helper/OutputWrapper.php +++ b/app/vendor/symfony/console/Helper/OutputWrapper.php @@ -49,7 +49,7 @@ final class OutputWrapper private const URL_PATTERN = 'https?://\S+'; public function __construct( - private bool $allowCutUrls = false + private bool $allowCutUrls = false, ) { } @@ -59,7 +59,7 @@ public function wrap(string $text, int $width, string $break = "\n"): string return $text; } - $tagPattern = sprintf('<(?:(?:%s)|/(?:%s)?)>', self::TAG_OPEN_REGEX_SEGMENT, self::TAG_CLOSE_REGEX_SEGMENT); + $tagPattern = \sprintf('<(?:(?:%s)|/(?:%s)?)>', self::TAG_OPEN_REGEX_SEGMENT, self::TAG_CLOSE_REGEX_SEGMENT); $limitPattern = "{1,$width}"; $patternBlocks = [$tagPattern]; if (!$this->allowCutUrls) { @@ -68,7 +68,7 @@ public function wrap(string $text, int $width, string $break = "\n"): string $patternBlocks[] = '.'; $blocks = implode('|', $patternBlocks); $rowPattern = "(?:$blocks)$limitPattern"; - $pattern = sprintf('#(?:((?>(%1$s)((?<=[^\S\r\n])[^\S\r\n]?|(?=\r?\n)|$|[^\S\r\n]))|(%1$s))(?:\r?\n)?|(?:\r?\n|$))#imux', $rowPattern); + $pattern = \sprintf('#(?:((?>(%1$s)((?<=[^\S\r\n])[^\S\r\n]?|(?=\r?\n)|$|[^\S\r\n]))|(%1$s))(?:\r?\n)?|(?:\r?\n|$))#imux', $rowPattern); $output = rtrim(preg_replace($pattern, '\\1'.$break, $text), $break); return str_replace(' '.$break, $break, $output); diff --git a/app/vendor/symfony/console/Helper/ProcessHelper.php b/app/vendor/symfony/console/Helper/ProcessHelper.php index 3ef6f71f7..ae55a83c2 100644 --- a/app/vendor/symfony/console/Helper/ProcessHelper.php +++ b/app/vendor/symfony/console/Helper/ProcessHelper.php @@ -55,7 +55,7 @@ public function run(OutputInterface $output, array|Process $cmd, ?string $error $process = $cmd[0]; unset($cmd[0]); } else { - throw new \InvalidArgumentException(sprintf('Invalid command provided to "%s()": the command should be an array whose first element is either the path to the binary to run or a "Process" object.', __METHOD__)); + throw new \InvalidArgumentException(\sprintf('Invalid command provided to "%s()": the command should be an array whose first element is either the path to the binary to run or a "Process" object.', __METHOD__)); } if ($verbosity <= $output->getVerbosity()) { @@ -69,12 +69,12 @@ public function run(OutputInterface $output, array|Process $cmd, ?string $error $process->run($callback, $cmd); if ($verbosity <= $output->getVerbosity()) { - $message = $process->isSuccessful() ? 'Command ran successfully' : sprintf('%s Command did not run successfully', $process->getExitCode()); + $message = $process->isSuccessful() ? 'Command ran successfully' : \sprintf('%s Command did not run successfully', $process->getExitCode()); $output->write($formatter->stop(spl_object_hash($process), $message, $process->isSuccessful())); } if (!$process->isSuccessful() && null !== $error) { - $output->writeln(sprintf('%s', $this->escapeString($error))); + $output->writeln(\sprintf('%s', $this->escapeString($error))); } return $process; diff --git a/app/vendor/symfony/console/Helper/ProgressBar.php b/app/vendor/symfony/console/Helper/ProgressBar.php index f4eec051c..8143acaff 100644 --- a/app/vendor/symfony/console/Helper/ProgressBar.php +++ b/app/vendor/symfony/console/Helper/ProgressBar.php @@ -183,9 +183,9 @@ public function setMessage(string $message, string $name = 'message'): void $this->messages[$name] = $message; } - public function getMessage(string $name = 'message'): string + public function getMessage(string $name = 'message'): ?string { - return $this->messages[$name]; + return $this->messages[$name] ?? null; } public function getStartTime(): int @@ -229,7 +229,7 @@ public function getEstimated(): float public function getRemaining(): float { - if (!$this->step) { + if (0 === $this->step || $this->step === $this->startingStep) { return 0; } @@ -486,12 +486,21 @@ private function overwrite(string $message): void if ($this->output instanceof ConsoleSectionOutput) { $messageLines = explode("\n", $this->previousMessage); $lineCount = \count($messageLines); + + $lastLineWithoutDecoration = Helper::removeDecoration($this->output->getFormatter(), end($messageLines) ?? ''); + + // When the last previous line is empty (without formatting) it is already cleared by the section output, so we don't need to clear it again + if ('' === $lastLineWithoutDecoration) { + --$lineCount; + } + foreach ($messageLines as $messageLine) { $messageLineLength = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $messageLine)); if ($messageLineLength > $this->terminal->getWidth()) { $lineCount += floor($messageLineLength / $this->terminal->getWidth()); } } + $this->output->clear($lineCount); } else { $lineCount = substr_count($this->previousMessage, "\n"); @@ -594,7 +603,7 @@ private function buildLine(): string } if (isset($matches[2])) { - $text = sprintf('%'.$matches[2], $text); + $text = \sprintf('%'.$matches[2], $text); } return $text; diff --git a/app/vendor/symfony/console/Helper/QuestionHelper.php b/app/vendor/symfony/console/Helper/QuestionHelper.php index b40b13191..3d9091d2b 100644 --- a/app/vendor/symfony/console/Helper/QuestionHelper.php +++ b/app/vendor/symfony/console/Helper/QuestionHelper.php @@ -220,7 +220,7 @@ protected function formatChoiceQuestionChoices(ChoiceQuestion $question, string foreach ($choices as $key => $value) { $padding = str_repeat(' ', $maxWidth - self::width($key)); - $messages[] = sprintf(" [<$tag>%s$padding] %s", $key, $value); + $messages[] = \sprintf(" [<$tag>%s$padding] %s", $key, $value); } return $messages; diff --git a/app/vendor/symfony/console/Helper/SymfonyQuestionHelper.php b/app/vendor/symfony/console/Helper/SymfonyQuestionHelper.php index 8ebc84376..11b4e4238 100644 --- a/app/vendor/symfony/console/Helper/SymfonyQuestionHelper.php +++ b/app/vendor/symfony/console/Helper/SymfonyQuestionHelper.php @@ -34,17 +34,17 @@ protected function writePrompt(OutputInterface $output, Question $question) $default = $question->getDefault(); if ($question->isMultiline()) { - $text .= sprintf(' (press %s to continue)', $this->getEofShortcut()); + $text .= \sprintf(' (press %s to continue)', $this->getEofShortcut()); } switch (true) { case null === $default: - $text = sprintf(' %s:', $text); + $text = \sprintf(' %s:', $text); break; case $question instanceof ConfirmationQuestion: - $text = sprintf(' %s (yes/no) [%s]:', $text, $default ? 'yes' : 'no'); + $text = \sprintf(' %s (yes/no) [%s]:', $text, $default ? 'yes' : 'no'); break; @@ -56,18 +56,18 @@ protected function writePrompt(OutputInterface $output, Question $question) $default[$key] = $choices[trim($value)]; } - $text = sprintf(' %s [%s]:', $text, OutputFormatter::escape(implode(', ', $default))); + $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape(implode(', ', $default))); break; case $question instanceof ChoiceQuestion: $choices = $question->getChoices(); - $text = sprintf(' %s [%s]:', $text, OutputFormatter::escape($choices[$default] ?? $default)); + $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape($choices[$default] ?? $default)); break; default: - $text = sprintf(' %s [%s]:', $text, OutputFormatter::escape($default)); + $text = \sprintf(' %s [%s]:', $text, OutputFormatter::escape($default)); } $output->writeln($text); diff --git a/app/vendor/symfony/console/Helper/Table.php b/app/vendor/symfony/console/Helper/Table.php index 6aad9e95b..469d228d6 100644 --- a/app/vendor/symfony/console/Helper/Table.php +++ b/app/vendor/symfony/console/Helper/Table.php @@ -83,7 +83,7 @@ public static function getStyleDefinition(string $name): TableStyle { self::$styles ??= self::initStyles(); - return self::$styles[$name] ?? throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name)); + return self::$styles[$name] ?? throw new InvalidArgumentException(\sprintf('Style "%s" is not defined.', $name)); } /** @@ -168,7 +168,7 @@ public function setColumnWidths(array $widths): static public function setColumnMaxWidth(int $columnIndex, int $width): static { if (!$this->output->getFormatter() instanceof WrappableOutputFormatterInterface) { - throw new \LogicException(sprintf('Setting a maximum column width is only supported when using a "%s" formatter, got "%s".', WrappableOutputFormatterInterface::class, get_debug_type($this->output->getFormatter()))); + throw new \LogicException(\sprintf('Setting a maximum column width is only supported when using a "%s" formatter, got "%s".', WrappableOutputFormatterInterface::class, get_debug_type($this->output->getFormatter()))); } $this->columnMaxWidths[$columnIndex] = $width; @@ -237,7 +237,7 @@ public function addRow(TableSeparator|array $row): static public function appendRow(TableSeparator|array $row): static { if (!$this->output instanceof ConsoleSectionOutput) { - throw new RuntimeException(sprintf('Output should be an instance of "%s" when calling "%s".', ConsoleSectionOutput::class, __METHOD__)); + throw new RuntimeException(\sprintf('Output should be an instance of "%s" when calling "%s".', ConsoleSectionOutput::class, __METHOD__)); } if ($this->rendered) { @@ -370,13 +370,14 @@ public function render() foreach ($parts as $idx => $part) { if ($headers && !$containsColspan) { if (0 === $idx) { - $rows[] = [sprintf( - '%s: %s', - str_pad($headers[$i] ?? '', $maxHeaderLength, ' ', \STR_PAD_LEFT), + $rows[] = [\sprintf( + '%s%s: %s', + str_repeat(' ', $maxHeaderLength - Helper::width(Helper::removeDecoration($formatter, $headers[$i] ?? ''))), + $headers[$i] ?? '', $part )]; } else { - $rows[] = [sprintf( + $rows[] = [\sprintf( '%s %s', str_pad('', $maxHeaderLength, ' ', \STR_PAD_LEFT), $part @@ -496,12 +497,12 @@ private function renderRowSeparator(int $type = self::SEPARATOR_MID, ?string $ti } if (null !== $title) { - $titleLength = Helper::width(Helper::removeDecoration($formatter = $this->output->getFormatter(), $formattedTitle = sprintf($titleFormat, $title))); + $titleLength = Helper::width(Helper::removeDecoration($formatter = $this->output->getFormatter(), $formattedTitle = \sprintf($titleFormat, $title))); $markupLength = Helper::width($markup); if ($titleLength > $limit = $markupLength - 4) { $titleLength = $limit; - $formatLength = Helper::width(Helper::removeDecoration($formatter, sprintf($titleFormat, ''))); - $formattedTitle = sprintf($titleFormat, Helper::substr($title, 0, $limit - $formatLength - 3).'...'); + $formatLength = Helper::width(Helper::removeDecoration($formatter, \sprintf($titleFormat, ''))); + $formattedTitle = \sprintf($titleFormat, Helper::substr($title, 0, $limit - $formatLength - 3).'...'); } $titleStart = intdiv($markupLength - $titleLength, 2); @@ -512,7 +513,7 @@ private function renderRowSeparator(int $type = self::SEPARATOR_MID, ?string $ti } } - $this->output->writeln(sprintf($this->style->getBorderFormat(), $markup)); + $this->output->writeln(\sprintf($this->style->getBorderFormat(), $markup)); } /** @@ -522,7 +523,7 @@ private function renderColumnSeparator(int $type = self::BORDER_OUTSIDE): string { $borders = $this->style->getBorderChars(); - return sprintf($this->style->getBorderFormat(), self::BORDER_OUTSIDE === $type ? $borders[1] : $borders[3]); + return \sprintf($this->style->getBorderFormat(), self::BORDER_OUTSIDE === $type ? $borders[1] : $borders[3]); } /** @@ -563,18 +564,15 @@ private function renderCell(array $row, int $column, string $cellFormat): string } // str_pad won't work properly with multi-byte strings, we need to fix the padding - if (false !== $encoding = mb_detect_encoding($cell, null, true)) { - $width += \strlen($cell) - mb_strwidth($cell, $encoding); - } - + $width += \strlen($cell) - Helper::width($cell) - substr_count($cell, "\0"); $style = $this->getColumnStyle($column); if ($cell instanceof TableSeparator) { - return sprintf($style->getBorderFormat(), str_repeat($style->getBorderChars()[2], $width)); + return \sprintf($style->getBorderFormat(), str_repeat($style->getBorderChars()[2], $width)); } $width += Helper::length($cell) - Helper::length(Helper::removeDecoration($this->output->getFormatter(), $cell)); - $content = sprintf($style->getCellRowContentFormat(), $cell); + $content = \sprintf($style->getCellRowContentFormat(), $cell); $padType = $style->getPadType(); if ($cell instanceof TableCell && $cell->getStyle() instanceof TableCellStyle) { @@ -599,7 +597,7 @@ private function renderCell(array $row, int $column, string $cellFormat): string $padType = $cell->getStyle()->getPadByAlign(); } - return sprintf($cellFormat, str_pad($content, $width, $style->getPaddingChar(), $padType)); + return \sprintf($cellFormat, str_pad($content, $width, $style->getPaddingChar(), $padType)); } /** @@ -631,8 +629,48 @@ private function buildTableRows(array $rows): TableRows foreach ($rows[$rowKey] as $column => $cell) { $colspan = $cell instanceof TableCell ? $cell->getColspan() : 1; - if (isset($this->columnMaxWidths[$column]) && Helper::width(Helper::removeDecoration($formatter, $cell)) > $this->columnMaxWidths[$column]) { - $cell = $formatter->formatAndWrap($cell, $this->columnMaxWidths[$column] * $colspan); + $minWrappedWidth = 0; + $widthApplied = []; + $lengthColumnBorder = $this->getColumnSeparatorWidth() + Helper::width($this->style->getCellRowContentFormat()) - 2; + for ($i = $column; $i < ($column + $colspan); ++$i) { + if (isset($this->columnMaxWidths[$i])) { + $minWrappedWidth += $this->columnMaxWidths[$i]; + $widthApplied[] = ['type' => 'max', 'column' => $i]; + } elseif (($this->columnWidths[$i] ?? 0) > 0 && $colspan > 1) { + $minWrappedWidth += $this->columnWidths[$i]; + $widthApplied[] = ['type' => 'min', 'column' => $i]; + } + } + if (1 === \count($widthApplied)) { + if ($colspan > 1) { + $minWrappedWidth *= $colspan; // previous logic + } + } elseif (\count($widthApplied) > 1) { + $minWrappedWidth += (\count($widthApplied) - 1) * $lengthColumnBorder; + } + + $cellWidth = Helper::width(Helper::removeDecoration($formatter, $cell)); + if ($minWrappedWidth && $cellWidth > $minWrappedWidth) { + $cell = $formatter->formatAndWrap($cell, $minWrappedWidth); + } + // update minimal columnWidths for spanned columns + if ($colspan > 1 && $minWrappedWidth > 0) { + $columnsMinWidthProcessed = []; + $cellWidth = min($cellWidth, $minWrappedWidth); + foreach ($widthApplied as $item) { + if ('max' === $item['type'] && $cellWidth >= $this->columnMaxWidths[$item['column']]) { + $minWidthColumn = $this->columnMaxWidths[$item['column']]; + $this->columnWidths[$item['column']] = $minWidthColumn; + $columnsMinWidthProcessed[$item['column']] = true; + $cellWidth -= $minWidthColumn + $lengthColumnBorder; + } + } + for ($i = $column; $i < ($column + $colspan); ++$i) { + if (isset($columnsMinWidthProcessed[$i])) { + continue; + } + $this->columnWidths[$i] = $cellWidth + $lengthColumnBorder; + } } if (!str_contains($cell ?? '', "\n")) { continue; @@ -696,7 +734,7 @@ private function fillNextRows(array $rows, int $line): array $unmergedRows = []; foreach ($rows[$line] as $column => $cell) { if (null !== $cell && !$cell instanceof TableCell && !\is_scalar($cell) && !$cell instanceof \Stringable) { - throw new InvalidArgumentException(sprintf('A cell must be a TableCell, a scalar or an object implementing "__toString()", "%s" given.', get_debug_type($cell))); + throw new InvalidArgumentException(\sprintf('A cell must be a TableCell, a scalar or an object implementing "__toString()", "%s" given.', get_debug_type($cell))); } if ($cell instanceof TableCell && $cell->getRowspan() > 1) { $nbLines = $cell->getRowspan() - 1; @@ -841,7 +879,7 @@ private function calculateColumnsWidth(iterable $groups): void private function getColumnSeparatorWidth(): int { - return Helper::width(sprintf($this->style->getBorderFormat(), $this->style->getBorderChars()[3])); + return Helper::width(\sprintf($this->style->getBorderFormat(), $this->style->getBorderChars()[3])); } private function getCellWidth(array $row, int $column): int @@ -924,6 +962,6 @@ private function resolveStyle(TableStyle|string $name): TableStyle return $name; } - return self::$styles[$name] ?? throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name)); + return self::$styles[$name] ?? throw new InvalidArgumentException(\sprintf('Style "%s" is not defined.', $name)); } } diff --git a/app/vendor/symfony/console/Helper/TableCell.php b/app/vendor/symfony/console/Helper/TableCell.php index 394b2bc95..ead32f283 100644 --- a/app/vendor/symfony/console/Helper/TableCell.php +++ b/app/vendor/symfony/console/Helper/TableCell.php @@ -31,7 +31,7 @@ public function __construct(string $value = '', array $options = []) // check option names if ($diff = array_diff(array_keys($options), array_keys($this->options))) { - throw new InvalidArgumentException(sprintf('The TableCell does not support the following options: \'%s\'.', implode('\', \'', $diff))); + throw new InvalidArgumentException(\sprintf('The TableCell does not support the following options: \'%s\'.', implode('\', \'', $diff))); } if (isset($options['style']) && !$options['style'] instanceof TableCellStyle) { diff --git a/app/vendor/symfony/console/Helper/TableCellStyle.php b/app/vendor/symfony/console/Helper/TableCellStyle.php index 9419dcb40..1b1ef276e 100644 --- a/app/vendor/symfony/console/Helper/TableCellStyle.php +++ b/app/vendor/symfony/console/Helper/TableCellStyle.php @@ -43,11 +43,11 @@ class TableCellStyle public function __construct(array $options = []) { if ($diff = array_diff(array_keys($options), array_keys($this->options))) { - throw new InvalidArgumentException(sprintf('The TableCellStyle does not support the following options: \'%s\'.', implode('\', \'', $diff))); + throw new InvalidArgumentException(\sprintf('The TableCellStyle does not support the following options: \'%s\'.', implode('\', \'', $diff))); } if (isset($options['align']) && !\array_key_exists($options['align'], self::ALIGN_MAP)) { - throw new InvalidArgumentException(sprintf('Wrong align value. Value must be following: \'%s\'.', implode('\', \'', array_keys(self::ALIGN_MAP)))); + throw new InvalidArgumentException(\sprintf('Wrong align value. Value must be following: \'%s\'.', implode('\', \'', array_keys(self::ALIGN_MAP)))); } $this->options = array_merge($this->options, $options); diff --git a/app/vendor/symfony/console/Input/ArgvInput.php b/app/vendor/symfony/console/Input/ArgvInput.php index ab9f28c54..a33092aee 100644 --- a/app/vendor/symfony/console/Input/ArgvInput.php +++ b/app/vendor/symfony/console/Input/ArgvInput.php @@ -122,7 +122,7 @@ private function parseShortOptionSet(string $name): void for ($i = 0; $i < $len; ++$i) { if (!$this->definition->hasShortcut($name[$i])) { $encoding = mb_detect_encoding($name, null, true); - throw new RuntimeException(sprintf('The "-%s" option does not exist.', false === $encoding ? $name[$i] : mb_substr($name, $i, 1, $encoding))); + throw new RuntimeException(\sprintf('The "-%s" option does not exist.', false === $encoding ? $name[$i] : mb_substr($name, $i, 1, $encoding))); } $option = $this->definition->getOptionForShortcut($name[$i]); @@ -183,14 +183,14 @@ private function parseArgument(string $token): void if (\count($all)) { if ($symfonyCommandName) { - $message = sprintf('Too many arguments to "%s" command, expected arguments "%s".', $symfonyCommandName, implode('" "', array_keys($all))); + $message = \sprintf('Too many arguments to "%s" command, expected arguments "%s".', $symfonyCommandName, implode('" "', array_keys($all))); } else { - $message = sprintf('Too many arguments, expected arguments "%s".', implode('" "', array_keys($all))); + $message = \sprintf('Too many arguments, expected arguments "%s".', implode('" "', array_keys($all))); } } elseif ($symfonyCommandName) { - $message = sprintf('No arguments expected for "%s" command, got "%s".', $symfonyCommandName, $token); + $message = \sprintf('No arguments expected for "%s" command, got "%s".', $symfonyCommandName, $token); } else { - $message = sprintf('No arguments expected, got "%s".', $token); + $message = \sprintf('No arguments expected, got "%s".', $token); } throw new RuntimeException($message); @@ -205,7 +205,7 @@ private function parseArgument(string $token): void private function addShortOption(string $shortcut, mixed $value): void { if (!$this->definition->hasShortcut($shortcut)) { - throw new RuntimeException(sprintf('The "-%s" option does not exist.', $shortcut)); + throw new RuntimeException(\sprintf('The "-%s" option does not exist.', $shortcut)); } $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value); @@ -220,12 +220,12 @@ private function addLongOption(string $name, mixed $value): void { if (!$this->definition->hasOption($name)) { if (!$this->definition->hasNegation($name)) { - throw new RuntimeException(sprintf('The "--%s" option does not exist.', $name)); + throw new RuntimeException(\sprintf('The "--%s" option does not exist.', $name)); } $optionName = $this->definition->negationToName($name); if (null !== $value) { - throw new RuntimeException(sprintf('The "--%s" option does not accept a value.', $name)); + throw new RuntimeException(\sprintf('The "--%s" option does not accept a value.', $name)); } $this->options[$optionName] = false; @@ -235,7 +235,7 @@ private function addLongOption(string $name, mixed $value): void $option = $this->definition->getOption($name); if (null !== $value && !$option->acceptValue()) { - throw new RuntimeException(sprintf('The "--%s" option does not accept a value.', $name)); + throw new RuntimeException(\sprintf('The "--%s" option does not accept a value.', $name)); } if (\in_array($value, ['', null], true) && $option->acceptValue() && \count($this->parsed)) { @@ -251,7 +251,7 @@ private function addLongOption(string $name, mixed $value): void if (null === $value) { if ($option->isValueRequired()) { - throw new RuntimeException(sprintf('The "--%s" option requires a value.', $name)); + throw new RuntimeException(\sprintf('The "--%s" option requires a value.', $name)); } if (!$option->isArray() && !$option->isValueOptional()) { diff --git a/app/vendor/symfony/console/Input/ArrayInput.php b/app/vendor/symfony/console/Input/ArrayInput.php index c1bc914ca..b9f753394 100644 --- a/app/vendor/symfony/console/Input/ArrayInput.php +++ b/app/vendor/symfony/console/Input/ArrayInput.php @@ -140,7 +140,7 @@ protected function parse() private function addShortOption(string $shortcut, mixed $value): void { if (!$this->definition->hasShortcut($shortcut)) { - throw new InvalidOptionException(sprintf('The "-%s" option does not exist.', $shortcut)); + throw new InvalidOptionException(\sprintf('The "-%s" option does not exist.', $shortcut)); } $this->addLongOption($this->definition->getOptionForShortcut($shortcut)->getName(), $value); @@ -156,7 +156,7 @@ private function addLongOption(string $name, mixed $value): void { if (!$this->definition->hasOption($name)) { if (!$this->definition->hasNegation($name)) { - throw new InvalidOptionException(sprintf('The "--%s" option does not exist.', $name)); + throw new InvalidOptionException(\sprintf('The "--%s" option does not exist.', $name)); } $optionName = $this->definition->negationToName($name); @@ -169,7 +169,7 @@ private function addLongOption(string $name, mixed $value): void if (null === $value) { if ($option->isValueRequired()) { - throw new InvalidOptionException(sprintf('The "--%s" option requires a value.', $name)); + throw new InvalidOptionException(\sprintf('The "--%s" option requires a value.', $name)); } if (!$option->isValueOptional()) { @@ -188,7 +188,7 @@ private function addLongOption(string $name, mixed $value): void private function addArgument(string|int $name, mixed $value): void { if (!$this->definition->hasArgument($name)) { - throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); } $this->arguments[$name] = $value; diff --git a/app/vendor/symfony/console/Input/Input.php b/app/vendor/symfony/console/Input/Input.php index 1c21573bc..d3a3c7fd2 100644 --- a/app/vendor/symfony/console/Input/Input.php +++ b/app/vendor/symfony/console/Input/Input.php @@ -74,7 +74,7 @@ public function validate() $missingArguments = array_filter(array_keys($definition->getArguments()), fn ($argument) => !\array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired()); if (\count($missingArguments) > 0) { - throw new RuntimeException(sprintf('Not enough arguments (missing: "%s").', implode(', ', $missingArguments))); + throw new RuntimeException(\sprintf('Not enough arguments (missing: "%s").', implode(', ', $missingArguments))); } } @@ -99,7 +99,7 @@ public function getArguments(): array public function getArgument(string $name): mixed { if (!$this->definition->hasArgument($name)) { - throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); } return $this->arguments[$name] ?? $this->definition->getArgument($name)->getDefault(); @@ -111,7 +111,7 @@ public function getArgument(string $name): mixed public function setArgument(string $name, mixed $value) { if (!$this->definition->hasArgument($name)) { - throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); } $this->arguments[$name] = $value; @@ -138,7 +138,7 @@ public function getOption(string $name): mixed } if (!$this->definition->hasOption($name)) { - throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "%s" option does not exist.', $name)); } return \array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault(); @@ -154,7 +154,7 @@ public function setOption(string $name, mixed $value) return; } elseif (!$this->definition->hasOption($name)) { - throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "%s" option does not exist.', $name)); } $this->options[$name] = $value; diff --git a/app/vendor/symfony/console/Input/InputArgument.php b/app/vendor/symfony/console/Input/InputArgument.php index 4ef79feb7..fd203919f 100644 --- a/app/vendor/symfony/console/Input/InputArgument.php +++ b/app/vendor/symfony/console/Input/InputArgument.php @@ -31,7 +31,7 @@ class InputArgument private string $name; private int $mode; - private string|int|bool|array|null|float $default; + private string|int|bool|array|float|null $default; private array|\Closure $suggestedValues; private string $description; @@ -49,7 +49,7 @@ public function __construct(string $name, ?int $mode = null, string $description if (null === $mode) { $mode = self::OPTIONAL; } elseif ($mode > 7 || $mode < 1) { - throw new InvalidArgumentException(sprintf('Argument mode "%s" is not valid.', $mode)); + throw new InvalidArgumentException(\sprintf('Argument mode "%s" is not valid.', $mode)); } $this->name = $name; @@ -137,7 +137,7 @@ public function complete(CompletionInput $input, CompletionSuggestions $suggesti { $values = $this->suggestedValues; if ($values instanceof \Closure && !\is_array($values = $values($input))) { - throw new LogicException(sprintf('Closure for argument "%s" must return an array. Got "%s".', $this->name, get_debug_type($values))); + throw new LogicException(\sprintf('Closure for argument "%s" must return an array. Got "%s".', $this->name, get_debug_type($values))); } if ($values) { $suggestions->suggestValues($values); diff --git a/app/vendor/symfony/console/Input/InputDefinition.php b/app/vendor/symfony/console/Input/InputDefinition.php index b7162d770..b5c202838 100644 --- a/app/vendor/symfony/console/Input/InputDefinition.php +++ b/app/vendor/symfony/console/Input/InputDefinition.php @@ -105,15 +105,15 @@ public function addArguments(?array $arguments = []) public function addArgument(InputArgument $argument) { if (isset($this->arguments[$argument->getName()])) { - throw new LogicException(sprintf('An argument with name "%s" already exists.', $argument->getName())); + throw new LogicException(\sprintf('An argument with name "%s" already exists.', $argument->getName())); } if (null !== $this->lastArrayArgument) { - throw new LogicException(sprintf('Cannot add a required argument "%s" after an array argument "%s".', $argument->getName(), $this->lastArrayArgument->getName())); + throw new LogicException(\sprintf('Cannot add a required argument "%s" after an array argument "%s".', $argument->getName(), $this->lastArrayArgument->getName())); } if ($argument->isRequired() && null !== $this->lastOptionalArgument) { - throw new LogicException(sprintf('Cannot add a required argument "%s" after an optional one "%s".', $argument->getName(), $this->lastOptionalArgument->getName())); + throw new LogicException(\sprintf('Cannot add a required argument "%s" after an optional one "%s".', $argument->getName(), $this->lastOptionalArgument->getName())); } if ($argument->isArray()) { @@ -137,7 +137,7 @@ public function addArgument(InputArgument $argument) public function getArgument(string|int $name): InputArgument { if (!$this->hasArgument($name)) { - throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "%s" argument does not exist.', $name)); } $arguments = \is_int($name) ? array_values($this->arguments) : $this->arguments; @@ -231,16 +231,16 @@ public function addOptions(array $options = []) public function addOption(InputOption $option) { if (isset($this->options[$option->getName()]) && !$option->equals($this->options[$option->getName()])) { - throw new LogicException(sprintf('An option named "%s" already exists.', $option->getName())); + throw new LogicException(\sprintf('An option named "%s" already exists.', $option->getName())); } if (isset($this->negations[$option->getName()])) { - throw new LogicException(sprintf('An option named "%s" already exists.', $option->getName())); + throw new LogicException(\sprintf('An option named "%s" already exists.', $option->getName())); } if ($option->getShortcut()) { foreach (explode('|', $option->getShortcut()) as $shortcut) { if (isset($this->shortcuts[$shortcut]) && !$option->equals($this->options[$this->shortcuts[$shortcut]])) { - throw new LogicException(sprintf('An option with shortcut "%s" already exists.', $shortcut)); + throw new LogicException(\sprintf('An option with shortcut "%s" already exists.', $shortcut)); } } } @@ -255,7 +255,7 @@ public function addOption(InputOption $option) if ($option->isNegatable()) { $negatedName = 'no-'.$option->getName(); if (isset($this->options[$negatedName])) { - throw new LogicException(sprintf('An option named "%s" already exists.', $negatedName)); + throw new LogicException(\sprintf('An option named "%s" already exists.', $negatedName)); } $this->negations[$negatedName] = $option->getName(); } @@ -269,7 +269,7 @@ public function addOption(InputOption $option) public function getOption(string $name): InputOption { if (!$this->hasOption($name)) { - throw new InvalidArgumentException(sprintf('The "--%s" option does not exist.', $name)); + throw new InvalidArgumentException(\sprintf('The "--%s" option does not exist.', $name)); } return $this->options[$name]; @@ -343,7 +343,7 @@ public function getOptionDefaults(): array public function shortcutToName(string $shortcut): string { if (!isset($this->shortcuts[$shortcut])) { - throw new InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut)); + throw new InvalidArgumentException(\sprintf('The "-%s" option does not exist.', $shortcut)); } return $this->shortcuts[$shortcut]; @@ -359,7 +359,7 @@ public function shortcutToName(string $shortcut): string public function negationToName(string $negation): string { if (!isset($this->negations[$negation])) { - throw new InvalidArgumentException(sprintf('The "--%s" option does not exist.', $negation)); + throw new InvalidArgumentException(\sprintf('The "--%s" option does not exist.', $negation)); } return $this->negations[$negation]; @@ -378,7 +378,7 @@ public function getSynopsis(bool $short = false): string foreach ($this->getOptions() as $option) { $value = ''; if ($option->acceptValue()) { - $value = sprintf( + $value = \sprintf( ' %s%s%s', $option->isValueOptional() ? '[' : '', strtoupper($option->getName()), @@ -386,9 +386,9 @@ public function getSynopsis(bool $short = false): string ); } - $shortcut = $option->getShortcut() ? sprintf('-%s|', $option->getShortcut()) : ''; - $negation = $option->isNegatable() ? sprintf('|--no-%s', $option->getName()) : ''; - $elements[] = sprintf('[%s--%s%s%s]', $shortcut, $option->getName(), $value, $negation); + $shortcut = $option->getShortcut() ? \sprintf('-%s|', $option->getShortcut()) : ''; + $negation = $option->isNegatable() ? \sprintf('|--no-%s', $option->getName()) : ''; + $elements[] = \sprintf('[%s--%s%s%s]', $shortcut, $option->getName(), $value, $negation); } } diff --git a/app/vendor/symfony/console/Input/InputOption.php b/app/vendor/symfony/console/Input/InputOption.php index bb533801f..3adc8c424 100644 --- a/app/vendor/symfony/console/Input/InputOption.php +++ b/app/vendor/symfony/console/Input/InputOption.php @@ -53,7 +53,7 @@ class InputOption private string $name; private string|array|null $shortcut; private int $mode; - private string|int|bool|array|null|float $default; + private string|int|bool|array|float|null $default; private array|\Closure $suggestedValues; private string $description; @@ -95,7 +95,7 @@ public function __construct(string $name, string|array|null $shortcut = null, ?i if (null === $mode) { $mode = self::VALUE_NONE; } elseif ($mode >= (self::VALUE_NEGATABLE << 1) || $mode < 1) { - throw new InvalidArgumentException(sprintf('Option mode "%s" is not valid.', $mode)); + throw new InvalidArgumentException(\sprintf('Option mode "%s" is not valid.', $mode)); } $this->name = $name; @@ -231,7 +231,7 @@ public function complete(CompletionInput $input, CompletionSuggestions $suggesti { $values = $this->suggestedValues; if ($values instanceof \Closure && !\is_array($values = $values($input))) { - throw new LogicException(sprintf('Closure for option "%s" must return an array. Got "%s".', $this->name, get_debug_type($values))); + throw new LogicException(\sprintf('Closure for option "%s" must return an array. Got "%s".', $this->name, get_debug_type($values))); } if ($values) { $suggestions->suggestValues($values); diff --git a/app/vendor/symfony/console/Input/StringInput.php b/app/vendor/symfony/console/Input/StringInput.php index 82bd21440..9b94784af 100644 --- a/app/vendor/symfony/console/Input/StringInput.php +++ b/app/vendor/symfony/console/Input/StringInput.php @@ -72,7 +72,7 @@ private function tokenize(string $input): array $token .= $match[1]; } else { // should never happen - throw new InvalidArgumentException(sprintf('Unable to parse input near "... %s ...".', substr($input, $cursor, 10))); + throw new InvalidArgumentException(\sprintf('Unable to parse input near "... %s ...".', substr($input, $cursor, 10))); } $cursor += \strlen($match[0]); diff --git a/app/vendor/symfony/console/Logger/ConsoleLogger.php b/app/vendor/symfony/console/Logger/ConsoleLogger.php index fddef50cd..70432b7de 100644 --- a/app/vendor/symfony/console/Logger/ConsoleLogger.php +++ b/app/vendor/symfony/console/Logger/ConsoleLogger.php @@ -62,7 +62,7 @@ public function __construct(OutputInterface $output, array $verbosityLevelMap = public function log($level, $message, array $context = []): void { if (!isset($this->verbosityLevelMap[$level])) { - throw new InvalidArgumentException(sprintf('The log level "%s" does not exist.', $level)); + throw new InvalidArgumentException(\sprintf('The log level "%s" does not exist.', $level)); } $output = $this->output; @@ -78,7 +78,7 @@ public function log($level, $message, array $context = []): void // the if condition check isn't necessary -- it's the same one that $output will do internally anyway. // We only do it for efficiency here as the message formatting is relatively expensive. if ($output->getVerbosity() >= $this->verbosityLevelMap[$level]) { - $output->writeln(sprintf('<%1$s>[%2$s] %3$s', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context)), $this->verbosityLevelMap[$level]); + $output->writeln(\sprintf('<%1$s>[%2$s] %3$s', $this->formatLevelMap[$level], $level, $this->interpolate($message, $context)), $this->verbosityLevelMap[$level]); } } diff --git a/app/vendor/symfony/console/Messenger/RunCommandMessageHandler.php b/app/vendor/symfony/console/Messenger/RunCommandMessageHandler.php index 14f9c1764..3f4286542 100644 --- a/app/vendor/symfony/console/Messenger/RunCommandMessageHandler.php +++ b/app/vendor/symfony/console/Messenger/RunCommandMessageHandler.php @@ -16,6 +16,8 @@ use Symfony\Component\Console\Exception\RunCommandFailedException; use Symfony\Component\Console\Input\StringInput; use Symfony\Component\Console\Output\BufferedOutput; +use Symfony\Component\Messenger\Exception\RecoverableExceptionInterface; +use Symfony\Component\Messenger\Exception\UnrecoverableExceptionInterface; /** * @author Kevin Bond @@ -35,12 +37,14 @@ public function __invoke(RunCommandMessage $message): RunCommandContext try { $exitCode = $this->application->run($input, $output); + } catch (UnrecoverableExceptionInterface|RecoverableExceptionInterface $e) { + throw $e; } catch (\Throwable $e) { throw new RunCommandFailedException($e, new RunCommandContext($message, Command::FAILURE, $output->fetch())); } if ($message->throwOnFailure && Command::SUCCESS !== $exitCode) { - throw new RunCommandFailedException(sprintf('Command "%s" exited with code "%s".', $message->input, $exitCode), new RunCommandContext($message, $exitCode, $output->fetch())); + throw new RunCommandFailedException(\sprintf('Command "%s" exited with code "%s".', $message->input, $exitCode), new RunCommandContext($message, $exitCode, $output->fetch())); } return new RunCommandContext($message, $exitCode, $output->fetch()); diff --git a/app/vendor/symfony/console/Output/AnsiColorMode.php b/app/vendor/symfony/console/Output/AnsiColorMode.php index 5f9f744fe..dcdd1d5c4 100644 --- a/app/vendor/symfony/console/Output/AnsiColorMode.php +++ b/app/vendor/symfony/console/Output/AnsiColorMode.php @@ -51,7 +51,7 @@ public function convertFromHexToAnsiColorCode(string $hexColor): string } if (6 !== \strlen($hexColor)) { - throw new InvalidArgumentException(sprintf('Invalid "#%s" color.', $hexColor)); + throw new InvalidArgumentException(\sprintf('Invalid "#%s" color.', $hexColor)); } $color = hexdec($hexColor); @@ -63,7 +63,7 @@ public function convertFromHexToAnsiColorCode(string $hexColor): string return match ($this) { self::Ansi4 => (string) $this->convertFromRGB($r, $g, $b), self::Ansi8 => '8;5;'.((string) $this->convertFromRGB($r, $g, $b)), - self::Ansi24 => sprintf('8;2;%d;%d;%d', $r, $g, $b) + self::Ansi24 => \sprintf('8;2;%d;%d;%d', $r, $g, $b), }; } @@ -72,7 +72,7 @@ private function convertFromRGB(int $r, int $g, int $b): int return match ($this) { self::Ansi4 => $this->degradeHexColorToAnsi4($r, $g, $b), self::Ansi8 => $this->degradeHexColorToAnsi8($r, $g, $b), - default => throw new InvalidArgumentException("RGB cannot be converted to {$this->name}.") + default => throw new InvalidArgumentException("RGB cannot be converted to {$this->name}."), }; } diff --git a/app/vendor/symfony/console/Output/ConsoleSectionOutput.php b/app/vendor/symfony/console/Output/ConsoleSectionOutput.php index f2d7933bb..04d587cf2 100644 --- a/app/vendor/symfony/console/Output/ConsoleSectionOutput.php +++ b/app/vendor/symfony/console/Output/ConsoleSectionOutput.php @@ -229,7 +229,7 @@ private function popStreamContentUntilCurrentSection(int $numberOfLinesToClearFr if ($numberOfLinesToClear > 0) { // move cursor up n lines - parent::doWrite(sprintf("\x1b[%dA", $numberOfLinesToClear), false); + parent::doWrite(\sprintf("\x1b[%dA", $numberOfLinesToClear), false); // erase to end of screen parent::doWrite("\x1b[0J", false); } diff --git a/app/vendor/symfony/console/Output/StreamOutput.php b/app/vendor/symfony/console/Output/StreamOutput.php index 218bc9ef2..f51d03763 100644 --- a/app/vendor/symfony/console/Output/StreamOutput.php +++ b/app/vendor/symfony/console/Output/StreamOutput.php @@ -93,7 +93,7 @@ protected function doWrite(string $message, bool $newline) protected function hasColorSupport(): bool { // Follow https://no-color.org/ - if (isset($_SERVER['NO_COLOR']) || false !== getenv('NO_COLOR')) { + if ('' !== (($_SERVER['NO_COLOR'] ?? getenv('NO_COLOR'))[0] ?? '')) { return false; } diff --git a/app/vendor/symfony/console/Output/TrimmedBufferOutput.php b/app/vendor/symfony/console/Output/TrimmedBufferOutput.php index 23a2be8c3..90ee45aae 100644 --- a/app/vendor/symfony/console/Output/TrimmedBufferOutput.php +++ b/app/vendor/symfony/console/Output/TrimmedBufferOutput.php @@ -27,7 +27,7 @@ class TrimmedBufferOutput extends Output public function __construct(int $maxLength, ?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, ?OutputFormatterInterface $formatter = null) { if ($maxLength <= 0) { - throw new InvalidArgumentException(sprintf('"%s()" expects a strictly positive maxLength. Got %d.', __METHOD__, $maxLength)); + throw new InvalidArgumentException(\sprintf('"%s()" expects a strictly positive maxLength. Got %d.', __METHOD__, $maxLength)); } parent::__construct($verbosity, $decorated, $formatter); diff --git a/app/vendor/symfony/console/Question/ChoiceQuestion.php b/app/vendor/symfony/console/Question/ChoiceQuestion.php index e449ff683..9445ccc0c 100644 --- a/app/vendor/symfony/console/Question/ChoiceQuestion.php +++ b/app/vendor/symfony/console/Question/ChoiceQuestion.php @@ -26,11 +26,11 @@ class ChoiceQuestion extends Question private string $errorMessage = 'Value "%s" is invalid'; /** - * @param string $question The question to ask to the user - * @param array $choices The list of available choices - * @param mixed $default The default answer to return + * @param string $question The question to ask to the user + * @param array $choices The list of available choices + * @param string|bool|int|float|null $default The default answer to return */ - public function __construct(string $question, array $choices, mixed $default = null) + public function __construct(string $question, array $choices, string|bool|int|float|null $default = null) { if (!$choices) { throw new \LogicException('Choice question must have at least 1 choice available.'); @@ -120,7 +120,7 @@ private function getDefaultValidator(): callable if ($multiselect) { // Check for a separated comma values if (!preg_match('/^[^,]+(?:,[^,]+)*$/', (string) $selected, $matches)) { - throw new InvalidArgumentException(sprintf($errorMessage, $selected)); + throw new InvalidArgumentException(\sprintf($errorMessage, $selected)); } $selectedChoices = explode(',', (string) $selected); @@ -144,7 +144,7 @@ private function getDefaultValidator(): callable } if (\count($results) > 1) { - throw new InvalidArgumentException(sprintf('The provided answer is ambiguous. Value should be one of "%s".', implode('" or "', $results))); + throw new InvalidArgumentException(\sprintf('The provided answer is ambiguous. Value should be one of "%s".', implode('" or "', $results))); } $result = array_search($value, $choices); @@ -160,7 +160,7 @@ private function getDefaultValidator(): callable } if (false === $result) { - throw new InvalidArgumentException(sprintf($errorMessage, $value)); + throw new InvalidArgumentException(\sprintf($errorMessage, $value)); } // For associative choices, consistently return the key as string: diff --git a/app/vendor/symfony/console/Question/Question.php b/app/vendor/symfony/console/Question/Question.php index 94c688fa8..ecbde56d5 100644 --- a/app/vendor/symfony/console/Question/Question.php +++ b/app/vendor/symfony/console/Question/Question.php @@ -27,7 +27,7 @@ class Question private bool $hiddenFallback = true; private ?\Closure $autocompleterCallback = null; private ?\Closure $validator = null; - private string|int|bool|null|float $default; + private string|int|bool|float|null $default; private ?\Closure $normalizer = null; private bool $trimmable = true; private bool $multiline = false; diff --git a/app/vendor/symfony/console/Resources/completion.bash b/app/vendor/symfony/console/Resources/completion.bash index 0d76eacc3..64c6a338f 100644 --- a/app/vendor/symfony/console/Resources/completion.bash +++ b/app/vendor/symfony/console/Resources/completion.bash @@ -17,7 +17,7 @@ _sf_{{ COMMAND_NAME }}() { done # Use newline as only separator to allow space in completion values - IFS=$'\n' + local IFS=$'\n' local sf_cmd="${COMP_WORDS[0]}" # for an alias, get the real script behind it diff --git a/app/vendor/symfony/console/SignalRegistry/SignalMap.php b/app/vendor/symfony/console/SignalRegistry/SignalMap.php index de419bda7..2f9aa67c1 100644 --- a/app/vendor/symfony/console/SignalRegistry/SignalMap.php +++ b/app/vendor/symfony/console/SignalRegistry/SignalMap.php @@ -27,7 +27,7 @@ public static function getSignalName(int $signal): ?string if (!isset(self::$map)) { $r = new \ReflectionExtension('pcntl'); $c = $r->getConstants(); - $map = array_filter($c, fn ($k) => str_starts_with($k, 'SIG') && !str_starts_with($k, 'SIG_'), \ARRAY_FILTER_USE_KEY); + $map = array_filter($c, fn ($k) => str_starts_with($k, 'SIG') && !str_starts_with($k, 'SIG_') && 'SIGBABY' !== $k, \ARRAY_FILTER_USE_KEY); self::$map = array_flip($map); } diff --git a/app/vendor/symfony/console/Style/SymfonyStyle.php b/app/vendor/symfony/console/Style/SymfonyStyle.php index 03bda8784..135f4fd0e 100644 --- a/app/vendor/symfony/console/Style/SymfonyStyle.php +++ b/app/vendor/symfony/console/Style/SymfonyStyle.php @@ -79,8 +79,8 @@ public function title(string $message) { $this->autoPrependBlock(); $this->writeln([ - sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), - sprintf('%s', str_repeat('=', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))), + \sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), + \sprintf('%s', str_repeat('=', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))), ]); $this->newLine(); } @@ -92,8 +92,8 @@ public function section(string $message) { $this->autoPrependBlock(); $this->writeln([ - sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), - sprintf('%s', str_repeat('-', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))), + \sprintf('%s', OutputFormatter::escapeTrailingBackslash($message)), + \sprintf('%s', str_repeat('-', Helper::width(Helper::removeDecoration($this->getFormatter(), $message)))), ]); $this->newLine(); } @@ -104,7 +104,7 @@ public function section(string $message) public function listing(array $elements) { $this->autoPrependText(); - $elements = array_map(fn ($element) => sprintf(' * %s', $element), $elements); + $elements = array_map(fn ($element) => \sprintf(' * %s', $element), $elements); $this->writeln($elements); $this->newLine(); @@ -119,7 +119,7 @@ public function text(string|array $message) $messages = \is_array($message) ? array_values($message) : [$message]; foreach ($messages as $message) { - $this->writeln(sprintf(' %s', $message)); + $this->writeln(\sprintf(' %s', $message)); } } @@ -463,7 +463,7 @@ private function createBlock(iterable $messages, ?string $type = null, ?string $ $lines = []; if (null !== $type) { - $type = sprintf('[%s] ', $type); + $type = \sprintf('[%s] ', $type); $indentLength = Helper::width($type); $lineIndentation = str_repeat(' ', $indentLength); } @@ -505,7 +505,7 @@ private function createBlock(iterable $messages, ?string $type = null, ?string $ $line .= str_repeat(' ', max($this->lineLength - Helper::width(Helper::removeDecoration($this->getFormatter(), $line)), 0)); if ($style) { - $line = sprintf('<%s>%s', $style, $line); + $line = \sprintf('<%s>%s', $style, $line); } } diff --git a/app/vendor/symfony/console/Terminal.php b/app/vendor/symfony/console/Terminal.php index 3eda0376b..f094adedc 100644 --- a/app/vendor/symfony/console/Terminal.php +++ b/app/vendor/symfony/console/Terminal.php @@ -217,8 +217,7 @@ private static function readFromProcess(string|array $command): ?string $cp = \function_exists('sapi_windows_cp_set') ? sapi_windows_cp_get() : 0; - $process = proc_open($command, $descriptorspec, $pipes, null, null, ['suppress_errors' => true]); - if (!\is_resource($process)) { + if (!$process = @proc_open($command, $descriptorspec, $pipes, null, null, ['suppress_errors' => true])) { return null; } diff --git a/app/vendor/symfony/console/Tester/Constraint/CommandIsSuccessful.php b/app/vendor/symfony/console/Tester/Constraint/CommandIsSuccessful.php index 09c6194b9..d677c27aa 100644 --- a/app/vendor/symfony/console/Tester/Constraint/CommandIsSuccessful.php +++ b/app/vendor/symfony/console/Tester/Constraint/CommandIsSuccessful.php @@ -38,6 +38,6 @@ protected function additionalFailureDescription($other): string Command::INVALID => 'Command was invalid.', ]; - return $mapping[$other] ?? sprintf('Command returned exit status %d.', $other); + return $mapping[$other] ?? \sprintf('Command returned exit status %d.', $other); } } diff --git a/app/vendor/symfony/deprecation-contracts/composer.json b/app/vendor/symfony/deprecation-contracts/composer.json index c6d02d874..5533b5c3f 100644 --- a/app/vendor/symfony/deprecation-contracts/composer.json +++ b/app/vendor/symfony/deprecation-contracts/composer.json @@ -25,7 +25,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.6-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/app/vendor/symfony/filesystem/CHANGELOG.md b/app/vendor/symfony/filesystem/CHANGELOG.md index b4bd22eb5..80818d1b5 100644 --- a/app/vendor/symfony/filesystem/CHANGELOG.md +++ b/app/vendor/symfony/filesystem/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +7.1 +--- + + * Add the `Filesystem::readFile()` method + 7.0 --- diff --git a/app/vendor/symfony/filesystem/Exception/FileNotFoundException.php b/app/vendor/symfony/filesystem/Exception/FileNotFoundException.php index 06b732b16..d0d27977d 100644 --- a/app/vendor/symfony/filesystem/Exception/FileNotFoundException.php +++ b/app/vendor/symfony/filesystem/Exception/FileNotFoundException.php @@ -25,7 +25,7 @@ public function __construct(?string $message = null, int $code = 0, ?\Throwable if (null === $path) { $message = 'File could not be found.'; } else { - $message = sprintf('File "%s" could not be found.', $path); + $message = \sprintf('File "%s" could not be found.', $path); } } diff --git a/app/vendor/symfony/filesystem/Exception/IOException.php b/app/vendor/symfony/filesystem/Exception/IOException.php index df3a0850a..46ab8b4a5 100644 --- a/app/vendor/symfony/filesystem/Exception/IOException.php +++ b/app/vendor/symfony/filesystem/Exception/IOException.php @@ -20,12 +20,12 @@ */ class IOException extends \RuntimeException implements IOExceptionInterface { - private ?string $path; - - public function __construct(string $message, int $code = 0, ?\Throwable $previous = null, ?string $path = null) - { - $this->path = $path; - + public function __construct( + string $message, + int $code = 0, + ?\Throwable $previous = null, + private ?string $path = null, + ) { parent::__construct($message, $code, $previous); } diff --git a/app/vendor/symfony/filesystem/Filesystem.php b/app/vendor/symfony/filesystem/Filesystem.php index b7fc70118..bfe387803 100644 --- a/app/vendor/symfony/filesystem/Filesystem.php +++ b/app/vendor/symfony/filesystem/Filesystem.php @@ -38,25 +38,25 @@ public function copy(string $originFile, string $targetFile, bool $overwriteNewe { $originIsLocal = stream_is_local($originFile) || 0 === stripos($originFile, 'file://'); if ($originIsLocal && !is_file($originFile)) { - throw new FileNotFoundException(sprintf('Failed to copy "%s" because file does not exist.', $originFile), 0, null, $originFile); + throw new FileNotFoundException(\sprintf('Failed to copy "%s" because file does not exist.', $originFile), 0, null, $originFile); } $this->mkdir(\dirname($targetFile)); $doCopy = true; - if (!$overwriteNewerFiles && null === parse_url($originFile, \PHP_URL_HOST) && is_file($targetFile)) { + if (!$overwriteNewerFiles && !parse_url($originFile, \PHP_URL_HOST) && is_file($targetFile)) { $doCopy = filemtime($originFile) > filemtime($targetFile); } if ($doCopy) { // https://bugs.php.net/64634 if (!$source = self::box('fopen', $originFile, 'r')) { - throw new IOException(sprintf('Failed to copy "%s" to "%s" because source file could not be opened for reading: ', $originFile, $targetFile).self::$lastError, 0, null, $originFile); + throw new IOException(\sprintf('Failed to copy "%s" to "%s" because source file could not be opened for reading: ', $originFile, $targetFile).self::$lastError, 0, null, $originFile); } // Stream context created to allow files overwrite when using FTP stream wrapper - disabled by default if (!$target = self::box('fopen', $targetFile, 'w', false, stream_context_create(['ftp' => ['overwrite' => true]]))) { - throw new IOException(sprintf('Failed to copy "%s" to "%s" because target file could not be opened for writing: ', $originFile, $targetFile).self::$lastError, 0, null, $originFile); + throw new IOException(\sprintf('Failed to copy "%s" to "%s" because target file could not be opened for writing: ', $originFile, $targetFile).self::$lastError, 0, null, $originFile); } $bytesCopied = stream_copy_to_stream($source, $target); @@ -65,15 +65,18 @@ public function copy(string $originFile, string $targetFile, bool $overwriteNewe unset($source, $target); if (!is_file($targetFile)) { - throw new IOException(sprintf('Failed to copy "%s" to "%s".', $originFile, $targetFile), 0, null, $originFile); + throw new IOException(\sprintf('Failed to copy "%s" to "%s".', $originFile, $targetFile), 0, null, $originFile); } if ($originIsLocal) { // Like `cp`, preserve executable permission bits self::box('chmod', $targetFile, fileperms($targetFile) | (fileperms($originFile) & 0111)); + // Like `cp`, preserve the file modification time + self::box('touch', $targetFile, filemtime($originFile)); + if ($bytesCopied !== $bytesOrigin = filesize($originFile)) { - throw new IOException(sprintf('Failed to copy the whole content of "%s" to "%s" (%g of %g bytes copied).', $originFile, $targetFile, $bytesCopied, $bytesOrigin), 0, null, $originFile); + throw new IOException(\sprintf('Failed to copy the whole content of "%s" to "%s" (%g of %g bytes copied).', $originFile, $targetFile, $bytesCopied, $bytesOrigin), 0, null, $originFile); } } } @@ -92,7 +95,7 @@ public function mkdir(string|iterable $dirs, int $mode = 0777): void } if (!self::box('mkdir', $dir, $mode, true) && !is_dir($dir)) { - throw new IOException(sprintf('Failed to create "%s": ', $dir).self::$lastError, 0, null, $dir); + throw new IOException(\sprintf('Failed to create "%s": ', $dir).self::$lastError, 0, null, $dir); } } } @@ -106,7 +109,7 @@ public function exists(string|iterable $files): bool foreach ($this->toIterable($files) as $file) { if (\strlen($file) > $maxPathLength) { - throw new IOException(sprintf('Could not check if file exist because path length exceeds %d characters.', $maxPathLength), 0, null, $file); + throw new IOException(\sprintf('Could not check if file exist because path length exceeds %d characters.', $maxPathLength), 0, null, $file); } if (!file_exists($file)) { @@ -129,7 +132,7 @@ public function touch(string|iterable $files, ?int $time = null, ?int $atime = n { foreach ($this->toIterable($files) as $file) { if (!($time ? self::box('touch', $file, $time, $atime) : self::box('touch', $file))) { - throw new IOException(sprintf('Failed to touch "%s": ', $file).self::$lastError, 0, null, $file); + throw new IOException(\sprintf('Failed to touch "%s": ', $file).self::$lastError, 0, null, $file); } } } @@ -157,11 +160,11 @@ private static function doRemove(array $files, bool $isRecursive): void if (is_link($file)) { // See https://bugs.php.net/52176 if (!(self::box('unlink', $file) || '\\' !== \DIRECTORY_SEPARATOR || self::box('rmdir', $file)) && file_exists($file)) { - throw new IOException(sprintf('Failed to remove symlink "%s": ', $file).self::$lastError); + throw new IOException(\sprintf('Failed to remove symlink "%s": ', $file).self::$lastError); } } elseif (is_dir($file)) { if (!$isRecursive) { - $tmpName = \dirname(realpath($file)).'/.'.strrev(strtr(base64_encode(random_bytes(2)), '/=', '-_')); + $tmpName = \dirname(realpath($file)).'/.!'.strrev(strtr(base64_encode(random_bytes(2)), '/=', '-!')); if (file_exists($tmpName)) { try { @@ -188,10 +191,10 @@ private static function doRemove(array $files, bool $isRecursive): void $file = $origFile; } - throw new IOException(sprintf('Failed to remove directory "%s": ', $file).$lastError); + throw new IOException(\sprintf('Failed to remove directory "%s": ', $file).$lastError); } - } elseif (!self::box('unlink', $file) && (str_contains(self::$lastError, 'Permission denied') || file_exists($file))) { - throw new IOException(sprintf('Failed to remove file "%s": ', $file).self::$lastError); + } elseif (!self::box('unlink', $file) && ((self::$lastError && str_contains(self::$lastError, 'Permission denied')) || file_exists($file))) { + throw new IOException(\sprintf('Failed to remove file "%s": ', $file).self::$lastError); } } } @@ -209,7 +212,7 @@ public function chmod(string|iterable $files, int $mode, int $umask = 0000, bool { foreach ($this->toIterable($files) as $file) { if (!self::box('chmod', $file, $mode & ~$umask)) { - throw new IOException(sprintf('Failed to chmod file "%s": ', $file).self::$lastError, 0, null, $file); + throw new IOException(\sprintf('Failed to chmod file "%s": ', $file).self::$lastError, 0, null, $file); } if ($recursive && is_dir($file) && !is_link($file)) { $this->chmod(new \FilesystemIterator($file), $mode, $umask, true); @@ -220,6 +223,10 @@ public function chmod(string|iterable $files, int $mode, int $umask = 0000, bool /** * Change the owner of an array of files or directories. * + * This method always throws on Windows, as the underlying PHP function is not supported. + * + * @see https://php.net/chown + * * @param string|int $user A user name or number * @param bool $recursive Whether change the owner recursively or not * @@ -233,11 +240,11 @@ public function chown(string|iterable $files, string|int $user, bool $recursive } if (is_link($file) && \function_exists('lchown')) { if (!self::box('lchown', $file, $user)) { - throw new IOException(sprintf('Failed to chown file "%s": ', $file).self::$lastError, 0, null, $file); + throw new IOException(\sprintf('Failed to chown file "%s": ', $file).self::$lastError, 0, null, $file); } } else { if (!self::box('chown', $file, $user)) { - throw new IOException(sprintf('Failed to chown file "%s": ', $file).self::$lastError, 0, null, $file); + throw new IOException(\sprintf('Failed to chown file "%s": ', $file).self::$lastError, 0, null, $file); } } } @@ -246,6 +253,10 @@ public function chown(string|iterable $files, string|int $user, bool $recursive /** * Change the group of an array of files or directories. * + * This method always throws on Windows, as the underlying PHP function is not supported. + * + * @see https://php.net/chgrp + * * @param string|int $group A group name or number * @param bool $recursive Whether change the group recursively or not * @@ -259,11 +270,11 @@ public function chgrp(string|iterable $files, string|int $group, bool $recursive } if (is_link($file) && \function_exists('lchgrp')) { if (!self::box('lchgrp', $file, $group)) { - throw new IOException(sprintf('Failed to chgrp file "%s": ', $file).self::$lastError, 0, null, $file); + throw new IOException(\sprintf('Failed to chgrp file "%s": ', $file).self::$lastError, 0, null, $file); } } else { if (!self::box('chgrp', $file, $group)) { - throw new IOException(sprintf('Failed to chgrp file "%s": ', $file).self::$lastError, 0, null, $file); + throw new IOException(\sprintf('Failed to chgrp file "%s": ', $file).self::$lastError, 0, null, $file); } } } @@ -279,7 +290,7 @@ public function rename(string $origin, string $target, bool $overwrite = false): { // we check that target does not exist if (!$overwrite && $this->isReadable($target)) { - throw new IOException(sprintf('Cannot rename because the target "%s" already exists.', $target), 0, null, $target); + throw new IOException(\sprintf('Cannot rename because the target "%s" already exists.', $target), 0, null, $target); } if (!self::box('rename', $origin, $target)) { @@ -290,7 +301,7 @@ public function rename(string $origin, string $target, bool $overwrite = false): return; } - throw new IOException(sprintf('Cannot rename "%s" to "%s": ', $origin, $target).self::$lastError, 0, null, $target); + throw new IOException(\sprintf('Cannot rename "%s" to "%s": ', $origin, $target).self::$lastError, 0, null, $target); } } @@ -304,7 +315,7 @@ private function isReadable(string $filename): bool $maxPathLength = \PHP_MAXPATHLEN - 2; if (\strlen($filename) > $maxPathLength) { - throw new IOException(sprintf('Could not check if file is readable because path length exceeds %d characters.', $maxPathLength), 0, null, $filename); + throw new IOException(\sprintf('Could not check if file is readable because path length exceeds %d characters.', $maxPathLength), 0, null, $filename); } return is_readable($filename); @@ -361,7 +372,7 @@ public function hardlink(string $originFile, string|iterable $targetFiles): void } if (!is_file($originFile)) { - throw new FileNotFoundException(sprintf('Origin file "%s" is not a file.', $originFile)); + throw new FileNotFoundException(\sprintf('Origin file "%s" is not a file.', $originFile)); } foreach ($this->toIterable($targetFiles) as $targetFile) { @@ -385,10 +396,10 @@ private function linkException(string $origin, string $target, string $linkType) { if (self::$lastError) { if ('\\' === \DIRECTORY_SEPARATOR && str_contains(self::$lastError, 'error code(1314)')) { - throw new IOException(sprintf('Unable to create "%s" link due to error code 1314: \'A required privilege is not held by the client\'. Do you have the required Administrator-rights?', $linkType), 0, null, $target); + throw new IOException(\sprintf('Unable to create "%s" link due to error code 1314: \'A required privilege is not held by the client\'. Do you have the required Administrator-rights?', $linkType), 0, null, $target); } } - throw new IOException(sprintf('Failed to create "%s" link from "%s" to "%s": ', $linkType, $origin, $target).self::$lastError, 0, null, $target); + throw new IOException(\sprintf('Failed to create "%s" link from "%s" to "%s": ', $linkType, $origin, $target).self::$lastError, 0, null, $target); } /** @@ -425,11 +436,11 @@ public function readlink(string $path, bool $canonicalize = false): ?string public function makePathRelative(string $endPath, string $startPath): string { if (!$this->isAbsolutePath($startPath)) { - throw new InvalidArgumentException(sprintf('The start path "%s" is not absolute.', $startPath)); + throw new InvalidArgumentException(\sprintf('The start path "%s" is not absolute.', $startPath)); } if (!$this->isAbsolutePath($endPath)) { - throw new InvalidArgumentException(sprintf('The end path "%s" is not absolute.', $endPath)); + throw new InvalidArgumentException(\sprintf('The end path "%s" is not absolute.', $endPath)); } // Normalize separators on Windows @@ -515,7 +526,7 @@ public function mirror(string $originDir, string $targetDir, ?\Traversable $iter $originDirLen = \strlen($originDir); if (!$this->exists($originDir)) { - throw new IOException(sprintf('The origin directory specified "%s" was not found.', $originDir), 0, null, $originDir); + throw new IOException(\sprintf('The origin directory specified "%s" was not found.', $originDir), 0, null, $originDir); } // Iterate in destination folder to remove obsolete entries @@ -559,7 +570,7 @@ public function mirror(string $originDir, string $targetDir, ?\Traversable $iter } elseif (is_file($file)) { $this->copy($file, $target, $options['override'] ?? false); } else { - throw new IOException(sprintf('Unable to guess "%s" file type.', $file), 0, null, $file); + throw new IOException(\sprintf('Unable to guess "%s" file type.', $file), 0, null, $file); } } } @@ -608,7 +619,7 @@ public function tempnam(string $dir, string $prefix, string $suffix = ''): strin // Loop until we create a valid temp file or have reached 10 attempts for ($i = 0; $i < 10; ++$i) { // Create a unique filename - $tmpFile = $dir.'/'.$prefix.uniqid(mt_rand(), true).$suffix; + $tmpFile = $dir.'/'.$prefix.bin2hex(random_bytes(4)).$suffix; // Use fopen instead of file_exists as some streams do not support stat // Use mode 'x+' to atomically check existence and create to avoid a TOCTOU vulnerability @@ -635,7 +646,7 @@ public function tempnam(string $dir, string $prefix, string $suffix = ''): strin public function dumpFile(string $filename, $content): void { if (\is_array($content)) { - throw new \TypeError(sprintf('Argument 2 passed to "%s()" must be string or resource, array given.', __METHOD__)); + throw new \TypeError(\sprintf('Argument 2 passed to "%s()" must be string or resource, array given.', __METHOD__)); } $dir = \dirname($filename); @@ -656,14 +667,18 @@ public function dumpFile(string $filename, $content): void try { if (false === self::box('file_put_contents', $tmpFile, $content)) { - throw new IOException(sprintf('Failed to write file "%s": ', $filename).self::$lastError, 0, null, $filename); + throw new IOException(\sprintf('Failed to write file "%s": ', $filename).self::$lastError, 0, null, $filename); } - self::box('chmod', $tmpFile, file_exists($filename) ? fileperms($filename) : 0666 & ~umask()); + self::box('chmod', $tmpFile, self::box('fileperms', $filename) ?: 0666 & ~umask()); $this->rename($tmpFile, $filename, true); } finally { if (file_exists($tmpFile)) { + if ('\\' === \DIRECTORY_SEPARATOR && !is_writable($tmpFile)) { + self::box('chmod', $tmpFile, self::box('fileperms', $tmpFile) | 0200); + } + self::box('unlink', $tmpFile); } } @@ -680,7 +695,7 @@ public function dumpFile(string $filename, $content): void public function appendToFile(string $filename, $content, bool $lock = false): void { if (\is_array($content)) { - throw new \TypeError(sprintf('Argument 2 passed to "%s()" must be string or resource, array given.', __METHOD__)); + throw new \TypeError(\sprintf('Argument 2 passed to "%s()" must be string or resource, array given.', __METHOD__)); } $dir = \dirname($filename); @@ -690,10 +705,29 @@ public function appendToFile(string $filename, $content, bool $lock = false): vo } if (false === self::box('file_put_contents', $filename, $content, \FILE_APPEND | ($lock ? \LOCK_EX : 0))) { - throw new IOException(sprintf('Failed to write file "%s": ', $filename).self::$lastError, 0, null, $filename); + throw new IOException(\sprintf('Failed to write file "%s": ', $filename).self::$lastError, 0, null, $filename); } } + /** + * Returns the content of a file as a string. + * + * @throws IOException If the file cannot be read + */ + public function readFile(string $filename): string + { + if (is_dir($filename)) { + throw new IOException(\sprintf('Failed to read file "%s": File is a directory.', $filename)); + } + + $content = self::box('file_get_contents', $filename); + if (false === $content) { + throw new IOException(\sprintf('Failed to read file "%s": ', $filename).self::$lastError, 0, null, $filename); + } + + return $content; + } + private function toIterable(string|iterable $files): iterable { return is_iterable($files) ? $files : [$files]; @@ -712,7 +746,7 @@ private function getSchemeAndHierarchy(string $filename): array private static function assertFunctionExists(string $func): void { if (!\function_exists($func)) { - throw new IOException(sprintf('Unable to perform filesystem operation because the "%s()" function has been disabled.', $func)); + throw new IOException(\sprintf('Unable to perform filesystem operation because the "%s()" function has been disabled.', $func)); } } diff --git a/app/vendor/symfony/filesystem/Path.php b/app/vendor/symfony/filesystem/Path.php index 01b561724..2f2e87903 100644 --- a/app/vendor/symfony/filesystem/Path.php +++ b/app/vendor/symfony/filesystem/Path.php @@ -346,13 +346,13 @@ public static function changeExtension(string $path, string $extension): string $extension = ltrim($extension, '.'); // No extension for paths - if ('/' === substr($path, -1)) { + if (str_ends_with($path, '/')) { return $path; } // No actual extension in path - if (empty($actualExtension)) { - return $path.('.' === substr($path, -1) ? '' : '.').$extension; + if (!$actualExtension) { + return $path.(str_ends_with($path, '.') ? '' : '.').$extension; } return substr($path, 0, -\strlen($actualExtension)).$extension; @@ -365,7 +365,7 @@ public static function isAbsolute(string $path): bool } // Strip scheme - if (false !== $schemeSeparatorPosition = strpos($path, '://')) { + if (false !== ($schemeSeparatorPosition = strpos($path, '://')) && 1 !== $schemeSeparatorPosition) { $path = substr($path, $schemeSeparatorPosition + 3); } @@ -437,11 +437,11 @@ public static function isRelative(string $path): bool public static function makeAbsolute(string $path, string $basePath): string { if ('' === $basePath) { - throw new InvalidArgumentException(sprintf('The base path must be a non-empty string. Got: "%s".', $basePath)); + throw new InvalidArgumentException(\sprintf('The base path must be a non-empty string. Got: "%s".', $basePath)); } if (!self::isAbsolute($basePath)) { - throw new InvalidArgumentException(sprintf('The base path "%s" is not an absolute path.', $basePath)); + throw new InvalidArgumentException(\sprintf('The base path "%s" is not an absolute path.', $basePath)); } if (self::isAbsolute($path)) { @@ -531,12 +531,12 @@ public static function makeRelative(string $path, string $basePath): string // If the passed path is absolute, but the base path is not, we // cannot generate a relative path if ('' !== $root && '' === $baseRoot) { - throw new InvalidArgumentException(sprintf('The absolute path "%s" cannot be made relative to the relative path "%s". You should provide an absolute base path instead.', $path, $basePath)); + throw new InvalidArgumentException(\sprintf('The absolute path "%s" cannot be made relative to the relative path "%s". You should provide an absolute base path instead.', $path, $basePath)); } // Fail if the roots of the two paths are different if ($baseRoot && $root !== $baseRoot) { - throw new InvalidArgumentException(sprintf('The path "%s" cannot be made relative to "%s", because they have different roots ("%s" and "%s").', $path, $basePath, $root, $baseRoot)); + throw new InvalidArgumentException(\sprintf('The path "%s" cannot be made relative to "%s", because they have different roots ("%s" and "%s").', $path, $basePath, $root, $baseRoot)); } if ('' === $relativeBasePath) { @@ -668,7 +668,7 @@ public static function join(string ...$paths): string } // Only add slash if previous part didn't end with '/' or '\' - if (!\in_array(substr($finalPath, -1), ['/', '\\'])) { + if (!\in_array(substr($finalPath, -1), ['/', '\\'], true)) { $finalPath .= '/'; } diff --git a/app/vendor/symfony/filesystem/composer.json b/app/vendor/symfony/filesystem/composer.json index 1e054b682..c781e55b1 100644 --- a/app/vendor/symfony/filesystem/composer.json +++ b/app/vendor/symfony/filesystem/composer.json @@ -20,6 +20,9 @@ "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.8" }, + "require-dev": { + "symfony/process": "^6.4|^7.0" + }, "autoload": { "psr-4": { "Symfony\\Component\\Filesystem\\": "" }, "exclude-from-classmap": [ diff --git a/app/vendor/symfony/finder/Comparator/Comparator.php b/app/vendor/symfony/finder/Comparator/Comparator.php index bd6858347..41c02ac69 100644 --- a/app/vendor/symfony/finder/Comparator/Comparator.php +++ b/app/vendor/symfony/finder/Comparator/Comparator.php @@ -16,16 +16,16 @@ */ class Comparator { - private string $target; private string $operator; - public function __construct(string $target, string $operator = '==') - { + public function __construct( + private string $target, + string $operator = '==', + ) { if (!\in_array($operator, ['>', '<', '>=', '<=', '==', '!='])) { - throw new \InvalidArgumentException(sprintf('Invalid operator "%s".', $operator)); + throw new \InvalidArgumentException(\sprintf('Invalid operator "%s".', $operator)); } - $this->target = $target; $this->operator = $operator; } diff --git a/app/vendor/symfony/finder/Comparator/DateComparator.php b/app/vendor/symfony/finder/Comparator/DateComparator.php index e0c523d05..bcf93cfb6 100644 --- a/app/vendor/symfony/finder/Comparator/DateComparator.php +++ b/app/vendor/symfony/finder/Comparator/DateComparator.php @@ -26,17 +26,17 @@ class DateComparator extends Comparator public function __construct(string $test) { if (!preg_match('#^\s*(==|!=|[<>]=?|after|since|before|until)?\s*(.+?)\s*$#i', $test, $matches)) { - throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a date test.', $test)); + throw new \InvalidArgumentException(\sprintf('Don\'t understand "%s" as a date test.', $test)); } try { $date = new \DateTimeImmutable($matches[2]); $target = $date->format('U'); } catch (\Exception) { - throw new \InvalidArgumentException(sprintf('"%s" is not a valid date.', $matches[2])); + throw new \InvalidArgumentException(\sprintf('"%s" is not a valid date.', $matches[2])); } - $operator = $matches[1] ?? '=='; + $operator = $matches[1] ?: '=='; if ('since' === $operator || 'after' === $operator) { $operator = '>'; } diff --git a/app/vendor/symfony/finder/Comparator/NumberComparator.php b/app/vendor/symfony/finder/Comparator/NumberComparator.php index dd3082077..0ec0049ff 100644 --- a/app/vendor/symfony/finder/Comparator/NumberComparator.php +++ b/app/vendor/symfony/finder/Comparator/NumberComparator.php @@ -19,7 +19,7 @@ * magnitudes. * * The target value may use magnitudes of kilobytes (k, ki), - * megabytes (m, mi), or gigabytes (g, gi). Those suffixed + * megabytes (m, mi), or gigabytes (g, gi). Those suffixed * with an i use the appropriate 2**n version in accordance with the * IEC standard: http://physics.nist.gov/cuu/Units/binary.html * @@ -42,12 +42,12 @@ class NumberComparator extends Comparator public function __construct(?string $test) { if (null === $test || !preg_match('#^\s*(==|!=|[<>]=?)?\s*([0-9\.]+)\s*([kmg]i?)?\s*$#i', $test, $matches)) { - throw new \InvalidArgumentException(sprintf('Don\'t understand "%s" as a number test.', $test ?? 'null')); + throw new \InvalidArgumentException(\sprintf('Don\'t understand "%s" as a number test.', $test ?? 'null')); } $target = $matches[2]; if (!is_numeric($target)) { - throw new \InvalidArgumentException(sprintf('Invalid number "%s".', $target)); + throw new \InvalidArgumentException(\sprintf('Invalid number "%s".', $target)); } if (isset($matches[3])) { // magnitude diff --git a/app/vendor/symfony/finder/Finder.php b/app/vendor/symfony/finder/Finder.php index d062a60a4..78673af66 100644 --- a/app/vendor/symfony/finder/Finder.php +++ b/app/vendor/symfony/finder/Finder.php @@ -124,7 +124,7 @@ public function files(): static public function depth(string|int|array $levels): static { foreach ((array) $levels as $level) { - $this->depths[] = new Comparator\NumberComparator($level); + $this->depths[] = new NumberComparator($level); } return $this; @@ -152,7 +152,7 @@ public function depth(string|int|array $levels): static public function date(string|array $dates): static { foreach ((array) $dates as $date) { - $this->dates[] = new Comparator\DateComparator($date); + $this->dates[] = new DateComparator($date); } return $this; @@ -307,7 +307,7 @@ public function notPath(string|array $patterns): static public function size(string|int|array $sizes): static { foreach ((array) $sizes as $size) { - $this->sizes[] = new Comparator\NumberComparator($size); + $this->sizes[] = new NumberComparator($size); } return $this; @@ -436,7 +436,7 @@ public function sort(\Closure $closure): static */ public function sortByExtension(): static { - $this->sort = Iterator\SortableIterator::SORT_BY_EXTENSION; + $this->sort = SortableIterator::SORT_BY_EXTENSION; return $this; } @@ -452,7 +452,7 @@ public function sortByExtension(): static */ public function sortByName(bool $useNaturalSort = false): static { - $this->sort = $useNaturalSort ? Iterator\SortableIterator::SORT_BY_NAME_NATURAL : Iterator\SortableIterator::SORT_BY_NAME; + $this->sort = $useNaturalSort ? SortableIterator::SORT_BY_NAME_NATURAL : SortableIterator::SORT_BY_NAME; return $this; } @@ -468,7 +468,7 @@ public function sortByName(bool $useNaturalSort = false): static */ public function sortByCaseInsensitiveName(bool $useNaturalSort = false): static { - $this->sort = $useNaturalSort ? Iterator\SortableIterator::SORT_BY_NAME_NATURAL_CASE_INSENSITIVE : Iterator\SortableIterator::SORT_BY_NAME_CASE_INSENSITIVE; + $this->sort = $useNaturalSort ? SortableIterator::SORT_BY_NAME_NATURAL_CASE_INSENSITIVE : SortableIterator::SORT_BY_NAME_CASE_INSENSITIVE; return $this; } @@ -484,7 +484,7 @@ public function sortByCaseInsensitiveName(bool $useNaturalSort = false): static */ public function sortBySize(): static { - $this->sort = Iterator\SortableIterator::SORT_BY_SIZE; + $this->sort = SortableIterator::SORT_BY_SIZE; return $this; } @@ -500,7 +500,7 @@ public function sortBySize(): static */ public function sortByType(): static { - $this->sort = Iterator\SortableIterator::SORT_BY_TYPE; + $this->sort = SortableIterator::SORT_BY_TYPE; return $this; } @@ -518,7 +518,7 @@ public function sortByType(): static */ public function sortByAccessedTime(): static { - $this->sort = Iterator\SortableIterator::SORT_BY_ACCESSED_TIME; + $this->sort = SortableIterator::SORT_BY_ACCESSED_TIME; return $this; } @@ -550,7 +550,7 @@ public function reverseSorting(): static */ public function sortByChangedTime(): static { - $this->sort = Iterator\SortableIterator::SORT_BY_CHANGED_TIME; + $this->sort = SortableIterator::SORT_BY_CHANGED_TIME; return $this; } @@ -568,7 +568,7 @@ public function sortByChangedTime(): static */ public function sortByModifiedTime(): static { - $this->sort = Iterator\SortableIterator::SORT_BY_MODIFIED_TIME; + $this->sort = SortableIterator::SORT_BY_MODIFIED_TIME; return $this; } @@ -643,7 +643,7 @@ public function in(string|array $dirs): static sort($glob); $resolvedDirs[] = array_map($this->normalizeDir(...), $glob); } else { - throw new DirectoryNotFoundException(sprintf('The "%s" directory does not exist.', $dir)); + throw new DirectoryNotFoundException(\sprintf('The "%s" directory does not exist.', $dir)); } } @@ -671,7 +671,7 @@ public function getIterator(): \Iterator $iterator = $this->searchInDirectory($this->dirs[0]); if ($this->sort || $this->reverseSorting) { - $iterator = (new Iterator\SortableIterator($iterator, $this->sort, $this->reverseSorting))->getIterator(); + $iterator = (new SortableIterator($iterator, $this->sort, $this->reverseSorting))->getIterator(); } return $iterator; @@ -687,7 +687,7 @@ public function getIterator(): \Iterator } if ($this->sort || $this->reverseSorting) { - $iterator = (new Iterator\SortableIterator($iterator, $this->sort, $this->reverseSorting))->getIterator(); + $iterator = (new SortableIterator($iterator, $this->sort, $this->reverseSorting))->getIterator(); } return $iterator; @@ -699,8 +699,6 @@ public function getIterator(): \Iterator * The set can be another Finder, an Iterator, an IteratorAggregate, or even a plain array. * * @return $this - * - * @throws \InvalidArgumentException when the given argument is not iterable */ public function append(iterable $iterator): static { @@ -708,15 +706,13 @@ public function append(iterable $iterator): static $this->iterators[] = $iterator->getIterator(); } elseif ($iterator instanceof \Iterator) { $this->iterators[] = $iterator; - } elseif (is_iterable($iterator)) { + } else { $it = new \ArrayIterator(); foreach ($iterator as $file) { $file = $file instanceof \SplFileInfo ? $file : new \SplFileInfo($file); $it[$file->getPathname()] = $file; } $this->iterators[] = $it; - } else { - throw new \InvalidArgumentException('Finder::append() method wrong argument type.'); } return $this; @@ -790,13 +786,13 @@ private function searchInDirectory(string $dir): \Iterator $iterator = new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs); if ($exclude) { - $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $exclude); + $iterator = new ExcludeDirectoryFilterIterator($iterator, $exclude); } $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST); if ($minDepth > 0 || $maxDepth < \PHP_INT_MAX) { - $iterator = new Iterator\DepthRangeFilterIterator($iterator, $minDepth, $maxDepth); + $iterator = new DepthRangeFilterIterator($iterator, $minDepth, $maxDepth); } if ($this->mode) { @@ -804,23 +800,23 @@ private function searchInDirectory(string $dir): \Iterator } if ($this->names || $this->notNames) { - $iterator = new Iterator\FilenameFilterIterator($iterator, $this->names, $this->notNames); + $iterator = new FilenameFilterIterator($iterator, $this->names, $this->notNames); } if ($this->contains || $this->notContains) { - $iterator = new Iterator\FilecontentFilterIterator($iterator, $this->contains, $this->notContains); + $iterator = new FilecontentFilterIterator($iterator, $this->contains, $this->notContains); } if ($this->sizes) { - $iterator = new Iterator\SizeRangeFilterIterator($iterator, $this->sizes); + $iterator = new SizeRangeFilterIterator($iterator, $this->sizes); } if ($this->dates) { - $iterator = new Iterator\DateRangeFilterIterator($iterator, $this->dates); + $iterator = new DateRangeFilterIterator($iterator, $this->dates); } if ($this->filters) { - $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters); + $iterator = new CustomFilterIterator($iterator, $this->filters); } if ($this->paths || $notPaths) { diff --git a/app/vendor/symfony/finder/Iterator/FileTypeFilterIterator.php b/app/vendor/symfony/finder/Iterator/FileTypeFilterIterator.php index 21303781e..0d4a5fd36 100644 --- a/app/vendor/symfony/finder/Iterator/FileTypeFilterIterator.php +++ b/app/vendor/symfony/finder/Iterator/FileTypeFilterIterator.php @@ -23,16 +23,14 @@ class FileTypeFilterIterator extends \FilterIterator public const ONLY_FILES = 1; public const ONLY_DIRECTORIES = 2; - private int $mode; - /** * @param \Iterator $iterator The Iterator to filter * @param int $mode The mode (self::ONLY_FILES or self::ONLY_DIRECTORIES) */ - public function __construct(\Iterator $iterator, int $mode) - { - $this->mode = $mode; - + public function __construct( + \Iterator $iterator, + private int $mode, + ) { parent::__construct($iterator); } diff --git a/app/vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php b/app/vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php index 34cced688..f5fd2d4dc 100644 --- a/app/vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php +++ b/app/vendor/symfony/finder/Iterator/RecursiveDirectoryIterator.php @@ -63,8 +63,9 @@ public function current(): SplFileInfo $subPathname .= $this->directorySeparator; } $subPathname .= $this->getFilename(); + $basePath = $this->rootPath; - if ('/' !== $basePath = $this->rootPath) { + if ('/' !== $basePath && !str_ends_with($basePath, $this->directorySeparator) && !str_ends_with($basePath, '/')) { $basePath .= $this->directorySeparator; } diff --git a/app/vendor/symfony/finder/Iterator/VcsIgnoredFilterIterator.php b/app/vendor/symfony/finder/Iterator/VcsIgnoredFilterIterator.php index ddd700772..b278706e9 100644 --- a/app/vendor/symfony/finder/Iterator/VcsIgnoredFilterIterator.php +++ b/app/vendor/symfony/finder/Iterator/VcsIgnoredFilterIterator.php @@ -37,9 +37,9 @@ public function __construct(\Iterator $iterator, string $baseDir) { $this->baseDir = $this->normalizePath($baseDir); - foreach ($this->parentDirectoriesUpwards($this->baseDir) as $parentDirectory) { - if (@is_dir("{$parentDirectory}/.git")) { - $this->baseDir = $parentDirectory; + foreach ([$this->baseDir, ...$this->parentDirectoriesUpwards($this->baseDir)] as $directory) { + if (@is_dir("{$directory}/.git")) { + $this->baseDir = $directory; break; } } diff --git a/app/vendor/symfony/finder/SplFileInfo.php b/app/vendor/symfony/finder/SplFileInfo.php index 867e8e81a..2afc37826 100644 --- a/app/vendor/symfony/finder/SplFileInfo.php +++ b/app/vendor/symfony/finder/SplFileInfo.php @@ -18,19 +18,17 @@ */ class SplFileInfo extends \SplFileInfo { - private string $relativePath; - private string $relativePathname; - /** * @param string $file The file name * @param string $relativePath The relative path * @param string $relativePathname The relative path name */ - public function __construct(string $file, string $relativePath, string $relativePathname) - { + public function __construct( + string $file, + private string $relativePath, + private string $relativePathname, + ) { parent::__construct($file); - $this->relativePath = $relativePath; - $this->relativePathname = $relativePathname; } /** diff --git a/app/vendor/symfony/html-sanitizer/TextSanitizer/UrlSanitizer.php b/app/vendor/symfony/html-sanitizer/TextSanitizer/UrlSanitizer.php index 05d86ba15..b026d3777 100644 --- a/app/vendor/symfony/html-sanitizer/TextSanitizer/UrlSanitizer.php +++ b/app/vendor/symfony/html-sanitizer/TextSanitizer/UrlSanitizer.php @@ -100,6 +100,10 @@ public static function parse(string $url): ?array return null; } + if (isset($parsedUrl['host']) && self::decodeUnreservedCharacters($parsedUrl['host']) !== $parsedUrl['host']) { + return null; + } + return $parsedUrl; } catch (SyntaxError) { return null; @@ -132,11 +136,23 @@ private static function matchAllowedHostParts(array $uriParts, array $trustedPar { // Check each chunk of the domain is valid foreach ($trustedParts as $key => $trustedPart) { - if ($uriParts[$key] !== $trustedPart) { + if (!\array_key_exists($key, $uriParts) || $uriParts[$key] !== $trustedPart) { return false; } } return true; } + + /** + * Implementation borrowed from League\Uri\Encoder::decodeUnreservedCharacters(). + */ + private static function decodeUnreservedCharacters(string $host): string + { + return preg_replace_callback( + ',%(2[1-9A-Fa-f]|[3-7][0-9A-Fa-f]|61|62|64|65|66|7[AB]|5F),', + static fn (array $matches): string => rawurldecode($matches[0]), + $host + ); + } } diff --git a/app/vendor/symfony/polyfill-ctype/composer.json b/app/vendor/symfony/polyfill-ctype/composer.json index b222fdab9..131ca7adb 100644 --- a/app/vendor/symfony/polyfill-ctype/composer.json +++ b/app/vendor/symfony/polyfill-ctype/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-ctype": "*" diff --git a/app/vendor/symfony/polyfill-intl-grapheme/composer.json b/app/vendor/symfony/polyfill-intl-grapheme/composer.json index a20d3faaf..0eea417d7 100644 --- a/app/vendor/symfony/polyfill-intl-grapheme/composer.json +++ b/app/vendor/symfony/polyfill-intl-grapheme/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=7.1" + "php": ">=7.2" }, "autoload": { "psr-4": { "Symfony\\Polyfill\\Intl\\Grapheme\\": "" }, diff --git a/app/vendor/symfony/polyfill-intl-normalizer/composer.json b/app/vendor/symfony/polyfill-intl-normalizer/composer.json index 1b93573ae..9bd04e887 100644 --- a/app/vendor/symfony/polyfill-intl-normalizer/composer.json +++ b/app/vendor/symfony/polyfill-intl-normalizer/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=7.1" + "php": ">=7.2" }, "autoload": { "psr-4": { "Symfony\\Polyfill\\Intl\\Normalizer\\": "" }, diff --git a/app/vendor/symfony/polyfill-mbstring/Mbstring.php b/app/vendor/symfony/polyfill-mbstring/Mbstring.php index 2e0b96940..31e36a368 100644 --- a/app/vendor/symfony/polyfill-mbstring/Mbstring.php +++ b/app/vendor/symfony/polyfill-mbstring/Mbstring.php @@ -48,6 +48,11 @@ * - mb_strstr - Finds first occurrence of a string within another * - mb_strwidth - Return width of string * - mb_substr_count - Count the number of substring occurrences + * - mb_ucfirst - Make a string's first character uppercase + * - mb_lcfirst - Make a string's first character lowercase + * - mb_trim - Strip whitespace (or other characters) from the beginning and end of a string + * - mb_ltrim - Strip whitespace (or other characters) from the beginning of a string + * - mb_rtrim - Strip whitespace (or other characters) from the end of a string * * Not implemented: * - mb_convert_kana - Convert "kana" one from another ("zen-kaku", "han-kaku" and more) @@ -80,6 +85,15 @@ final class Mbstring public static function mb_convert_encoding($s, $toEncoding, $fromEncoding = null) { + if (\is_array($s)) { + $r = []; + foreach ($s as $str) { + $r[] = self::mb_convert_encoding($str, $toEncoding, $fromEncoding); + } + + return $r; + } + if (\is_array($fromEncoding) || (null !== $fromEncoding && false !== strpos($fromEncoding, ','))) { $fromEncoding = self::mb_detect_encoding($s, $fromEncoding); } else { @@ -410,12 +424,6 @@ public static function mb_encoding_aliases($encoding) public static function mb_check_encoding($var = null, $encoding = null) { - if (PHP_VERSION_ID < 70200 && \is_array($var)) { - trigger_error('mb_check_encoding() expects parameter 1 to be string, array given', \E_USER_WARNING); - - return null; - } - if (null === $encoding) { if (null === $var) { return false; @@ -437,7 +445,6 @@ public static function mb_check_encoding($var = null, $encoding = null) } return true; - } public static function mb_detect_encoding($str, $encodingList = null, $strict = false) @@ -827,7 +834,7 @@ public static function mb_ord($s, $encoding = null) return $code; } - public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, string $encoding = null): string + public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, ?string $encoding = null): string { if (!\in_array($pad_type, [\STR_PAD_RIGHT, \STR_PAD_LEFT, \STR_PAD_BOTH], true)) { throw new \ValueError('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH'); @@ -835,17 +842,8 @@ public static function mb_str_pad(string $string, int $length, string $pad_strin if (null === $encoding) { $encoding = self::mb_internal_encoding(); - } - - try { - $validEncoding = @self::mb_check_encoding('', $encoding); - } catch (\ValueError $e) { - throw new \ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding)); - } - - // BC for PHP 7.3 and lower - if (!$validEncoding) { - throw new \ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding)); + } else { + self::assertEncoding($encoding, 'mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given'); } if (self::mb_strlen($pad_string, $encoding) <= 0) { @@ -871,6 +869,34 @@ public static function mb_str_pad(string $string, int $length, string $pad_strin } } + public static function mb_ucfirst(string $string, ?string $encoding = null): string + { + if (null === $encoding) { + $encoding = self::mb_internal_encoding(); + } else { + self::assertEncoding($encoding, 'mb_ucfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given'); + } + + $firstChar = mb_substr($string, 0, 1, $encoding); + $firstChar = mb_convert_case($firstChar, \MB_CASE_TITLE, $encoding); + + return $firstChar.mb_substr($string, 1, null, $encoding); + } + + public static function mb_lcfirst(string $string, ?string $encoding = null): string + { + if (null === $encoding) { + $encoding = self::mb_internal_encoding(); + } else { + self::assertEncoding($encoding, 'mb_lcfirst(): Argument #2 ($encoding) must be a valid encoding, "%s" given'); + } + + $firstChar = mb_substr($string, 0, 1, $encoding); + $firstChar = mb_convert_case($firstChar, \MB_CASE_LOWER, $encoding); + + return $firstChar.mb_substr($string, 1, null, $encoding); + } + private static function getSubpart($pos, $part, $haystack, $encoding) { if (false === $pos) { @@ -944,4 +970,76 @@ private static function getEncoding($encoding) return $encoding; } + + public static function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string + { + return self::mb_internal_trim('{^[%s]+|[%1$s]+$}Du', $string, $characters, $encoding, __FUNCTION__); + } + + public static function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string + { + return self::mb_internal_trim('{^[%s]+}Du', $string, $characters, $encoding, __FUNCTION__); + } + + public static function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string + { + return self::mb_internal_trim('{[%s]+$}Du', $string, $characters, $encoding, __FUNCTION__); + } + + private static function mb_internal_trim(string $regex, string $string, ?string $characters, ?string $encoding, string $function): string + { + if (null === $encoding) { + $encoding = self::mb_internal_encoding(); + } else { + self::assertEncoding($encoding, $function.'(): Argument #3 ($encoding) must be a valid encoding, "%s" given'); + } + + if ('' === $characters) { + return null === $encoding ? $string : self::mb_convert_encoding($string, $encoding); + } + + if ('UTF-8' === $encoding) { + $encoding = null; + if (!preg_match('//u', $string)) { + $string = @iconv('UTF-8', 'UTF-8//IGNORE', $string); + } + if (null !== $characters && !preg_match('//u', $characters)) { + $characters = @iconv('UTF-8', 'UTF-8//IGNORE', $characters); + } + } else { + $string = iconv($encoding, 'UTF-8//IGNORE', $string); + + if (null !== $characters) { + $characters = iconv($encoding, 'UTF-8//IGNORE', $characters); + } + } + + if (null === $characters) { + $characters = "\\0 \f\n\r\t\v\u{00A0}\u{1680}\u{2000}\u{2001}\u{2002}\u{2003}\u{2004}\u{2005}\u{2006}\u{2007}\u{2008}\u{2009}\u{200A}\u{2028}\u{2029}\u{202F}\u{205F}\u{3000}\u{0085}\u{180E}"; + } else { + $characters = preg_quote($characters); + } + + $string = preg_replace(sprintf($regex, $characters), '', $string); + + if (null === $encoding) { + return $string; + } + + return iconv('UTF-8', $encoding.'//IGNORE', $string); + } + + private static function assertEncoding(string $encoding, string $errorFormat): void + { + try { + $validEncoding = @self::mb_check_encoding('', $encoding); + } catch (\ValueError $e) { + throw new \ValueError(sprintf($errorFormat, $encoding)); + } + + // BC for PHP 7.3 and lower + if (!$validEncoding) { + throw new \ValueError(sprintf($errorFormat, $encoding)); + } + } } diff --git a/app/vendor/symfony/polyfill-mbstring/bootstrap.php b/app/vendor/symfony/polyfill-mbstring/bootstrap.php index ecf1a0352..ff51ae079 100644 --- a/app/vendor/symfony/polyfill-mbstring/bootstrap.php +++ b/app/vendor/symfony/polyfill-mbstring/bootstrap.php @@ -136,6 +136,27 @@ function mb_str_split($string, $length = 1, $encoding = null) { return p\Mbstrin function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); } } +if (!function_exists('mb_ucfirst')) { + function mb_ucfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_ucfirst($string, $encoding); } +} + +if (!function_exists('mb_lcfirst')) { + function mb_lcfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); } +} + +if (!function_exists('mb_trim')) { + function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_trim($string, $characters, $encoding); } +} + +if (!function_exists('mb_ltrim')) { + function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_ltrim($string, $characters, $encoding); } +} + +if (!function_exists('mb_rtrim')) { + function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_rtrim($string, $characters, $encoding); } +} + + if (extension_loaded('mbstring')) { return; } diff --git a/app/vendor/symfony/polyfill-mbstring/bootstrap80.php b/app/vendor/symfony/polyfill-mbstring/bootstrap80.php index 2f9fb5b42..5236e6dcc 100644 --- a/app/vendor/symfony/polyfill-mbstring/bootstrap80.php +++ b/app/vendor/symfony/polyfill-mbstring/bootstrap80.php @@ -93,7 +93,7 @@ function mb_strrpos(?string $haystack, ?string $needle, ?int $offset = 0, ?strin function mb_strstr(?string $haystack, ?string $needle, ?bool $before_needle = false, ?string $encoding = null): string|false { return p\Mbstring::mb_strstr((string) $haystack, (string) $needle, (bool) $before_needle, $encoding); } } if (!function_exists('mb_get_info')) { - function mb_get_info(?string $type = 'all'): array|string|int|false { return p\Mbstring::mb_get_info((string) $type); } + function mb_get_info(?string $type = 'all'): array|string|int|false|null { return p\Mbstring::mb_get_info((string) $type); } } if (!function_exists('mb_http_output')) { function mb_http_output(?string $encoding = null): string|bool { return p\Mbstring::mb_http_output($encoding); } @@ -132,6 +132,26 @@ function mb_str_split(?string $string, ?int $length = 1, ?string $encoding = nul function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); } } +if (!function_exists('mb_ucfirst')) { + function mb_ucfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_ucfirst($string, $encoding); } +} + +if (!function_exists('mb_lcfirst')) { + function mb_lcfirst(string $string, ?string $encoding = null): string { return p\Mbstring::mb_lcfirst($string, $encoding); } +} + +if (!function_exists('mb_trim')) { + function mb_trim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_trim($string, $characters, $encoding); } +} + +if (!function_exists('mb_ltrim')) { + function mb_ltrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_ltrim($string, $characters, $encoding); } +} + +if (!function_exists('mb_rtrim')) { + function mb_rtrim(string $string, ?string $characters = null, ?string $encoding = null): string { return p\Mbstring::mb_rtrim($string, $characters, $encoding); } +} + if (extension_loaded('mbstring')) { return; } diff --git a/app/vendor/symfony/polyfill-mbstring/composer.json b/app/vendor/symfony/polyfill-mbstring/composer.json index bd99d4b9d..daa07f86b 100644 --- a/app/vendor/symfony/polyfill-mbstring/composer.json +++ b/app/vendor/symfony/polyfill-mbstring/composer.json @@ -16,7 +16,8 @@ } ], "require": { - "php": ">=7.1" + "php": ">=7.2", + "ext-iconv": "*" }, "provide": { "ext-mbstring": "*" diff --git a/app/vendor/symfony/polyfill-php73/composer.json b/app/vendor/symfony/polyfill-php73/composer.json index 3d47d1541..09d98cb87 100644 --- a/app/vendor/symfony/polyfill-php73/composer.json +++ b/app/vendor/symfony/polyfill-php73/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=7.1" + "php": ">=7.2" }, "autoload": { "psr-4": { "Symfony\\Polyfill\\Php73\\": "" }, diff --git a/app/vendor/symfony/polyfill-php80/PhpToken.php b/app/vendor/symfony/polyfill-php80/PhpToken.php index fe6e69105..cd78c4ccc 100644 --- a/app/vendor/symfony/polyfill-php80/PhpToken.php +++ b/app/vendor/symfony/polyfill-php80/PhpToken.php @@ -29,7 +29,7 @@ class PhpToken implements \Stringable public $text; /** - * @var int + * @var -1|positive-int */ public $line; @@ -38,6 +38,9 @@ class PhpToken implements \Stringable */ public $pos; + /** + * @param -1|positive-int $line + */ public function __construct(int $id, string $text, int $line = -1, int $position = -1) { $this->id = $id; @@ -80,7 +83,7 @@ public function __toString(): string } /** - * @return static[] + * @return list */ public static function tokenize(string $code, int $flags = 0): array { diff --git a/app/vendor/symfony/polyfill-php80/composer.json b/app/vendor/symfony/polyfill-php80/composer.json index 46ccde203..a503b039a 100644 --- a/app/vendor/symfony/polyfill-php80/composer.json +++ b/app/vendor/symfony/polyfill-php80/composer.json @@ -20,7 +20,7 @@ } ], "require": { - "php": ">=7.1" + "php": ">=7.2" }, "autoload": { "psr-4": { "Symfony\\Polyfill\\Php80\\": "" }, diff --git a/app/vendor/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php b/app/vendor/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php index eb5952ee3..5ff93fcaf 100644 --- a/app/vendor/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php +++ b/app/vendor/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php @@ -32,7 +32,7 @@ public function __set(string $name, $value): void } if (is_object($value) ? !method_exists($value, '__toString') : !is_scalar($value)) { - throw new \TypeError('Cannot assign '.gettype($value).' to property CURLStringFile::$data of type string'); + throw new TypeError('Cannot assign '.gettype($value).' to property CURLStringFile::$data of type string'); } $this->name = 'data://application/octet-stream;base64,'.base64_encode($value); diff --git a/app/vendor/symfony/polyfill-php81/composer.json b/app/vendor/symfony/polyfill-php81/composer.json index 381af79ac..28b6408ea 100644 --- a/app/vendor/symfony/polyfill-php81/composer.json +++ b/app/vendor/symfony/polyfill-php81/composer.json @@ -16,7 +16,7 @@ } ], "require": { - "php": ">=7.1" + "php": ">=7.2" }, "autoload": { "psr-4": { "Symfony\\Polyfill\\Php81\\": "" }, diff --git a/app/vendor/symfony/process/CHANGELOG.md b/app/vendor/symfony/process/CHANGELOG.md index 3e33cd0bc..d73085663 100644 --- a/app/vendor/symfony/process/CHANGELOG.md +++ b/app/vendor/symfony/process/CHANGELOG.md @@ -1,6 +1,12 @@ CHANGELOG ========= + +7.3 +--- + + * Add `RunProcessMessage::fromShellCommandline()` to instantiate a Process via the fromShellCommandline method + 7.1 --- diff --git a/app/vendor/symfony/process/ExecutableFinder.php b/app/vendor/symfony/process/ExecutableFinder.php index 5cc652512..6aa2d4d7e 100644 --- a/app/vendor/symfony/process/ExecutableFinder.php +++ b/app/vendor/symfony/process/ExecutableFinder.php @@ -72,7 +72,7 @@ public function find(string $name, ?string $default = null, array $extraDirs = [ $pathExt = getenv('PATHEXT'); $suffixes = array_merge($suffixes, $pathExt ? explode(\PATH_SEPARATOR, $pathExt) : ['.exe', '.bat', '.cmd', '.com']); } - $suffixes = '' !== pathinfo($name, PATHINFO_EXTENSION) ? array_merge([''], $suffixes) : array_merge($suffixes, ['']); + $suffixes = '' !== pathinfo($name, \PATHINFO_EXTENSION) ? array_merge([''], $suffixes) : array_merge($suffixes, ['']); foreach ($suffixes as $suffix) { foreach ($dirs as $dir) { if ('' === $dir) { diff --git a/app/vendor/symfony/process/Messenger/RunProcessMessage.php b/app/vendor/symfony/process/Messenger/RunProcessMessage.php index b2c33fe3b..d14ac2365 100644 --- a/app/vendor/symfony/process/Messenger/RunProcessMessage.php +++ b/app/vendor/symfony/process/Messenger/RunProcessMessage.php @@ -16,6 +16,8 @@ */ class RunProcessMessage implements \Stringable { + public ?string $commandLine = null; + public function __construct( public readonly array $command, public readonly ?string $cwd = null, @@ -27,6 +29,19 @@ public function __construct( public function __toString(): string { - return implode(' ', $this->command); + return $this->commandLine ?? implode(' ', $this->command); + } + + /** + * Create a process message instance that will instantiate a Process using the fromShellCommandline method. + * + * @see Process::fromShellCommandline + */ + public static function fromShellCommandline(string $command, ?string $cwd = null, ?array $env = null, mixed $input = null, ?float $timeout = 60): self + { + $message = new self([], $cwd, $env, $input, $timeout); + $message->commandLine = $command; + + return $message; } } diff --git a/app/vendor/symfony/process/Messenger/RunProcessMessageHandler.php b/app/vendor/symfony/process/Messenger/RunProcessMessageHandler.php index 41c1934cc..69bfa6a18 100644 --- a/app/vendor/symfony/process/Messenger/RunProcessMessageHandler.php +++ b/app/vendor/symfony/process/Messenger/RunProcessMessageHandler.php @@ -22,7 +22,10 @@ final class RunProcessMessageHandler { public function __invoke(RunProcessMessage $message): RunProcessContext { - $process = new Process($message->command, $message->cwd, $message->env, $message->input, $message->timeout); + $process = match ($message->commandLine) { + null => new Process($message->command, $message->cwd, $message->env, $message->input, $message->timeout), + default => Process::fromShellCommandline($message->commandLine, $message->cwd, $message->env, $message->input, $message->timeout), + }; try { return new RunProcessContext($message, $process->mustRun()); diff --git a/app/vendor/symfony/process/PhpExecutableFinder.php b/app/vendor/symfony/process/PhpExecutableFinder.php index 9f9218f98..f9ed79e4d 100644 --- a/app/vendor/symfony/process/PhpExecutableFinder.php +++ b/app/vendor/symfony/process/PhpExecutableFinder.php @@ -83,6 +83,8 @@ public function find(bool $includeArgs = true): string|false /** * Finds the PHP executable arguments. + * + * @return list */ public function findArguments(): array { diff --git a/app/vendor/symfony/process/Process.php b/app/vendor/symfony/process/Process.php index 6fe1086ea..a8beb93d4 100644 --- a/app/vendor/symfony/process/Process.php +++ b/app/vendor/symfony/process/Process.php @@ -1584,7 +1584,7 @@ function ($m) use (&$env, $uid) { if (!$comSpec && $comSpec = (new ExecutableFinder())->find('cmd.exe')) { // Escape according to CommandLineToArgvW rules - $comSpec = '"'.preg_replace('{(\\\\*+)"}', '$1$1\"', $comSpec) .'"'; + $comSpec = '"'.preg_replace('{(\\\\*+)"}', '$1$1\"', $comSpec).'"'; } $cmd = ($comSpec ?? 'cmd').' /V:ON /E:ON /D /C ('.str_replace("\n", ' ', $cmd).')'; diff --git a/app/vendor/symfony/service-contracts/Attribute/SubscribedService.php b/app/vendor/symfony/service-contracts/Attribute/SubscribedService.php index d98e1dfdb..f850b8401 100644 --- a/app/vendor/symfony/service-contracts/Attribute/SubscribedService.php +++ b/app/vendor/symfony/service-contracts/Attribute/SubscribedService.php @@ -11,15 +11,15 @@ namespace Symfony\Contracts\Service\Attribute; +use Symfony\Contracts\Service\ServiceMethodsSubscriberTrait; use Symfony\Contracts\Service\ServiceSubscriberInterface; -use Symfony\Contracts\Service\ServiceSubscriberTrait; /** * For use as the return value for {@see ServiceSubscriberInterface}. * * @example new SubscribedService('http_client', HttpClientInterface::class, false, new Target('githubApi')) * - * Use with {@see ServiceSubscriberTrait} to mark a method's return type + * Use with {@see ServiceMethodsSubscriberTrait} to mark a method's return type * as a subscribed service. * * @author Kevin Bond diff --git a/app/vendor/symfony/service-contracts/ServiceCollectionInterface.php b/app/vendor/symfony/service-contracts/ServiceCollectionInterface.php new file mode 100644 index 000000000..2333139ce --- /dev/null +++ b/app/vendor/symfony/service-contracts/ServiceCollectionInterface.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +/** + * A ServiceProviderInterface that is also countable and iterable. + * + * @author Kevin Bond + * + * @template-covariant T of mixed + * + * @extends ServiceProviderInterface + * @extends \IteratorAggregate + */ +interface ServiceCollectionInterface extends ServiceProviderInterface, \Countable, \IteratorAggregate +{ +} diff --git a/app/vendor/symfony/service-contracts/ServiceLocatorTrait.php b/app/vendor/symfony/service-contracts/ServiceLocatorTrait.php index b62ec3e53..bbe454843 100644 --- a/app/vendor/symfony/service-contracts/ServiceLocatorTrait.php +++ b/app/vendor/symfony/service-contracts/ServiceLocatorTrait.php @@ -26,16 +26,15 @@ class_exists(NotFoundExceptionInterface::class); */ trait ServiceLocatorTrait { - private array $factories; private array $loading = []; private array $providedTypes; /** * @param array $factories */ - public function __construct(array $factories) - { - $this->factories = $factories; + public function __construct( + private array $factories, + ) { } public function has(string $id): bool @@ -91,16 +90,16 @@ private function createNotFoundException(string $id): NotFoundExceptionInterface } else { $last = array_pop($alternatives); if ($alternatives) { - $message = sprintf('only knows about the "%s" and "%s" services.', implode('", "', $alternatives), $last); + $message = \sprintf('only knows about the "%s" and "%s" services.', implode('", "', $alternatives), $last); } else { - $message = sprintf('only knows about the "%s" service.', $last); + $message = \sprintf('only knows about the "%s" service.', $last); } } if ($this->loading) { - $message = sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $message); + $message = \sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $message); } else { - $message = sprintf('Service "%s" not found: the current service locator %s', $id, $message); + $message = \sprintf('Service "%s" not found: the current service locator %s', $id, $message); } return new class($message) extends \InvalidArgumentException implements NotFoundExceptionInterface { @@ -109,7 +108,7 @@ private function createNotFoundException(string $id): NotFoundExceptionInterface private function createCircularReferenceException(string $id, array $path): ContainerExceptionInterface { - return new class(sprintf('Circular reference detected for service "%s", path: "%s".', $id, implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface { + return new class(\sprintf('Circular reference detected for service "%s", path: "%s".', $id, implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface { }; } } diff --git a/app/vendor/symfony/service-contracts/ServiceMethodsSubscriberTrait.php b/app/vendor/symfony/service-contracts/ServiceMethodsSubscriberTrait.php new file mode 100644 index 000000000..844be8907 --- /dev/null +++ b/app/vendor/symfony/service-contracts/ServiceMethodsSubscriberTrait.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +use Psr\Container\ContainerInterface; +use Symfony\Contracts\Service\Attribute\Required; +use Symfony\Contracts\Service\Attribute\SubscribedService; + +/** + * Implementation of ServiceSubscriberInterface that determines subscribed services + * from methods that have the #[SubscribedService] attribute. + * + * Service ids are available as "ClassName::methodName" so that the implementation + * of subscriber methods can be just `return $this->container->get(__METHOD__);`. + * + * @author Kevin Bond + */ +trait ServiceMethodsSubscriberTrait +{ + protected ContainerInterface $container; + + public static function getSubscribedServices(): array + { + $services = method_exists(get_parent_class(self::class) ?: '', __FUNCTION__) ? parent::getSubscribedServices() : []; + + foreach ((new \ReflectionClass(self::class))->getMethods() as $method) { + if (self::class !== $method->getDeclaringClass()->name) { + continue; + } + + if (!$attribute = $method->getAttributes(SubscribedService::class)[0] ?? null) { + continue; + } + + if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { + throw new \LogicException(\sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); + } + + if (!$returnType = $method->getReturnType()) { + throw new \LogicException(\sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); + } + + /* @var SubscribedService $attribute */ + $attribute = $attribute->newInstance(); + $attribute->key ??= self::class.'::'.$method->name; + $attribute->type ??= $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType; + $attribute->nullable = $attribute->nullable ?: $returnType->allowsNull(); + + if ($attribute->attributes) { + $services[] = $attribute; + } else { + $services[$attribute->key] = ($attribute->nullable ? '?' : '').$attribute->type; + } + } + + return $services; + } + + #[Required] + public function setContainer(ContainerInterface $container): ?ContainerInterface + { + $ret = null; + if (method_exists(get_parent_class(self::class) ?: '', __FUNCTION__)) { + $ret = parent::setContainer($container); + } + + $this->container = $container; + + return $ret; + } +} diff --git a/app/vendor/symfony/service-contracts/ServiceSubscriberTrait.php b/app/vendor/symfony/service-contracts/ServiceSubscriberTrait.php index f3b450cd6..ed4cec044 100644 --- a/app/vendor/symfony/service-contracts/ServiceSubscriberTrait.php +++ b/app/vendor/symfony/service-contracts/ServiceSubscriberTrait.php @@ -15,17 +15,23 @@ use Symfony\Contracts\Service\Attribute\Required; use Symfony\Contracts\Service\Attribute\SubscribedService; +trigger_deprecation('symfony/contracts', 'v3.5', '"%s" is deprecated, use "ServiceMethodsSubscriberTrait" instead.', ServiceSubscriberTrait::class); + /** - * Implementation of ServiceSubscriberInterface that determines subscribed services from - * method return types. Service ids are available as "ClassName::methodName". + * Implementation of ServiceSubscriberInterface that determines subscribed services + * from methods that have the #[SubscribedService] attribute. + * + * Service ids are available as "ClassName::methodName" so that the implementation + * of subscriber methods can be just `return $this->container->get(__METHOD__);`. + * + * @property ContainerInterface $container * * @author Kevin Bond + * + * @deprecated since symfony/contracts v3.5, use ServiceMethodsSubscriberTrait instead */ trait ServiceSubscriberTrait { - /** @var ContainerInterface */ - protected $container; - public static function getSubscribedServices(): array { $services = method_exists(get_parent_class(self::class) ?: '', __FUNCTION__) ? parent::getSubscribedServices() : []; @@ -40,18 +46,18 @@ public static function getSubscribedServices(): array } if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { - throw new \LogicException(sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); + throw new \LogicException(\sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); } if (!$returnType = $method->getReturnType()) { - throw new \LogicException(sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); + throw new \LogicException(\sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); } /* @var SubscribedService $attribute */ $attribute = $attribute->newInstance(); $attribute->key ??= self::class.'::'.$method->name; $attribute->type ??= $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType; - $attribute->nullable = $returnType->allowsNull(); + $attribute->nullable = $attribute->nullable ?: $returnType->allowsNull(); if ($attribute->attributes) { $services[] = $attribute; diff --git a/app/vendor/symfony/service-contracts/Test/ServiceLocatorTestCase.php b/app/vendor/symfony/service-contracts/Test/ServiceLocatorTestCase.php index 65a3fe337..fdd5b2793 100644 --- a/app/vendor/symfony/service-contracts/Test/ServiceLocatorTestCase.php +++ b/app/vendor/symfony/service-contracts/Test/ServiceLocatorTestCase.php @@ -19,6 +19,9 @@ abstract class ServiceLocatorTestCase extends TestCase { + /** + * @param array $factories + */ protected function getServiceLocator(array $factories): ContainerInterface { return new class($factories) implements ContainerInterface { @@ -72,10 +75,8 @@ public function testThrowsOnUndefinedInternalService() 'foo' => function () use (&$locator) { return $locator->get('bar'); }, ]); - if (!$this->getExpectedException()) { - $this->expectException(NotFoundExceptionInterface::class); - $this->expectExceptionMessage('The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service.'); - } + $this->expectException(NotFoundExceptionInterface::class); + $this->expectExceptionMessage('The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service.'); $locator->get('foo'); } diff --git a/app/vendor/symfony/service-contracts/composer.json b/app/vendor/symfony/service-contracts/composer.json index 32bb8a316..bc2e99a8f 100644 --- a/app/vendor/symfony/service-contracts/composer.json +++ b/app/vendor/symfony/service-contracts/composer.json @@ -17,7 +17,8 @@ ], "require": { "php": ">=8.1", - "psr/container": "^1.1|^2.0" + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" }, "conflict": { "ext-psr": "<1.1|>=2" @@ -31,7 +32,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.6-dev" }, "thanks": { "name": "symfony/contracts", diff --git a/app/vendor/symfony/string/AbstractString.php b/app/vendor/symfony/string/AbstractString.php index 253d2dcb6..fc60f8f24 100644 --- a/app/vendor/symfony/string/AbstractString.php +++ b/app/vendor/symfony/string/AbstractString.php @@ -263,7 +263,7 @@ public function containsAny(string|iterable $needle): bool public function endsWith(string|iterable $suffix): bool { if (\is_string($suffix)) { - throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); } foreach ($suffix as $s) { @@ -312,7 +312,7 @@ public function ensureStart(string $prefix): static public function equalsTo(string|iterable $string): bool { if (\is_string($string)) { - throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); } foreach ($string as $s) { @@ -340,7 +340,7 @@ public function ignoreCase(): static public function indexOf(string|iterable $needle, int $offset = 0): ?int { if (\is_string($needle)) { - throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); } $i = \PHP_INT_MAX; @@ -362,7 +362,7 @@ public function indexOf(string|iterable $needle, int $offset = 0): ?int public function indexOfLast(string|iterable $needle, int $offset = 0): ?int { if (\is_string($needle)) { - throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); } $i = null; @@ -414,7 +414,7 @@ abstract public function prepend(string ...$prefix): static; public function repeat(int $multiplier): static { if (0 > $multiplier) { - throw new InvalidArgumentException(sprintf('Multiplier must be positive, %d given.', $multiplier)); + throw new InvalidArgumentException(\sprintf('Multiplier must be positive, %d given.', $multiplier)); } $str = clone $this; @@ -433,6 +433,16 @@ abstract public function slice(int $start = 0, ?int $length = null): static; abstract public function snake(): static; + public function kebab(): static + { + return $this->snake()->replace('_', '-'); + } + + public function pascal(): static + { + return $this->camel()->title(); + } + abstract public function splice(string $replacement, int $start = 0, ?int $length = null): static; /** @@ -481,7 +491,7 @@ public function split(string $delimiter, ?int $limit = null, ?int $flags = null) public function startsWith(string|iterable $prefix): bool { if (\is_string($prefix)) { - throw new \TypeError(sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); + throw new \TypeError(\sprintf('Method "%s()" must be overridden by class "%s" to deal with non-iterable values.', __FUNCTION__, static::class)); } foreach ($prefix as $prefix) { @@ -605,7 +615,7 @@ public function trimSuffix($suffix): static return $str; } - public function truncate(int $length, string $ellipsis = '', bool $cut = true): static + public function truncate(int $length, string $ellipsis = '', bool|TruncateMode $cut = TruncateMode::Char): static { $stringLength = $this->length(); @@ -619,16 +629,27 @@ public function truncate(int $length, string $ellipsis = '', bool $cut = true): $ellipsisLength = 0; } - if (!$cut) { + $desiredLength = $length; + if (TruncateMode::WordAfter === $cut || !$cut) { if (null === $length = $this->indexOf([' ', "\r", "\n", "\t"], ($length ?: 1) - 1)) { return clone $this; } + $length += $ellipsisLength; + } elseif (TruncateMode::WordBefore === $cut && null !== $this->indexOf([' ', "\r", "\n", "\t"], ($length ?: 1) - 1)) { $length += $ellipsisLength; } $str = $this->slice(0, $length - $ellipsisLength); + if (TruncateMode::WordBefore === $cut) { + if (0 === $ellipsisLength && $desiredLength === $this->indexOf([' ', "\r", "\n", "\t"], $length)) { + return $str; + } + + $str = $str->beforeLast([' ', "\r", "\n", "\t"]); + } + return $ellipsisLength ? $str->trimEnd()->append($ellipsis) : $str; } diff --git a/app/vendor/symfony/string/AbstractUnicodeString.php b/app/vendor/symfony/string/AbstractUnicodeString.php index 673ad8ce9..cf280cdba 100644 --- a/app/vendor/symfony/string/AbstractUnicodeString.php +++ b/app/vendor/symfony/string/AbstractUnicodeString.php @@ -124,7 +124,7 @@ public function ascii(array $rules = []): self } if (null === $transliterator) { - throw new InvalidArgumentException(sprintf('Unknown transliteration rule "%s".', $rule)); + throw new InvalidArgumentException(\sprintf('Unknown transliteration rule "%s".', $rule)); } self::$transliterators['any-latin/bgn'] = $transliterator; @@ -135,15 +135,21 @@ public function ascii(array $rules = []): self } elseif (!\function_exists('iconv')) { $s = preg_replace('/[^\x00-\x7F]/u', '?', $s); } else { - $s = @preg_replace_callback('/[^\x00-\x7F]/u', static function ($c) { - $c = (string) iconv('UTF-8', 'ASCII//TRANSLIT', $c[0]); - - if ('' === $c && '' === iconv('UTF-8', 'ASCII//TRANSLIT', '²')) { - throw new \LogicException(sprintf('"%s" requires a translit-able iconv implementation, try installing "gnu-libiconv" if you\'re using Alpine Linux.', static::class)); - } + $previousLocale = setlocale(\LC_CTYPE, 0); + try { + setlocale(\LC_CTYPE, 'C'); + $s = @preg_replace_callback('/[^\x00-\x7F]/u', static function ($c) { + $c = (string) iconv('UTF-8', 'ASCII//TRANSLIT', $c[0]); + + if ('' === $c && '' === iconv('UTF-8', 'ASCII//TRANSLIT', '²')) { + throw new \LogicException(\sprintf('"%s" requires a translit-able iconv implementation, try installing "gnu-libiconv" if you\'re using Alpine Linux.', static::class)); + } - return 1 < \strlen($c) ? ltrim($c, '\'`"^~') : ('' !== $c ? $c : '?'); - }, $s); + return 1 < \strlen($c) ? ltrim($c, '\'`"^~') : ('' !== $c ? $c : '?'); + }, $s); + } finally { + setlocale(\LC_CTYPE, $previousLocale); + } } } @@ -155,7 +161,7 @@ public function ascii(array $rules = []): self public function camel(): static { $str = clone $this; - $str->string = str_replace(' ', '', preg_replace_callback('/\b.(?![A-Z]{2,})/u', static function ($m) { + $str->string = str_replace(' ', '', preg_replace_callback('/\b.(?!\p{Lu})/u', static function ($m) { static $i = 0; return 1 === ++$i ? ('İ' === $m[0] ? 'i̇' : mb_strtolower($m[0], 'UTF-8')) : mb_convert_case($m[0], \MB_CASE_TITLE, 'UTF-8'); @@ -190,7 +196,7 @@ public function folded(bool $compat = true): static if (!$compat || !\defined('Normalizer::NFKC_CF')) { $str->string = normalizer_normalize($str->string, $compat ? \Normalizer::NFKC : \Normalizer::NFC); - $str->string = mb_strtolower(str_replace(self::FOLD_FROM, self::FOLD_TO, $this->string), 'UTF-8'); + $str->string = mb_strtolower(str_replace(self::FOLD_FROM, self::FOLD_TO, $str->string), 'UTF-8'); } else { $str->string = normalizer_normalize($str->string, \Normalizer::NFKC_CF); } @@ -220,6 +226,21 @@ public function lower(): static return $str; } + /** + * @param string $locale In the format language_region (e.g. tr_TR) + */ + public function localeLower(string $locale): static + { + if (null !== $transliterator = $this->getLocaleTransliterator($locale, 'Lower')) { + $str = clone $this; + $str->string = $transliterator->transliterate($str->string); + + return $str; + } + + return $this->lower(); + } + public function match(string $regexp, int $flags = 0, int $offset = 0): array { $match = ((\PREG_PATTERN_ORDER | \PREG_SET_ORDER) & $flags) ? 'preg_match_all' : 'preg_match'; @@ -363,6 +384,21 @@ public function title(bool $allWords = false): static return $str; } + /** + * @param string $locale In the format language_region (e.g. tr_TR) + */ + public function localeTitle(string $locale): static + { + if (null !== $transliterator = $this->getLocaleTransliterator($locale, 'Title')) { + $str = clone $this; + $str->string = $transliterator->transliterate($str->string); + + return $str; + } + + return $this->title(); + } + public function trim(string $chars = " \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}"): static { if (" \t\n\r\0\x0B\x0C\u{A0}\u{FEFF}" !== $chars && !preg_match('//u', $chars)) { @@ -450,6 +486,21 @@ public function upper(): static return $str; } + /** + * @param string $locale In the format language_region (e.g. tr_TR) + */ + public function localeUpper(string $locale): static + { + if (null !== $transliterator = $this->getLocaleTransliterator($locale, 'Upper')) { + $str = clone $this; + $str->string = $transliterator->transliterate($str->string); + + return $str; + } + + return $this->upper(); + } + public function width(bool $ignoreAnsiDecoration = true): int { $width = 0; @@ -587,4 +638,33 @@ private function wcswidth(string $string): int return $width; } + + private function getLocaleTransliterator(string $locale, string $id): ?\Transliterator + { + $rule = $locale.'-'.$id; + if (\array_key_exists($rule, self::$transliterators)) { + return self::$transliterators[$rule]; + } + + if (null !== $transliterator = self::$transliterators[$rule] = \Transliterator::create($rule)) { + return $transliterator; + } + + // Try to find a parent locale (nl_BE -> nl) + if (false === $i = strpos($locale, '_')) { + return null; + } + + $parentRule = substr_replace($locale, '-'.$id, $i); + + // Parent locale was already cached, return and store as current locale + if (\array_key_exists($parentRule, self::$transliterators)) { + return self::$transliterators[$rule] = self::$transliterators[$parentRule]; + } + + // Create transliterator based on parent locale and cache the result on both initial and parent locale values + $transliterator = \Transliterator::create($parentRule); + + return self::$transliterators[$rule] = self::$transliterators[$parentRule] = $transliterator; + } } diff --git a/app/vendor/symfony/string/ByteString.php b/app/vendor/symfony/string/ByteString.php index 3ebe43c10..5cbfd6de4 100644 --- a/app/vendor/symfony/string/ByteString.php +++ b/app/vendor/symfony/string/ByteString.php @@ -11,6 +11,7 @@ namespace Symfony\Component\String; +use Random\Randomizer; use Symfony\Component\String\Exception\ExceptionInterface; use Symfony\Component\String\Exception\InvalidArgumentException; use Symfony\Component\String\Exception\RuntimeException; @@ -45,7 +46,7 @@ public function __construct(string $string = '') public static function fromRandom(int $length = 16, ?string $alphabet = null): self { if ($length <= 0) { - throw new InvalidArgumentException(sprintf('A strictly positive length is expected, "%d" given.', $length)); + throw new InvalidArgumentException(\sprintf('A strictly positive length is expected, "%d" given.', $length)); } $alphabet ??= self::ALPHABET_ALPHANUMERIC; @@ -55,6 +56,10 @@ public static function fromRandom(int $length = 16, ?string $alphabet = null): s throw new InvalidArgumentException('The length of the alphabet must in the [2^1, 2^56] range.'); } + if (\PHP_VERSION_ID >= 80300) { + return new static((new Randomizer())->getBytesFromString($alphabet, $length)); + } + $ret = ''; while ($length > 0) { $urandomLength = (int) ceil(2 * $length * $bits / 8.0); @@ -335,7 +340,7 @@ public function reverse(): static public function slice(int $start = 0, ?int $length = null): static { $str = clone $this; - $str->string = (string) substr($this->string, $start, $length ?? \PHP_INT_MAX); + $str->string = substr($this->string, $start, $length ?? \PHP_INT_MAX); return $str; } @@ -436,7 +441,7 @@ public function toCodePointString(?string $fromEncoding = null): CodePointString } if (!$validEncoding) { - throw new InvalidArgumentException(sprintf('Invalid "%s" string.', $fromEncoding ?? 'Windows-1252')); + throw new InvalidArgumentException(\sprintf('Invalid "%s" string.', $fromEncoding ?? 'Windows-1252')); } $u->string = mb_convert_encoding($this->string, 'UTF-8', $fromEncoding ?? 'Windows-1252'); diff --git a/app/vendor/symfony/string/CHANGELOG.md b/app/vendor/symfony/string/CHANGELOG.md index 31a3b54db..0782ae21b 100644 --- a/app/vendor/symfony/string/CHANGELOG.md +++ b/app/vendor/symfony/string/CHANGELOG.md @@ -1,6 +1,22 @@ CHANGELOG ========= +7.3 +--- + + * Add the `AbstractString::pascal()` method + +7.2 +--- + + * Add `TruncateMode` enum to handle more truncate methods + * Add the `AbstractString::kebab()` method + +7.1 +--- + + * Add `localeLower()`, `localeUpper()`, `localeTitle()` methods to `AbstractUnicodeString` + 6.2 --- diff --git a/app/vendor/symfony/string/Inflector/EnglishInflector.php b/app/vendor/symfony/string/Inflector/EnglishInflector.php index dc7b08e7e..73db80c6f 100644 --- a/app/vendor/symfony/string/Inflector/EnglishInflector.php +++ b/app/vendor/symfony/string/Inflector/EnglishInflector.php @@ -25,8 +25,35 @@ final class EnglishInflector implements InflectorInterface // Fourth entry: Whether the suffix may succeed a consonant // Fifth entry: singular suffix, normal - // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) - ['a', 1, true, true, ['on', 'um']], + // bacteria (bacterium) + ['airetcab', 8, true, true, 'bacterium'], + + // corpora (corpus) + ['aroproc', 7, true, true, 'corpus'], + + // criteria (criterion) + ['airetirc', 8, true, true, 'criterion'], + + // curricula (curriculum) + ['alucirruc', 9, true, true, 'curriculum'], + + // quora (quorum) + ['arouq', 5, true, true, 'quorum'], + + // genera (genus) + ['areneg', 6, true, true, 'genus'], + + // media (medium) + ['aidem', 5, true, true, 'medium'], + + // memoranda (memorandum) + ['adnaromem', 9, true, true, 'memorandum'], + + // phenomena (phenomenon) + ['anemonehp', 9, true, true, 'phenomenon'], + + // strata (stratum) + ['atarts', 6, true, true, 'stratum'], // nebulae (nebula) ['ea', 2, true, true, 'a'], @@ -97,6 +124,9 @@ final class EnglishInflector implements InflectorInterface // statuses (status) ['sesutats', 8, true, true, 'status'], + // article (articles), ancle (ancles) + ['sel', 3, true, true, 'le'], + // analyses (analysis), ellipses (ellipsis), fungi (fungus), // neuroses (neurosis), theses (thesis), emphases (emphasis), // oases (oasis), crises (crisis), houses (house), bases (base), @@ -141,7 +171,7 @@ final class EnglishInflector implements InflectorInterface // shoes (shoe) ['se', 2, true, true, ['', 'e']], - // status (status) + // status (status) ['sutats', 6, true, true, 'status'], // tags (tag) @@ -238,7 +268,13 @@ final class EnglishInflector implements InflectorInterface // teeth (tooth) ['htoot', 5, true, true, 'teeth'], - // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) + // albums (album) + ['mubla', 5, true, true, 'albums'], + + // quorums (quorum) + ['murouq', 6, true, true, ['quora', 'quorums']], + + // bacteria (bacterium), curricula (curriculum), media (medium), memoranda (memorandum), phenomena (phenomenon), strata (stratum) ['mu', 2, true, true, 'a'], // men (man), women (woman) @@ -247,20 +283,11 @@ final class EnglishInflector implements InflectorInterface // people (person) ['nosrep', 6, true, true, ['persons', 'people']], - // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) - ['noi', 3, true, true, 'ions'], - - // coupon (coupons) - ['nop', 3, true, true, 'pons'], + // criteria (criterion) + ['noiretirc', 9, true, true, 'criteria'], - // seasons (season), treasons (treason), poisons (poison), lessons (lesson) - ['nos', 3, true, true, 'sons'], - - // icons (icon) - ['noc', 3, true, true, 'cons'], - - // bacteria (bacterium), criteria (criterion), phenomena (phenomenon) - ['no', 2, true, true, 'a'], + // phenomena (phenomenon) + ['nonemonehp', 10, true, true, 'phenomena'], // echoes (echo) ['ohce', 4, true, true, 'echoes'], @@ -271,6 +298,9 @@ final class EnglishInflector implements InflectorInterface // atlases (atlas) ['salta', 5, true, true, 'atlases'], + // aliases (alias) + ['saila', 5, true, true, 'aliases'], + // irises (iris) ['siri', 4, true, true, 'irises'], @@ -303,6 +333,9 @@ final class EnglishInflector implements InflectorInterface // conspectuses (conspectus), prospectuses (prospectus) ['sutcep', 6, true, true, 'pectuses'], + // nexuses (nexus) + ['suxen', 5, false, false, 'nexuses'], + // fungi (fungus), alumni (alumnus), syllabi (syllabus), radii (radius) ['su', 2, true, true, 'i'], @@ -324,14 +357,14 @@ final class EnglishInflector implements InflectorInterface // indices (index) ['xedni', 5, false, true, ['indicies', 'indexes']], + // fax (faxes, faxxes) + ['xaf', 3, true, true, ['faxes', 'faxxes']], + // boxes (box) ['xo', 2, false, true, 'oxes'], - // indexes (index), matrixes (matrix) - ['x', 1, true, false, ['cies', 'xes']], - - // appendices (appendix) - ['xi', 2, false, true, 'ices'], + // indexes (index), matrixes (matrix), appendices (appendix) + ['x', 1, true, false, ['ces', 'xes']], // babies (baby) ['y', 1, false, true, 'ies'], @@ -396,6 +429,9 @@ final class EnglishInflector implements InflectorInterface // aircraft 'tfarcria', + + // hardware + 'erawdrah', ]; public function singularize(string $plural): array diff --git a/app/vendor/symfony/string/Inflector/SpanishInflector.php b/app/vendor/symfony/string/Inflector/SpanishInflector.php new file mode 100644 index 000000000..4b98cb627 --- /dev/null +++ b/app/vendor/symfony/string/Inflector/SpanishInflector.php @@ -0,0 +1,126 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\String\Inflector; + +final class SpanishInflector implements InflectorInterface +{ + /** + * A list of all rules for pluralise. + * + * @see https://www.spanishdict.com/guide/spanish-plural-noun-forms + * @see https://www.rae.es/gram%C3%A1tica/morfolog%C3%ADa/la-formaci%C3%B3n-del-plural-plurales-en-s-y-plurales-en-es-reglas-generales + */ + // First entry: regex + // Second entry: replacement + private const PLURALIZE_REGEXP = [ + // Specials sí, no + ['/(sí|no)$/i', '\1es'], + + // Words ending with vowel must use -s (RAE 3.2a, 3.2c) + ['/(a|e|i|o|u|á|é|í|ó|ú)$/i', '\1s'], + + // Word ending in s or x and the previous letter is accented (RAE 3.2n) + ['/ás$/i', 'ases'], + ['/és$/i', 'eses'], + ['/ís$/i', 'ises'], + ['/ós$/i', 'oses'], + ['/ús$/i', 'uses'], + + // Words ending in -ión must changed to -iones + ['/ión$/i', '\1iones'], + + // Words ending in some consonants must use -es (RAE 3.2k) + ['/(l|r|n|d|j|s|x|ch|y)$/i', '\1es'], + + // Word ending in z, must changed to ces + ['/(z)$/i', 'ces'], + ]; + + /** + * A list of all rules for singularize. + */ + private const SINGULARIZE_REGEXP = [ + // Specials sí, no + ['/(sí|no)es$/i', '\1'], + + // Words ending in -ión must changed to -iones + ['/iones$/i', '\1ión'], + + // Word ending in z, must changed to ces + ['/ces$/i', 'z'], + + // Word ending in s or x and the previous letter is accented (RAE 3.2n) + ['/(\w)ases$/i', '\1ás'], + ['/eses$/i', 'és'], + ['/ises$/i', 'ís'], + ['/(\w{2,})oses$/i', '\1ós'], + ['/(\w)uses$/i', '\1ús'], + + // Words ending in some consonants and -es, must be the consonants + ['/(l|r|n|d|j|s|x|ch|y)e?s$/i', '\1'], + + // Words ended with vowel and s, must be vowel + ['/(a|e|i|o|u|á|é|ó|í|ú)s$/i', '\1'], + ]; + + private const UNINFLECTED_RULES = [ + // Words ending with pies (RAE 3.2n) + '/.*(piés)$/i', + ]; + + private const UNINFLECTED = '/^(lunes|martes|miércoles|jueves|viernes|análisis|torax|yo|pies)$/i'; + + public function singularize(string $plural): array + { + if ($this->isInflectedWord($plural)) { + return [$plural]; + } + + foreach (self::SINGULARIZE_REGEXP as $rule) { + [$regexp, $replace] = $rule; + + if (1 === preg_match($regexp, $plural)) { + return [preg_replace($regexp, $replace, $plural)]; + } + } + + return [$plural]; + } + + public function pluralize(string $singular): array + { + if ($this->isInflectedWord($singular)) { + return [$singular]; + } + + foreach (self::PLURALIZE_REGEXP as $rule) { + [$regexp, $replace] = $rule; + + if (1 === preg_match($regexp, $singular)) { + return [preg_replace($regexp, $replace, $singular)]; + } + } + + return [$singular.'s']; + } + + private function isInflectedWord(string $word): bool + { + foreach (self::UNINFLECTED_RULES as $rule) { + if (1 === preg_match($rule, $word)) { + return true; + } + } + + return 1 === preg_match(self::UNINFLECTED, $word); + } +} diff --git a/app/vendor/symfony/string/LazyString.php b/app/vendor/symfony/string/LazyString.php index 519b54ab9..b86d7337e 100644 --- a/app/vendor/symfony/string/LazyString.php +++ b/app/vendor/symfony/string/LazyString.php @@ -26,7 +26,7 @@ class LazyString implements \Stringable, \JsonSerializable public static function fromCallable(callable|array $callback, mixed ...$arguments): static { if (\is_array($callback) && !\is_callable($callback) && !(($callback[0] ?? null) instanceof \Closure || 2 < \count($callback))) { - throw new \TypeError(sprintf('Argument 1 passed to "%s()" must be a callable or a [Closure, method] lazy-callable, "%s" given.', __METHOD__, '['.implode(', ', array_map('get_debug_type', $callback)).']')); + throw new \TypeError(\sprintf('Argument 1 passed to "%s()" must be a callable or a [Closure, method] lazy-callable, "%s" given.', __METHOD__, '['.implode(', ', array_map('get_debug_type', $callback)).']')); } $lazyString = new static(); @@ -94,7 +94,7 @@ public function __toString(): string $r = new \ReflectionFunction($this->value); $callback = $r->getStaticVariables()['callback']; - $e = new \TypeError(sprintf('Return value of %s() passed to %s::fromCallable() must be of the type string, %s returned.', $callback, static::class, $type)); + $e = new \TypeError(\sprintf('Return value of %s() passed to %s::fromCallable() must be of the type string, %s returned.', $callback, static::class, $type)); } throw $e; @@ -129,7 +129,7 @@ private static function getPrettyName(callable $callback): string } elseif ($callback instanceof \Closure) { $r = new \ReflectionFunction($callback); - if (str_contains($r->name, '{closure}') || !$class = $r->getClosureCalledClass()) { + if ($r->isAnonymous() || !$class = $r->getClosureCalledClass()) { return $r->name; } diff --git a/app/vendor/symfony/string/Resources/data/wcswidth_table_wide.php b/app/vendor/symfony/string/Resources/data/wcswidth_table_wide.php index 8314c8fd5..b2c94c36d 100644 --- a/app/vendor/symfony/string/Resources/data/wcswidth_table_wide.php +++ b/app/vendor/symfony/string/Resources/data/wcswidth_table_wide.php @@ -1,10 +1,17 @@ + * * This file has been auto-generated by the Symfony String Component for internal use. * - * Unicode version: 15.1.0 - * Date: 2023-09-13T11:47:12+00:00 + * Unicode version: 16.0.0 + * Date: 2024-09-11T08:21:22+00:00 + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ return [ @@ -44,6 +51,10 @@ 9748, 9749, ], + [ + 9776, + 9783, + ], [ 9800, 9811, @@ -52,6 +63,10 @@ 9855, 9855, ], + [ + 9866, + 9871, + ], [ 9875, 9875, @@ -394,7 +409,7 @@ ], [ 12736, - 12771, + 12773, ], [ 12783, @@ -452,6 +467,10 @@ 13312, 19903, ], + [ + 19904, + 19967, + ], [ 19968, 40959, @@ -836,6 +855,10 @@ 101120, 101589, ], + [ + 101631, + 101631, + ], [ 101632, 101640, @@ -880,6 +903,14 @@ 110960, 111355, ], + [ + 119552, + 119638, + ], + [ + 119648, + 119670, + ], [ 126980, 126980, @@ -1054,23 +1085,19 @@ ], [ 129664, - 129672, - ], - [ - 129680, - 129725, + 129673, ], [ - 129727, - 129733, + 129679, + 129734, ], [ 129742, - 129755, + 129756, ], [ - 129760, - 129768, + 129759, + 129769, ], [ 129776, diff --git a/app/vendor/symfony/string/Resources/data/wcswidth_table_zero.php b/app/vendor/symfony/string/Resources/data/wcswidth_table_zero.php index e5b26a215..287c36c64 100644 --- a/app/vendor/symfony/string/Resources/data/wcswidth_table_zero.php +++ b/app/vendor/symfony/string/Resources/data/wcswidth_table_zero.php @@ -1,10 +1,17 @@ + * * This file has been auto-generated by the Symfony String Component for internal use. * - * Unicode version: 15.1.0 - * Date: 2023-09-13T11:47:13+00:00 + * Unicode version: 16.0.0 + * Date: 2024-09-11T08:21:22+00:00 + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ return [ @@ -109,7 +116,7 @@ 2139, ], [ - 2200, + 2199, 2207, ], [ @@ -916,12 +923,16 @@ 68900, 68903, ], + [ + 68969, + 68973, + ], [ 69291, 69292, ], [ - 69373, + 69372, 69375, ], [ @@ -1044,6 +1055,26 @@ 70512, 70516, ], + [ + 70587, + 70592, + ], + [ + 70606, + 70606, + ], + [ + 70608, + 70608, + ], + [ + 70610, + 70610, + ], + [ + 70625, + 70626, + ], [ 70712, 70719, @@ -1122,6 +1153,10 @@ ], [ 71453, + 71453, + ], + [ + 71455, 71455, ], [ @@ -1276,6 +1311,10 @@ 73538, 73538, ], + [ + 73562, + 73562, + ], [ 78912, 78912, @@ -1284,6 +1323,14 @@ 78919, 78933, ], + [ + 90398, + 90409, + ], + [ + 90413, + 90415, + ], [ 92912, 92916, @@ -1400,6 +1447,10 @@ 124140, 124143, ], + [ + 124398, + 124399, + ], [ 125136, 125142, diff --git a/app/vendor/symfony/string/Slugger/AsciiSlugger.php b/app/vendor/symfony/string/Slugger/AsciiSlugger.php index fd47770c2..9d4edf15b 100644 --- a/app/vendor/symfony/string/Slugger/AsciiSlugger.php +++ b/app/vendor/symfony/string/Slugger/AsciiSlugger.php @@ -11,7 +11,7 @@ namespace Symfony\Component\String\Slugger; -use Symfony\Component\Intl\Transliterator\EmojiTransliterator; +use Symfony\Component\Emoji\EmojiTransliterator; use Symfony\Component\String\AbstractUnicodeString; use Symfony\Component\String\UnicodeString; use Symfony\Contracts\Translation\LocaleAwareInterface; @@ -55,7 +55,6 @@ class AsciiSlugger implements SluggerInterface, LocaleAwareInterface 'zh' => 'Han-Latin', ]; - private ?string $defaultLocale; private \Closure|array $symbolsMap = [ 'en' => ['@' => 'at', '&' => 'and'], ]; @@ -68,9 +67,10 @@ class AsciiSlugger implements SluggerInterface, LocaleAwareInterface */ private array $transliterators = []; - public function __construct(?string $defaultLocale = null, array|\Closure|null $symbolsMap = null) - { - $this->defaultLocale = $defaultLocale; + public function __construct( + private ?string $defaultLocale = null, + array|\Closure|null $symbolsMap = null, + ) { $this->symbolsMap = $symbolsMap ?? $this->symbolsMap; } @@ -92,7 +92,7 @@ public function getLocale(): string public function withEmoji(bool|string $emoji = true): static { if (false !== $emoji && !class_exists(EmojiTransliterator::class)) { - throw new \LogicException(sprintf('You cannot use the "%s()" method as the "symfony/intl" package is not installed. Try running "composer require symfony/intl".', __METHOD__)); + throw new \LogicException(\sprintf('You cannot use the "%s()" method as the "symfony/emoji" package is not installed. Try running "composer require symfony/emoji".', __METHOD__)); } $new = clone $this; diff --git a/app/vendor/symfony/string/TruncateMode.php b/app/vendor/symfony/string/TruncateMode.php new file mode 100644 index 000000000..12568cd5b --- /dev/null +++ b/app/vendor/symfony/string/TruncateMode.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\String; + +enum TruncateMode +{ + /** + * Will cut exactly at given length. + * + * Length: 14 + * Source: Lorem ipsum dolor sit amet + * Output: Lorem ipsum do + */ + case Char; + + /** + * Returns the string up to the last complete word containing the specified length. + * + * Length: 14 + * Source: Lorem ipsum dolor sit amet + * Output: Lorem ipsum + */ + case WordBefore; + + /** + * Returns the string up to the complete word after or at the given length. + * + * Length: 14 + * Source: Lorem ipsum dolor sit amet + * Output: Lorem ipsum dolor + */ + case WordAfter; +} diff --git a/app/vendor/symfony/string/UnicodeString.php b/app/vendor/symfony/string/UnicodeString.php index 4b16caf9f..b458de0c5 100644 --- a/app/vendor/symfony/string/UnicodeString.php +++ b/app/vendor/symfony/string/UnicodeString.php @@ -286,7 +286,7 @@ public function splice(string $replacement, int $start = 0, ?int $length = null) $str = clone $this; $start = $start ? \strlen(grapheme_substr($this->string, 0, $start)) : 0; - $length = $length ? \strlen(grapheme_substr($this->string, $start, $length ?? 2147483647)) : $length; + $length = $length ? \strlen(grapheme_substr($this->string, $start, $length)) : $length; $str->string = substr_replace($this->string, $replacement, $start, $length ?? 2147483647); if (normalizer_is_normalized($str->string)) { diff --git a/app/vendor/symfony/string/composer.json b/app/vendor/symfony/string/composer.json index 26ce26da3..10d0ee620 100644 --- a/app/vendor/symfony/string/composer.json +++ b/app/vendor/symfony/string/composer.json @@ -24,8 +24,9 @@ }, "require-dev": { "symfony/error-handler": "^6.4|^7.0", - "symfony/intl": "^6.4|^7.0", + "symfony/emoji": "^7.1", "symfony/http-client": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", "symfony/translation-contracts": "^2.5|^3.0", "symfony/var-exporter": "^6.4|^7.0" }, diff --git a/app/vendor/symfony/var-dumper/CHANGELOG.md b/app/vendor/symfony/var-dumper/CHANGELOG.md index f7021f59a..bb63a9854 100644 --- a/app/vendor/symfony/var-dumper/CHANGELOG.md +++ b/app/vendor/symfony/var-dumper/CHANGELOG.md @@ -1,6 +1,24 @@ CHANGELOG ========= +7.3 +--- + + * Add casters for `Dba\Connection`, `SQLite3Result`, `OpenSSLAsymmetricKey` and `OpenSSLCertificateSigningRequest` + * Deprecate `ResourceCaster::castCurl()`, `ResourceCaster::castGd()` and `ResourceCaster::castOpensslX509()` + * Mark all casters as `@internal` + +7.2 +--- + + * Add support for `FORCE_COLOR` environment variable + * Add support for virtual properties + +7.1 +--- + + * Add support for new DOM extension classes in `DOMCaster` + 7.0 --- diff --git a/app/vendor/symfony/var-dumper/Caster/AddressInfoCaster.php b/app/vendor/symfony/var-dumper/Caster/AddressInfoCaster.php new file mode 100644 index 000000000..f341c688f --- /dev/null +++ b/app/vendor/symfony/var-dumper/Caster/AddressInfoCaster.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * @author Nicolas Grekas + * + * @internal since Symfony 7.3 + */ +final class AddressInfoCaster +{ + private const MAPS = [ + 'ai_flags' => [ + 1 => 'AI_PASSIVE', + 2 => 'AI_CANONNAME', + 4 => 'AI_NUMERICHOST', + 8 => 'AI_V4MAPPED', + 16 => 'AI_ALL', + 32 => 'AI_ADDRCONFIG', + 64 => 'AI_IDN', + 128 => 'AI_CANONIDN', + 1024 => 'AI_NUMERICSERV', + ], + 'ai_family' => [ + 1 => 'AF_UNIX', + 2 => 'AF_INET', + 10 => 'AF_INET6', + 44 => 'AF_DIVERT', + ], + 'ai_socktype' => [ + 1 => 'SOCK_STREAM', + 2 => 'SOCK_DGRAM', + 3 => 'SOCK_RAW', + 4 => 'SOCK_RDM', + 5 => 'SOCK_SEQPACKET', + ], + 'ai_protocol' => [ + 1 => 'SOL_SOCKET', + 6 => 'SOL_TCP', + 17 => 'SOL_UDP', + 136 => 'SOL_UDPLITE', + ], + ]; + + public static function castAddressInfo(\AddressInfo $h, array $a, Stub $stub, bool $isNested): array + { + static $resolvedMaps; + + if (!$resolvedMaps) { + foreach (self::MAPS as $k => $map) { + foreach ($map as $v => $name) { + if (\defined($name)) { + $resolvedMaps[$k][\constant($name)] = $name; + } elseif (!isset($resolvedMaps[$k][$v])) { + $resolvedMaps[$k][$v] = $name; + } + } + } + } + + foreach (socket_addrinfo_explain($h) as $k => $v) { + $a[Caster::PREFIX_VIRTUAL.$k] = match (true) { + 'ai_flags' === $k => ConstStub::fromBitfield($v, $resolvedMaps[$k]), + isset($resolvedMaps[$k][$v]) => new ConstStub($resolvedMaps[$k][$v], $v), + default => $v, + }; + } + + return $a; + } +} diff --git a/app/vendor/symfony/var-dumper/Caster/AmqpCaster.php b/app/vendor/symfony/var-dumper/Caster/AmqpCaster.php index 68b1a65ff..ff56288bd 100644 --- a/app/vendor/symfony/var-dumper/Caster/AmqpCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/AmqpCaster.php @@ -19,6 +19,8 @@ * @author Grégoire Pineau * * @final + * + * @internal since Symfony 7.3 */ class AmqpCaster { diff --git a/app/vendor/symfony/var-dumper/Caster/ArgsStub.php b/app/vendor/symfony/var-dumper/Caster/ArgsStub.php index 9dc24c1b1..aadd033f3 100644 --- a/app/vendor/symfony/var-dumper/Caster/ArgsStub.php +++ b/app/vendor/symfony/var-dumper/Caster/ArgsStub.php @@ -42,10 +42,9 @@ public function __construct(array $args, string $function, ?string $class) $params[] = $variadic; } if (['...'] === $params) { - $this->dumpKeys = false; - $this->value = $values[0]->value; + parent::__construct($values[0]->value, false); } else { - $this->value = array_combine($params, $values); + parent::__construct(array_combine($params, $values)); } } diff --git a/app/vendor/symfony/var-dumper/Caster/Caster.php b/app/vendor/symfony/var-dumper/Caster/Caster.php index d9577e7ae..c3bc54e3a 100644 --- a/app/vendor/symfony/var-dumper/Caster/Caster.php +++ b/app/vendor/symfony/var-dumper/Caster/Caster.php @@ -46,6 +46,8 @@ class Caster * Casts objects to arrays and adds the dynamic property prefix. * * @param bool $hasDebugInfo Whether the __debugInfo method exists on $obj or not + * + * @internal since Symfony 7.3 */ public static function castObject(object $obj, string $class, bool $hasDebugInfo = false, ?string $debugClass = null): array { @@ -162,6 +164,9 @@ public static function filter(array $a, int $filter, array $listedProperties = [ return $a; } + /** + * @internal since Symfony 7.3 + */ public static function castPhpIncompleteClass(\__PHP_Incomplete_Class $c, array $a, Stub $stub, bool $isNested): array { if (isset($a['__PHP_Incomplete_Class_Name'])) { @@ -190,7 +195,7 @@ private static function getClassProperties(\ReflectionClass $class): array $p->isPublic() => $p->name, $p->isProtected() => self::PREFIX_PROTECTED.$p->name, default => "\0".$className."\0".$p->name, - }] = new UninitializedStub($p); + }] = \PHP_VERSION_ID >= 80400 && $p->isVirtual() ? new VirtualStub($p) : new UninitializedStub($p); } return $classProperties; diff --git a/app/vendor/symfony/var-dumper/Caster/ClassStub.php b/app/vendor/symfony/var-dumper/Caster/ClassStub.php index 5b9ce6407..265baa578 100644 --- a/app/vendor/symfony/var-dumper/Caster/ClassStub.php +++ b/app/vendor/symfony/var-dumper/Caster/ClassStub.php @@ -56,7 +56,7 @@ public function __construct(string $identifier, callable|array|string|null $call } if (str_contains($identifier, "@anonymous\0")) { - $this->value = $identifier = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', fn ($m) => class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0], $identifier); + $this->value = $identifier = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)?[0-9a-fA-F]++/', fn ($m) => class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0], $identifier); } if (null !== $callable && $r instanceof \ReflectionFunctionAbstract) { diff --git a/app/vendor/symfony/var-dumper/Caster/ConstStub.php b/app/vendor/symfony/var-dumper/Caster/ConstStub.php index 587c6c398..adea7860d 100644 --- a/app/vendor/symfony/var-dumper/Caster/ConstStub.php +++ b/app/vendor/symfony/var-dumper/Caster/ConstStub.php @@ -30,4 +30,23 @@ public function __toString(): string { return (string) $this->value; } + + /** + * @param array $values + */ + public static function fromBitfield(int $value, array $values): self + { + $names = []; + foreach ($values as $v => $name) { + if ($value & $v) { + $names[] = $name; + } + } + + if (!$names) { + $names[] = $values[0] ?? 0; + } + + return new self(implode(' | ', $names), $value); + } } diff --git a/app/vendor/symfony/var-dumper/Caster/CurlCaster.php b/app/vendor/symfony/var-dumper/Caster/CurlCaster.php new file mode 100644 index 000000000..fe4ec525c --- /dev/null +++ b/app/vendor/symfony/var-dumper/Caster/CurlCaster.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * @author Nicolas Grekas + * + * @internal + */ +final class CurlCaster +{ + public static function castCurl(\CurlHandle $h, array $a, Stub $stub, bool $isNested): array + { + foreach (curl_getinfo($h) as $key => $val) { + $a[Caster::PREFIX_VIRTUAL.$key] = $val; + } + + return $a; + } +} diff --git a/app/vendor/symfony/var-dumper/Caster/CutStub.php b/app/vendor/symfony/var-dumper/Caster/CutStub.php index 772399ef6..6870a9cd2 100644 --- a/app/vendor/symfony/var-dumper/Caster/CutStub.php +++ b/app/vendor/symfony/var-dumper/Caster/CutStub.php @@ -27,7 +27,7 @@ public function __construct(mixed $value) switch (\gettype($value)) { case 'object': $this->type = self::TYPE_OBJECT; - $this->class = $value::class; + $this->class = get_debug_type($value); if ($value instanceof \Closure) { ReflectionCaster::castClosure($value, [], $this, true, Caster::EXCLUDE_VERBOSE); diff --git a/app/vendor/symfony/var-dumper/Caster/DOMCaster.php b/app/vendor/symfony/var-dumper/Caster/DOMCaster.php index ca1ffcea6..e16b33d42 100644 --- a/app/vendor/symfony/var-dumper/Caster/DOMCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/DOMCaster.php @@ -19,11 +19,13 @@ * @author Nicolas Grekas * * @final + * + * @internal since Symfony 7.3 */ class DOMCaster { private const ERROR_CODES = [ - \DOM_PHP_ERR => 'DOM_PHP_ERR', + 0 => 'DOM_PHP_ERR', \DOM_INDEX_SIZE_ERR => 'DOM_INDEX_SIZE_ERR', \DOMSTRING_SIZE_ERR => 'DOMSTRING_SIZE_ERR', \DOM_HIERARCHY_REQUEST_ERR => 'DOM_HIERARCHY_REQUEST_ERR', @@ -63,7 +65,7 @@ class DOMCaster \XML_NAMESPACE_DECL_NODE => 'XML_NAMESPACE_DECL_NODE', ]; - public static function castException(\DOMException $e, array $a, Stub $stub, bool $isNested): array + public static function castException(\DOMException|\Dom\Exception $e, array $a, Stub $stub, bool $isNested): array { $k = Caster::PREFIX_PROTECTED.'code'; if (isset($a[$k], self::ERROR_CODES[$a[$k]])) { @@ -82,7 +84,7 @@ public static function castLength($dom, array $a, Stub $stub, bool $isNested): a return $a; } - public static function castImplementation(\DOMImplementation $dom, array $a, Stub $stub, bool $isNested): array + public static function castImplementation(\DOMImplementation|\Dom\Implementation $dom, array $a, Stub $stub, bool $isNested): array { $a += [ Caster::PREFIX_VIRTUAL.'Core' => '1.0', @@ -92,7 +94,7 @@ public static function castImplementation(\DOMImplementation $dom, array $a, Stu return $a; } - public static function castNode(\DOMNode $dom, array $a, Stub $stub, bool $isNested): array + public static function castNode(\DOMNode|\Dom\Node $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'nodeName' => $dom->nodeName, @@ -104,15 +106,20 @@ public static function castNode(\DOMNode $dom, array $a, Stub $stub, bool $isNes 'lastChild' => new CutStub($dom->lastChild), 'previousSibling' => new CutStub($dom->previousSibling), 'nextSibling' => new CutStub($dom->nextSibling), - 'attributes' => $dom->attributes, 'ownerDocument' => new CutStub($dom->ownerDocument), - 'namespaceURI' => $dom->namespaceURI, - 'prefix' => $dom->prefix, - 'localName' => $dom->localName, 'baseURI' => $dom->baseURI ? new LinkStub($dom->baseURI) : $dom->baseURI, 'textContent' => new CutStub($dom->textContent), ]; + if ($dom instanceof \DOMNode || $dom instanceof \Dom\Element) { + $a += [ + 'attributes' => $dom->attributes, + 'namespaceURI' => $dom->namespaceURI, + 'prefix' => $dom->prefix, + 'localName' => $dom->localName, + ]; + } + return $a; } @@ -138,16 +145,12 @@ public static function castDocument(\DOMDocument $dom, array $a, Stub $stub, boo 'doctype' => $dom->doctype, 'implementation' => $dom->implementation, 'documentElement' => new CutStub($dom->documentElement), - 'actualEncoding' => $dom->actualEncoding, 'encoding' => $dom->encoding, 'xmlEncoding' => $dom->xmlEncoding, - 'standalone' => $dom->standalone, 'xmlStandalone' => $dom->xmlStandalone, - 'version' => $dom->version, 'xmlVersion' => $dom->xmlVersion, 'strictErrorChecking' => $dom->strictErrorChecking, 'documentURI' => $dom->documentURI ? new LinkStub($dom->documentURI) : $dom->documentURI, - 'config' => $dom->config, 'formatOutput' => $dom->formatOutput, 'validateOnParse' => $dom->validateOnParse, 'resolveExternals' => $dom->resolveExternals, @@ -166,7 +169,48 @@ public static function castDocument(\DOMDocument $dom, array $a, Stub $stub, boo return $a; } - public static function castCharacterData(\DOMCharacterData $dom, array $a, Stub $stub, bool $isNested): array + public static function castXMLDocument(\Dom\XMLDocument $dom, array $a, Stub $stub, bool $isNested, int $filter = 0): array + { + $a += [ + 'doctype' => $dom->doctype, + 'implementation' => $dom->implementation, + 'documentElement' => new CutStub($dom->documentElement), + 'inputEncoding' => $dom->inputEncoding, + 'xmlEncoding' => $dom->xmlEncoding, + 'xmlStandalone' => $dom->xmlStandalone, + 'xmlVersion' => $dom->xmlVersion, + 'documentURI' => $dom->documentURI ? new LinkStub($dom->documentURI) : $dom->documentURI, + 'formatOutput' => $dom->formatOutput, + ]; + + if (!($filter & Caster::EXCLUDE_VERBOSE)) { + $formatOutput = $dom->formatOutput; + $dom->formatOutput = true; + $a += [Caster::PREFIX_VIRTUAL.'xml' => $dom->saveXML()]; + $dom->formatOutput = $formatOutput; + } + + return $a; + } + + public static function castHTMLDocument(\Dom\HTMLDocument $dom, array $a, Stub $stub, bool $isNested, int $filter = 0): array + { + $a += [ + 'doctype' => $dom->doctype, + 'implementation' => $dom->implementation, + 'documentElement' => new CutStub($dom->documentElement), + 'inputEncoding' => $dom->inputEncoding, + 'documentURI' => $dom->documentURI ? new LinkStub($dom->documentURI) : $dom->documentURI, + ]; + + if (!($filter & Caster::EXCLUDE_VERBOSE)) { + $a += [Caster::PREFIX_VIRTUAL.'html' => $dom->saveHTML()]; + } + + return $a; + } + + public static function castCharacterData(\DOMCharacterData|\Dom\CharacterData $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'data' => $dom->data, @@ -176,30 +220,40 @@ public static function castCharacterData(\DOMCharacterData $dom, array $a, Stub return $a; } - public static function castAttr(\DOMAttr $dom, array $a, Stub $stub, bool $isNested): array + public static function castAttr(\DOMAttr|\Dom\Attr $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'name' => $dom->name, 'specified' => $dom->specified, 'value' => $dom->value, 'ownerElement' => $dom->ownerElement, - 'schemaTypeInfo' => $dom->schemaTypeInfo, ]; + if ($dom instanceof \DOMAttr) { + $a += [ + 'schemaTypeInfo' => $dom->schemaTypeInfo, + ]; + } + return $a; } - public static function castElement(\DOMElement $dom, array $a, Stub $stub, bool $isNested): array + public static function castElement(\DOMElement|\Dom\Element $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'tagName' => $dom->tagName, - 'schemaTypeInfo' => $dom->schemaTypeInfo, ]; + if ($dom instanceof \DOMElement) { + $a += [ + 'schemaTypeInfo' => $dom->schemaTypeInfo, + ]; + } + return $a; } - public static function castText(\DOMText $dom, array $a, Stub $stub, bool $isNested): array + public static function castText(\DOMText|\Dom\Text $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'wholeText' => $dom->wholeText, @@ -208,7 +262,7 @@ public static function castText(\DOMText $dom, array $a, Stub $stub, bool $isNes return $a; } - public static function castDocumentType(\DOMDocumentType $dom, array $a, Stub $stub, bool $isNested): array + public static function castDocumentType(\DOMDocumentType|\Dom\DocumentType $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'name' => $dom->name, @@ -222,7 +276,7 @@ public static function castDocumentType(\DOMDocumentType $dom, array $a, Stub $s return $a; } - public static function castNotation(\DOMNotation $dom, array $a, Stub $stub, bool $isNested): array + public static function castNotation(\DOMNotation|\Dom\Notation $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'publicId' => $dom->publicId, @@ -232,21 +286,18 @@ public static function castNotation(\DOMNotation $dom, array $a, Stub $stub, boo return $a; } - public static function castEntity(\DOMEntity $dom, array $a, Stub $stub, bool $isNested): array + public static function castEntity(\DOMEntity|\Dom\Entity $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'publicId' => $dom->publicId, 'systemId' => $dom->systemId, 'notationName' => $dom->notationName, - 'actualEncoding' => $dom->actualEncoding, - 'encoding' => $dom->encoding, - 'version' => $dom->version, ]; return $a; } - public static function castProcessingInstruction(\DOMProcessingInstruction $dom, array $a, Stub $stub, bool $isNested): array + public static function castProcessingInstruction(\DOMProcessingInstruction|\Dom\ProcessingInstruction $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'target' => $dom->target, @@ -256,7 +307,7 @@ public static function castProcessingInstruction(\DOMProcessingInstruction $dom, return $a; } - public static function castXPath(\DOMXPath $dom, array $a, Stub $stub, bool $isNested): array + public static function castXPath(\DOMXPath|\Dom\XPath $dom, array $a, Stub $stub, bool $isNested): array { $a += [ 'document' => $dom->document, diff --git a/app/vendor/symfony/var-dumper/Caster/DateCaster.php b/app/vendor/symfony/var-dumper/Caster/DateCaster.php index cc8593940..453d0cb90 100644 --- a/app/vendor/symfony/var-dumper/Caster/DateCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/DateCaster.php @@ -19,6 +19,8 @@ * @author Dany Maillard * * @final + * + * @internal since Symfony 7.3 */ class DateCaster { @@ -93,16 +95,16 @@ public static function castPeriod(\DatePeriod $p, array $a, Stub $stub, bool $is foreach (clone $p as $i => $d) { if (self::PERIOD_LIMIT === $i) { $now = new \DateTimeImmutable('now', new \DateTimeZone('UTC')); - $dates[] = sprintf('%s more', ($end = $p->getEndDate()) + $dates[] = \sprintf('%s more', ($end = $p->getEndDate()) ? ceil(($end->format('U.u') - $d->format('U.u')) / ((int) $now->add($p->getDateInterval())->format('U.u') - (int) $now->format('U.u'))) : $p->recurrences - $i ); break; } - $dates[] = sprintf('%s) %s', $i + 1, self::formatDateTime($d)); + $dates[] = \sprintf('%s) %s', $i + 1, self::formatDateTime($d)); } - $period = sprintf( + $period = \sprintf( 'every %s, from %s%s %s', self::formatInterval($p->getDateInterval()), $p->include_start_date ? '[' : ']', @@ -122,6 +124,6 @@ private static function formatDateTime(\DateTimeInterface $d, string $extra = '' private static function formatSeconds(string $s, string $us): string { - return sprintf('%02d.%s', $s, 0 === ($len = \strlen($t = rtrim($us, '0'))) ? '0' : ($len <= 3 ? str_pad($t, 3, '0') : $us)); + return \sprintf('%02d.%s', $s, 0 === ($len = \strlen($t = rtrim($us, '0'))) ? '0' : ($len <= 3 ? str_pad($t, 3, '0') : $us)); } } diff --git a/app/vendor/symfony/var-dumper/Caster/DoctrineCaster.php b/app/vendor/symfony/var-dumper/Caster/DoctrineCaster.php index 74c06a416..b963112fc 100644 --- a/app/vendor/symfony/var-dumper/Caster/DoctrineCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/DoctrineCaster.php @@ -22,6 +22,8 @@ * @author Nicolas Grekas * * @final + * + * @internal since Symfony 7.3 */ class DoctrineCaster { diff --git a/app/vendor/symfony/var-dumper/Caster/EnumStub.php b/app/vendor/symfony/var-dumper/Caster/EnumStub.php index 02ed1745e..11e0cd9a1 100644 --- a/app/vendor/symfony/var-dumper/Caster/EnumStub.php +++ b/app/vendor/symfony/var-dumper/Caster/EnumStub.php @@ -20,11 +20,10 @@ */ class EnumStub extends Stub { - public bool $dumpKeys = true; - - public function __construct(array $values, bool $dumpKeys = true) - { + public function __construct( + array $values, + public bool $dumpKeys = true, + ) { $this->value = $values; - $this->dumpKeys = $dumpKeys; } } diff --git a/app/vendor/symfony/var-dumper/Caster/ExceptionCaster.php b/app/vendor/symfony/var-dumper/Caster/ExceptionCaster.php index ec2afb431..4473bdc8d 100644 --- a/app/vendor/symfony/var-dumper/Caster/ExceptionCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/ExceptionCaster.php @@ -22,6 +22,8 @@ * @author Nicolas Grekas * * @final + * + * @internal since Symfony 7.3 */ class ExceptionCaster { @@ -42,7 +44,7 @@ class ExceptionCaster \E_USER_ERROR => 'E_USER_ERROR', \E_USER_WARNING => 'E_USER_WARNING', \E_USER_NOTICE => 'E_USER_NOTICE', - \E_STRICT => 'E_STRICT', + 2048 => 'E_STRICT', ]; private static array $framesCache = []; @@ -174,7 +176,7 @@ public static function castTraceStub(TraceStub $trace, array $a, Stub $stub, boo } else { $label = substr_replace($prefix, "title=Stack level $j.", 2, 0).$lastCall; } - $a[substr_replace($label, sprintf('separator=%s&', $frame instanceof EnumStub ? ' ' : ':'), 2, 0)] = $frame; + $a[substr_replace($label, \sprintf('separator=%s&', $frame instanceof EnumStub ? ' ' : ':'), 2, 0)] = $frame; $lastCall = $call; } @@ -219,7 +221,7 @@ public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, boo if (isset($f['object'])) { $template = $f['object']; } elseif ((new \ReflectionClass($f['class']))->isInstantiable()) { - $template = unserialize(sprintf('O:%d:"%s":0:{}', \strlen($f['class']), $f['class'])); + $template = unserialize(\sprintf('O:%d:"%s":0:{}', \strlen($f['class']), $f['class'])); } if (null !== $template) { $ellipsis = 0; @@ -243,7 +245,7 @@ public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, boo $ellipsis += 1 + \strlen($f['line']); } } - $srcAttr .= sprintf('&separator= &file=%s&line=%d', rawurlencode($f['file']), $f['line']); + $srcAttr .= \sprintf('&separator= &file=%s&line=%d', rawurlencode($f['file']), $f['line']); } else { $srcAttr .= '&separator=:'; } @@ -271,7 +273,7 @@ public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, boo public static function castFlattenException(FlattenException $e, array $a, Stub $stub, bool $isNested): array { if ($isNested) { - $k = sprintf(Caster::PATTERN_PRIVATE, FlattenException::class, 'traceAsString'); + $k = \sprintf(Caster::PATTERN_PRIVATE, FlattenException::class, 'traceAsString'); $a[$k] = new CutStub($a[$k]); } @@ -299,7 +301,7 @@ private static function filterExceptionArray(string $xClass, array $a, string $x unset($a[$xPrefix.'string'], $a[Caster::PREFIX_DYNAMIC.'xdebug_message']); if (isset($a[Caster::PREFIX_PROTECTED.'message']) && str_contains($a[Caster::PREFIX_PROTECTED.'message'], "@anonymous\0")) { - $a[Caster::PREFIX_PROTECTED.'message'] = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', fn ($m) => class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0], $a[Caster::PREFIX_PROTECTED.'message']); + $a[Caster::PREFIX_PROTECTED.'message'] = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)?[0-9a-fA-F]++/', fn ($m) => class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0], $a[Caster::PREFIX_PROTECTED.'message']); } if (isset($a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line'])) { @@ -387,7 +389,7 @@ private static function extractSource(string $srcLines, int $line, int $srcConte } } $c->attr['lang'] = $lang; - $srcLines[sprintf("\0~separator=› &%d\0", $i + $line - $srcContext)] = $c; + $srcLines[\sprintf("\0~separator=› &%d\0", $i + $line - $srcContext)] = $c; } return new EnumStub($srcLines); diff --git a/app/vendor/symfony/var-dumper/Caster/FFICaster.php b/app/vendor/symfony/var-dumper/Caster/FFICaster.php index f1984eef3..973b69689 100644 --- a/app/vendor/symfony/var-dumper/Caster/FFICaster.php +++ b/app/vendor/symfony/var-dumper/Caster/FFICaster.php @@ -41,7 +41,7 @@ public static function castCTypeOrCData(CData|CType $data, array $args, Stub $st $type = \FFI::typeof($data); } - $stub->class = sprintf('%s<%s> size %d align %d', ($data ?? $type)::class, $type->getName(), $type->getSize(), $type->getAlignment()); + $stub->class = \sprintf('%s<%s> size %d align %d', ($data ?? $type)::class, $type->getName(), $type->getSize(), $type->getAlignment()); return match ($type->getKind()) { CType::TYPE_FLOAT, @@ -86,7 +86,7 @@ private static function castFFIFunction(Stub $stub, CType $type): array CType::ABI_MS => '[ms]', CType::ABI_SYSV => '[sysv]', CType::ABI_VECTORCALL => '[vectorcall]', - default => '[unknown abi]' + default => '[unknown abi]', }; $returnType = $type->getFuncReturnType(); @@ -115,11 +115,21 @@ private static function castFFIPointer(Stub $stub, CType $type, ?CData $data = n private static function castFFIStringValue(CData $data): string|CutStub { $result = []; + $ffi = \FFI::cdef(<<zend_get_page_size(); + + // get cdata address + $start = $ffi->cast('uintptr_t', $ffi->cast('char*', $data))->cdata; + // accessing memory in the same page as $start is safe + $max = min(self::MAX_STRING_LENGTH, ($start | ($pageSize - 1)) - $start); + + for ($i = 0; $i < $max; ++$i) { $result[$i] = $data[$i]; - if ("\0" === $result[$i]) { + if ("\0" === $data[$i]) { return implode('', $result); } } diff --git a/app/vendor/symfony/var-dumper/Caster/FrameStub.php b/app/vendor/symfony/var-dumper/Caster/FrameStub.php index 9968c1101..e57aa4630 100644 --- a/app/vendor/symfony/var-dumper/Caster/FrameStub.php +++ b/app/vendor/symfony/var-dumper/Caster/FrameStub.php @@ -18,13 +18,11 @@ */ class FrameStub extends EnumStub { - public bool $keepArgs; - public bool $inTraceStub; - - public function __construct(array $frame, bool $keepArgs = true, bool $inTraceStub = false) - { - $this->value = $frame; - $this->keepArgs = $keepArgs; - $this->inTraceStub = $inTraceStub; + public function __construct( + array $frame, + public bool $keepArgs = true, + public bool $inTraceStub = false, + ) { + parent::__construct($frame); } } diff --git a/app/vendor/symfony/var-dumper/Caster/GdCaster.php b/app/vendor/symfony/var-dumper/Caster/GdCaster.php new file mode 100644 index 000000000..db87653e7 --- /dev/null +++ b/app/vendor/symfony/var-dumper/Caster/GdCaster.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * @author Nicolas Grekas + * + * @internal + */ +final class GdCaster +{ + public static function castGd(\GdImage $gd, array $a, Stub $stub, bool $isNested): array + { + $a[Caster::PREFIX_VIRTUAL.'size'] = imagesx($gd).'x'.imagesy($gd); + $a[Caster::PREFIX_VIRTUAL.'trueColor'] = imageistruecolor($gd); + + return $a; + } +} diff --git a/app/vendor/symfony/var-dumper/Caster/GmpCaster.php b/app/vendor/symfony/var-dumper/Caster/GmpCaster.php index b018cc7f8..325d2e904 100644 --- a/app/vendor/symfony/var-dumper/Caster/GmpCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/GmpCaster.php @@ -20,6 +20,8 @@ * @author Nicolas Grekas * * @final + * + * @internal since Symfony 7.3 */ class GmpCaster { diff --git a/app/vendor/symfony/var-dumper/Caster/ImagineCaster.php b/app/vendor/symfony/var-dumper/Caster/ImagineCaster.php index d1289da33..0fb2a9033 100644 --- a/app/vendor/symfony/var-dumper/Caster/ImagineCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/ImagineCaster.php @@ -16,6 +16,8 @@ /** * @author Grégoire Pineau + * + * @internal since Symfony 7.3 */ final class ImagineCaster { diff --git a/app/vendor/symfony/var-dumper/Caster/IntlCaster.php b/app/vendor/symfony/var-dumper/Caster/IntlCaster.php index f386c7215..529c8f76c 100644 --- a/app/vendor/symfony/var-dumper/Caster/IntlCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/IntlCaster.php @@ -18,6 +18,8 @@ * @author Jan Schädlich * * @final + * + * @internal since Symfony 7.3 */ class IntlCaster { diff --git a/app/vendor/symfony/var-dumper/Caster/MemcachedCaster.php b/app/vendor/symfony/var-dumper/Caster/MemcachedCaster.php index 740785cea..4e4f611f1 100644 --- a/app/vendor/symfony/var-dumper/Caster/MemcachedCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/MemcachedCaster.php @@ -17,6 +17,8 @@ * @author Jan Schädlich * * @final + * + * @internal since Symfony 7.3 */ class MemcachedCaster { diff --git a/app/vendor/symfony/var-dumper/Caster/OpenSSLCaster.php b/app/vendor/symfony/var-dumper/Caster/OpenSSLCaster.php new file mode 100644 index 000000000..4c311ac4a --- /dev/null +++ b/app/vendor/symfony/var-dumper/Caster/OpenSSLCaster.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * @author Nicolas Grekas + * @author Alexandre Daubois + * + * @internal + */ +final class OpenSSLCaster +{ + public static function castOpensslX509(\OpenSSLCertificate $h, array $a, Stub $stub, bool $isNested): array + { + $stub->cut = -1; + $info = openssl_x509_parse($h, false); + + $pin = openssl_pkey_get_public($h); + $pin = openssl_pkey_get_details($pin)['key']; + $pin = \array_slice(explode("\n", $pin), 1, -2); + $pin = base64_decode(implode('', $pin)); + $pin = base64_encode(hash('sha256', $pin, true)); + + $a += [ + Caster::PREFIX_VIRTUAL.'subject' => new EnumStub(array_intersect_key($info['subject'], ['organizationName' => true, 'commonName' => true])), + Caster::PREFIX_VIRTUAL.'issuer' => new EnumStub(array_intersect_key($info['issuer'], ['organizationName' => true, 'commonName' => true])), + Caster::PREFIX_VIRTUAL.'expiry' => new ConstStub(date(\DateTimeInterface::ISO8601, $info['validTo_time_t']), $info['validTo_time_t']), + Caster::PREFIX_VIRTUAL.'fingerprint' => new EnumStub([ + 'md5' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'md5')), 2, ':', true)), + 'sha1' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'sha1')), 2, ':', true)), + 'sha256' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'sha256')), 2, ':', true)), + 'pin-sha256' => new ConstStub($pin), + ]), + ]; + + return $a; + } + + public static function castOpensslAsymmetricKey(\OpenSSLAsymmetricKey $key, array $a, Stub $stub, bool $isNested): array + { + foreach (openssl_pkey_get_details($key) as $k => $v) { + $a[Caster::PREFIX_VIRTUAL.$k] = $v; + } + + unset($a[Caster::PREFIX_VIRTUAL.'rsa']); // binary data + + return $a; + } + + public static function castOpensslCsr(\OpenSSLCertificateSigningRequest $csr, array $a, Stub $stub, bool $isNested): array + { + foreach (openssl_csr_get_subject($csr, false) as $k => $v) { + $a[Caster::PREFIX_VIRTUAL.$k] = $v; + } + + return $a; + } +} diff --git a/app/vendor/symfony/var-dumper/Caster/PdoCaster.php b/app/vendor/symfony/var-dumper/Caster/PdoCaster.php index 1d364cdf0..697e4122f 100644 --- a/app/vendor/symfony/var-dumper/Caster/PdoCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/PdoCaster.php @@ -19,6 +19,8 @@ * @author Nicolas Grekas * * @final + * + * @internal since Symfony 7.3 */ class PdoCaster { diff --git a/app/vendor/symfony/var-dumper/Caster/PgSqlCaster.php b/app/vendor/symfony/var-dumper/Caster/PgSqlCaster.php index 7e7450086..3d6cb7d74 100644 --- a/app/vendor/symfony/var-dumper/Caster/PgSqlCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/PgSqlCaster.php @@ -14,11 +14,13 @@ use Symfony\Component\VarDumper\Cloner\Stub; /** - * Casts pqsql resources to array representation. + * Casts pgsql resources to array representation. * * @author Nicolas Grekas * * @final + * + * @internal since Symfony 7.3 */ class PgSqlCaster { @@ -131,11 +133,11 @@ public static function castResult($result, array $a, Stub $stub, bool $isNested) for ($i = 0; $i < $fields; ++$i) { $field = [ 'name' => pg_field_name($result, $i), - 'table' => sprintf('%s (OID: %s)', pg_field_table($result, $i), pg_field_table($result, $i, true)), - 'type' => sprintf('%s (OID: %s)', pg_field_type($result, $i), pg_field_type_oid($result, $i)), - 'nullable' => (bool) pg_field_is_null($result, $i), + 'table' => \sprintf('%s (OID: %s)', pg_field_table($result, $i), pg_field_table($result, $i, true)), + 'type' => \sprintf('%s (OID: %s)', pg_field_type($result, $i), pg_field_type_oid($result, $i)), + 'nullable' => (bool) (\PHP_VERSION_ID >= 80300 ? pg_field_is_null($result, null, $i) : pg_field_is_null($result, $i)), 'storage' => pg_field_size($result, $i).' bytes', - 'display' => pg_field_prtlen($result, $i).' chars', + 'display' => (\PHP_VERSION_ID >= 80300 ? pg_field_prtlen($result, null, $i) : pg_field_prtlen($result, $i)).' chars', ]; if (' (OID: )' === $field['table']) { $field['table'] = null; diff --git a/app/vendor/symfony/var-dumper/Caster/ProxyManagerCaster.php b/app/vendor/symfony/var-dumper/Caster/ProxyManagerCaster.php index 736a6e758..0d954f488 100644 --- a/app/vendor/symfony/var-dumper/Caster/ProxyManagerCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/ProxyManagerCaster.php @@ -18,6 +18,8 @@ * @author Nicolas Grekas * * @final + * + * @internal since Symfony 7.3 */ class ProxyManagerCaster { diff --git a/app/vendor/symfony/var-dumper/Caster/RdKafkaCaster.php b/app/vendor/symfony/var-dumper/Caster/RdKafkaCaster.php index 5445b2d4b..bfadef2f9 100644 --- a/app/vendor/symfony/var-dumper/Caster/RdKafkaCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/RdKafkaCaster.php @@ -28,6 +28,8 @@ * Casts RdKafka related classes to array representation. * * @author Romain Neutron + * + * @internal since Symfony 7.3 */ class RdKafkaCaster { diff --git a/app/vendor/symfony/var-dumper/Caster/RedisCaster.php b/app/vendor/symfony/var-dumper/Caster/RedisCaster.php index 5224bc05d..a1ed95de5 100644 --- a/app/vendor/symfony/var-dumper/Caster/RedisCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/RedisCaster.php @@ -20,6 +20,8 @@ * @author Nicolas Grekas * * @final + * + * @internal since Symfony 7.3 */ class RedisCaster { diff --git a/app/vendor/symfony/var-dumper/Caster/ReflectionCaster.php b/app/vendor/symfony/var-dumper/Caster/ReflectionCaster.php index f42d06cb6..e7310f404 100644 --- a/app/vendor/symfony/var-dumper/Caster/ReflectionCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/ReflectionCaster.php @@ -19,6 +19,8 @@ * @author Nicolas Grekas * * @final + * + * @internal since Symfony 7.3 */ class ReflectionCaster { @@ -42,7 +44,7 @@ public static function castClosure(\Closure $c, array $a, Stub $stub, bool $isNe $a = static::castFunctionAbstract($c, $a, $stub, $isNested, $filter); - if (!str_contains($c->name, '{closure}')) { + if (!$c->isAnonymous()) { $stub->class = isset($a[$prefix.'class']) ? $a[$prefix.'class']->value.'::'.$c->name : $c->name; unset($a[$prefix.'class']); } @@ -83,13 +85,13 @@ public static function castGenerator(\Generator $c, array $a, Stub $stub, bool $ // Cannot create ReflectionGenerator based on a terminated Generator try { $reflectionGenerator = new \ReflectionGenerator($c); + + return self::castReflectionGenerator($reflectionGenerator, $a, $stub, $isNested); } catch (\Exception) { $a[Caster::PREFIX_VIRTUAL.'closed'] = true; return $a; } - - return self::castReflectionGenerator($reflectionGenerator, $a, $stub, $isNested); } public static function castType(\ReflectionType $c, array $a, Stub $stub, bool $isNested): array @@ -98,7 +100,7 @@ public static function castType(\ReflectionType $c, array $a, Stub $stub, bool $ if ($c instanceof \ReflectionNamedType) { $a += [ - $prefix.'name' => $c instanceof \ReflectionNamedType ? $c->getName() : (string) $c, + $prefix.'name' => $c->getName(), $prefix.'allowsNull' => $c->allowsNull(), $prefix.'isBuiltin' => $c->isBuiltin(), ]; @@ -116,10 +118,16 @@ public static function castType(\ReflectionType $c, array $a, Stub $stub, bool $ public static function castAttribute(\ReflectionAttribute $c, array $a, Stub $stub, bool $isNested): array { - self::addMap($a, $c, [ + $map = [ 'name' => 'getName', 'arguments' => 'getArguments', - ]); + ]; + + if (\PHP_VERSION_ID >= 80400) { + unset($map['name']); + } + + self::addMap($a, $c, $map); return $a; } @@ -204,7 +212,7 @@ public static function castFunctionAbstract(\ReflectionFunctionAbstract $c, arra if (isset($a[$prefix.'returnType'])) { $v = $a[$prefix.'returnType']; $v = $v instanceof \ReflectionNamedType ? $v->getName() : (string) $v; - $a[$prefix.'returnType'] = new ClassStub($a[$prefix.'returnType'] instanceof \ReflectionNamedType && $a[$prefix.'returnType']->allowsNull() && 'mixed' !== $v ? '?'.$v : $v, [class_exists($v, false) || interface_exists($v, false) || trait_exists($v, false) ? $v : '', '']); + $a[$prefix.'returnType'] = new ClassStub($a[$prefix.'returnType'] instanceof \ReflectionNamedType && $a[$prefix.'returnType']->allowsNull() && !\in_array($v, ['mixed', 'null'], true) ? '?'.$v : $v, [class_exists($v, false) || interface_exists($v, false) || trait_exists($v, false) ? $v : '', '']); } if (isset($a[$prefix.'class'])) { $a[$prefix.'class'] = new ClassStub($a[$prefix.'class']); @@ -362,7 +370,7 @@ public static function getSignature(array $a): string if (!$type instanceof \ReflectionNamedType) { $signature .= $type.' '; } else { - if (!$param->isOptional() && $param->allowsNull() && 'mixed' !== $type->getName()) { + if ($param->allowsNull() && !\in_array($type->getName(), ['mixed', 'null'], true)) { $signature .= '?'; } $signature .= substr(strrchr('\\'.$type->getName(), '\\'), 1).' '; diff --git a/app/vendor/symfony/var-dumper/Caster/ResourceCaster.php b/app/vendor/symfony/var-dumper/Caster/ResourceCaster.php index f775f81ca..47c2efc69 100644 --- a/app/vendor/symfony/var-dumper/Caster/ResourceCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/ResourceCaster.php @@ -19,16 +19,31 @@ * @author Nicolas Grekas * * @final + * + * @internal since Symfony 7.3 */ class ResourceCaster { + /** + * @deprecated since Symfony 7.3 + */ public static function castCurl(\CurlHandle $h, array $a, Stub $stub, bool $isNested): array { - return curl_getinfo($h); + trigger_deprecation('symfony/var-dumper', '7.3', 'The "%s()" method is deprecated without replacement.', __METHOD__); + + return CurlCaster::castCurl($h, $a, $stub, $isNested); } - public static function castDba($dba, array $a, Stub $stub, bool $isNested): array + /** + * @param resource|\Dba\Connection $dba + */ + public static function castDba(mixed $dba, array $a, Stub $stub, bool $isNested): array { + if (\PHP_VERSION_ID < 80402 && !\is_resource($dba)) { + // @see https://github.com/php/php-src/issues/16990 + return $a; + } + $list = dba_list(); $a['file'] = $list[(int) $dba]; @@ -55,37 +70,23 @@ public static function castStreamContext($stream, array $a, Stub $stub, bool $is return @stream_context_get_params($stream) ?: $a; } - public static function castGd($gd, array $a, Stub $stub, bool $isNested): array + /** + * @deprecated since Symfony 7.3 + */ + public static function castGd(\GdImage $gd, array $a, Stub $stub, bool $isNested): array { - $a['size'] = imagesx($gd).'x'.imagesy($gd); - $a['trueColor'] = imageistruecolor($gd); + trigger_deprecation('symfony/var-dumper', '7.3', 'The "%s()" method is deprecated without replacement.', __METHOD__); - return $a; + return GdCaster::castGd($gd, $a, $stub, $isNested); } - public static function castOpensslX509($h, array $a, Stub $stub, bool $isNested): array + /** + * @deprecated since Symfony 7.3 + */ + public static function castOpensslX509(\OpenSSLCertificate $h, array $a, Stub $stub, bool $isNested): array { - $stub->cut = -1; - $info = openssl_x509_parse($h, false); - - $pin = openssl_pkey_get_public($h); - $pin = openssl_pkey_get_details($pin)['key']; - $pin = \array_slice(explode("\n", $pin), 1, -2); - $pin = base64_decode(implode('', $pin)); - $pin = base64_encode(hash('sha256', $pin, true)); - - $a += [ - 'subject' => new EnumStub(array_intersect_key($info['subject'], ['organizationName' => true, 'commonName' => true])), - 'issuer' => new EnumStub(array_intersect_key($info['issuer'], ['organizationName' => true, 'commonName' => true])), - 'expiry' => new ConstStub(date(\DateTimeInterface::ISO8601, $info['validTo_time_t']), $info['validTo_time_t']), - 'fingerprint' => new EnumStub([ - 'md5' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'md5')), 2, ':', true)), - 'sha1' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'sha1')), 2, ':', true)), - 'sha256' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'sha256')), 2, ':', true)), - 'pin-sha256' => new ConstStub($pin), - ]), - ]; + trigger_deprecation('symfony/var-dumper', '7.3', 'The "%s()" method is deprecated without replacement.', __METHOD__); - return $a; + return OpenSSLCaster::castOpensslX509($h, $a, $stub, $isNested); } } diff --git a/app/vendor/symfony/var-dumper/Caster/SocketCaster.php b/app/vendor/symfony/var-dumper/Caster/SocketCaster.php new file mode 100644 index 000000000..6b95cd10e --- /dev/null +++ b/app/vendor/symfony/var-dumper/Caster/SocketCaster.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * @author Nicolas Grekas + * @author Alexandre Daubois + * + * @internal + */ +final class SocketCaster +{ + public static function castSocket(\Socket $socket, array $a, Stub $stub, bool $isNested): array + { + socket_getsockname($socket, $addr, $port); + $info = stream_get_meta_data(socket_export_stream($socket)); + + if (\PHP_VERSION_ID >= 80300) { + $uri = ($info['uri'] ?? '//'); + if (str_starts_with($uri, 'unix://')) { + $uri .= $addr; + } else { + $uri .= \sprintf(str_contains($addr, ':') ? '[%s]:%s' : '%s:%s', $addr, $port); + } + + $a[Caster::PREFIX_VIRTUAL.'uri'] = $uri; + + if (@socket_atmark($socket)) { + $a[Caster::PREFIX_VIRTUAL.'atmark'] = true; + } + } + + $a += [ + Caster::PREFIX_VIRTUAL.'timed_out' => $info['timed_out'], + Caster::PREFIX_VIRTUAL.'blocked' => $info['blocked'], + ]; + + if (!$lastError = socket_last_error($socket)) { + return $a; + } + + static $errors; + + if (!$errors) { + $errors = get_defined_constants(true)['sockets'] ?? []; + $errors = array_flip(array_filter($errors, static fn ($k) => str_starts_with($k, 'SOCKET_E'), \ARRAY_FILTER_USE_KEY)); + } + + $a[Caster::PREFIX_VIRTUAL.'last_error'] = new ConstStub($errors[$lastError], socket_strerror($lastError)); + + return $a; + } +} diff --git a/app/vendor/symfony/var-dumper/Caster/SplCaster.php b/app/vendor/symfony/var-dumper/Caster/SplCaster.php index c6953646b..31f4b11cc 100644 --- a/app/vendor/symfony/var-dumper/Caster/SplCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/SplCaster.php @@ -19,6 +19,8 @@ * @author Nicolas Grekas * * @final + * + * @internal since Symfony 7.3 */ class SplCaster { @@ -126,7 +128,7 @@ public static function castFileInfo(\SplFileInfo $c, array $a, Stub $stub, bool } if (isset($a[$prefix.'perms'])) { - $a[$prefix.'perms'] = new ConstStub(sprintf('0%o', $a[$prefix.'perms']), $a[$prefix.'perms']); + $a[$prefix.'perms'] = new ConstStub(\sprintf('0%o', $a[$prefix.'perms']), $a[$prefix.'perms']); } static $mapDate = ['aTime', 'mTime', 'cTime']; @@ -187,7 +189,7 @@ public static function castObjectStorage(\SplObjectStorage $c, array $a, Stub $s $storage[] = new EnumStub([ 'object' => $obj, 'info' => $clone->getInfo(), - ]); + ]); } $a += [ @@ -219,7 +221,7 @@ public static function castWeakMap(\WeakMap $c, array $a, Stub $stub, bool $isNe $map[] = new EnumStub([ 'object' => $obj, 'data' => $data, - ]); + ]); } $a += [ diff --git a/app/vendor/symfony/var-dumper/Caster/SqliteCaster.php b/app/vendor/symfony/var-dumper/Caster/SqliteCaster.php new file mode 100644 index 000000000..25d47ac48 --- /dev/null +++ b/app/vendor/symfony/var-dumper/Caster/SqliteCaster.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * @author Alexandre Daubois + * + * @internal + */ +final class SqliteCaster +{ + public static function castSqlite3Result(\SQLite3Result $result, array $a, Stub $stub, bool $isNested): array + { + $numColumns = $result->numColumns(); + for ($i = 0; $i < $numColumns; ++$i) { + $a[Caster::PREFIX_VIRTUAL.'columnNames'][$i] = $result->columnName($i); + } + + return $a; + } +} diff --git a/app/vendor/symfony/var-dumper/Caster/StubCaster.php b/app/vendor/symfony/var-dumper/Caster/StubCaster.php index 56742b018..85cf99731 100644 --- a/app/vendor/symfony/var-dumper/Caster/StubCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/StubCaster.php @@ -19,6 +19,8 @@ * @author Nicolas Grekas * * @final + * + * @internal since Symfony 7.3 */ class StubCaster { diff --git a/app/vendor/symfony/var-dumper/Caster/SymfonyCaster.php b/app/vendor/symfony/var-dumper/Caster/SymfonyCaster.php index 5cd90f734..0921f6254 100644 --- a/app/vendor/symfony/var-dumper/Caster/SymfonyCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/SymfonyCaster.php @@ -19,6 +19,8 @@ /** * @final + * + * @internal since Symfony 7.3 */ class SymfonyCaster { @@ -48,7 +50,7 @@ public static function castRequest(Request $request, array $a, Stub $stub, bool public static function castHttpClient($client, array $a, Stub $stub, bool $isNested): array { - $multiKey = sprintf("\0%s\0multi", $client::class); + $multiKey = \sprintf("\0%s\0multi", $client::class); if (isset($a[$multiKey])) { $a[$multiKey] = new CutStub($a[$multiKey]); } @@ -78,12 +80,14 @@ public static function castLazyObjectState($state, array $a, Stub $stub, bool $i $instance = $a['realInstance'] ?? null; - $a = ['status' => new ConstStub(match ($a['status']) { - LazyObjectState::STATUS_INITIALIZED_FULL => 'INITIALIZED_FULL', - LazyObjectState::STATUS_INITIALIZED_PARTIAL => 'INITIALIZED_PARTIAL', - LazyObjectState::STATUS_UNINITIALIZED_FULL => 'UNINITIALIZED_FULL', - LazyObjectState::STATUS_UNINITIALIZED_PARTIAL => 'UNINITIALIZED_PARTIAL', - }, $a['status'])]; + if (isset($a['status'])) { // forward-compat with Symfony 8 + $a = ['status' => new ConstStub(match ($a['status']) { + LazyObjectState::STATUS_INITIALIZED_FULL => 'INITIALIZED_FULL', + LazyObjectState::STATUS_INITIALIZED_PARTIAL => 'INITIALIZED_PARTIAL', + LazyObjectState::STATUS_UNINITIALIZED_FULL => 'UNINITIALIZED_FULL', + LazyObjectState::STATUS_UNINITIALIZED_PARTIAL => 'UNINITIALIZED_PARTIAL', + }, $a['status'])]; + } if ($instance) { $a['realInstance'] = $instance; diff --git a/app/vendor/symfony/var-dumper/Caster/TraceStub.php b/app/vendor/symfony/var-dumper/Caster/TraceStub.php index 5766e5169..b732eb205 100644 --- a/app/vendor/symfony/var-dumper/Caster/TraceStub.php +++ b/app/vendor/symfony/var-dumper/Caster/TraceStub.php @@ -20,17 +20,13 @@ */ class TraceStub extends Stub { - public bool $keepArgs; - public int $sliceOffset; - public ?int $sliceLength; - public int $numberingOffset; - - public function __construct(array $trace, bool $keepArgs = true, int $sliceOffset = 0, ?int $sliceLength = null, int $numberingOffset = 0) - { + public function __construct( + array $trace, + public bool $keepArgs = true, + public int $sliceOffset = 0, + public ?int $sliceLength = null, + public int $numberingOffset = 0, + ) { $this->value = $trace; - $this->keepArgs = $keepArgs; - $this->sliceOffset = $sliceOffset; - $this->sliceLength = $sliceLength; - $this->numberingOffset = $numberingOffset; } } diff --git a/app/vendor/symfony/var-dumper/Caster/UuidCaster.php b/app/vendor/symfony/var-dumper/Caster/UuidCaster.php index b10277457..732ad7ccf 100644 --- a/app/vendor/symfony/var-dumper/Caster/UuidCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/UuidCaster.php @@ -16,6 +16,8 @@ /** * @author Grégoire Pineau + * + * @internal since Symfony 7.3 */ final class UuidCaster { diff --git a/app/vendor/symfony/var-dumper/Caster/VirtualStub.php b/app/vendor/symfony/var-dumper/Caster/VirtualStub.php new file mode 100644 index 000000000..60b58faa1 --- /dev/null +++ b/app/vendor/symfony/var-dumper/Caster/VirtualStub.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +class VirtualStub extends ConstStub +{ + public function __construct(\ReflectionProperty $property) + { + parent::__construct('~'.($property->hasType() ? ' '.$property->getType() : ''), 'Virtual property'); + $this->attr['virtual'] = true; + } +} diff --git a/app/vendor/symfony/var-dumper/Caster/XmlReaderCaster.php b/app/vendor/symfony/var-dumper/Caster/XmlReaderCaster.php index 672fec68f..00420c79f 100644 --- a/app/vendor/symfony/var-dumper/Caster/XmlReaderCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/XmlReaderCaster.php @@ -19,6 +19,8 @@ * @author Baptiste Clavié * * @final + * + * @internal since Symfony 7.3 */ class XmlReaderCaster { diff --git a/app/vendor/symfony/var-dumper/Caster/XmlResourceCaster.php b/app/vendor/symfony/var-dumper/Caster/XmlResourceCaster.php index fd3d3a2ab..f6b08965b 100644 --- a/app/vendor/symfony/var-dumper/Caster/XmlResourceCaster.php +++ b/app/vendor/symfony/var-dumper/Caster/XmlResourceCaster.php @@ -19,6 +19,8 @@ * @author Nicolas Grekas * * @final + * + * @internal since Symfony 7.3 */ class XmlResourceCaster { diff --git a/app/vendor/symfony/var-dumper/Cloner/AbstractCloner.php b/app/vendor/symfony/var-dumper/Cloner/AbstractCloner.php index e7cb39469..b49560913 100644 --- a/app/vendor/symfony/var-dumper/Cloner/AbstractCloner.php +++ b/app/vendor/symfony/var-dumper/Cloner/AbstractCloner.php @@ -24,6 +24,9 @@ abstract class AbstractCloner implements ClonerInterface public static array $defaultCasters = [ '__PHP_Incomplete_Class' => ['Symfony\Component\VarDumper\Caster\Caster', 'castPhpIncompleteClass'], + 'AddressInfo' => ['Symfony\Component\VarDumper\Caster\AddressInfoCaster', 'castAddressInfo'], + 'Socket' => ['Symfony\Component\VarDumper\Caster\SocketCaster', 'castSocket'], + 'Symfony\Component\VarDumper\Caster\CutStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'], 'Symfony\Component\VarDumper\Caster\CutArrayStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castCutArray'], 'Symfony\Component\VarDumper\Caster\ConstStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'], @@ -54,23 +57,38 @@ abstract class AbstractCloner implements ClonerInterface 'Doctrine\Persistence\ObjectManager' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], 'DOMException' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castException'], + 'Dom\Exception' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castException'], 'DOMStringList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], 'DOMNameList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], 'DOMImplementation' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castImplementation'], + 'Dom\Implementation' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castImplementation'], 'DOMImplementationList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], 'DOMNode' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNode'], + 'Dom\Node' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNode'], 'DOMNameSpaceNode' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNameSpaceNode'], 'DOMDocument' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocument'], + 'Dom\XMLDocument' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castXMLDocument'], + 'Dom\HTMLDocument' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castHTMLDocument'], 'DOMNodeList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], + 'Dom\NodeList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], 'DOMNamedNodeMap' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], + 'Dom\DTDNamedNodeMap' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], 'DOMCharacterData' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castCharacterData'], + 'Dom\CharacterData' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castCharacterData'], 'DOMAttr' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castAttr'], + 'Dom\Attr' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castAttr'], 'DOMElement' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castElement'], + 'Dom\Element' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castElement'], 'DOMText' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castText'], + 'Dom\Text' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castText'], 'DOMDocumentType' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocumentType'], + 'Dom\DocumentType' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocumentType'], 'DOMNotation' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNotation'], + 'Dom\Notation' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNotation'], 'DOMEntity' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castEntity'], + 'Dom\Entity' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castEntity'], 'DOMProcessingInstruction' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castProcessingInstruction'], + 'Dom\ProcessingInstruction' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castProcessingInstruction'], 'DOMXPath' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castXPath'], 'XMLReader' => ['Symfony\Component\VarDumper\Caster\XmlReaderCaster', 'castXmlReader'], @@ -85,6 +103,8 @@ abstract class AbstractCloner implements ClonerInterface 'Symfony\Component\HttpClient\CurlHttpClient' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClient'], 'Symfony\Component\HttpClient\NativeHttpClient' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClient'], 'Symfony\Component\HttpClient\Response\AmpResponse' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClientResponse'], + 'Symfony\Component\HttpClient\Response\AmpResponseV4' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClientResponse'], + 'Symfony\Component\HttpClient\Response\AmpResponseV5' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClientResponse'], 'Symfony\Component\HttpClient\Response\CurlResponse' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClientResponse'], 'Symfony\Component\HttpClient\Response\NativeResponse' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClientResponse'], 'Symfony\Component\HttpFoundation\Request' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castRequest'], @@ -157,29 +177,31 @@ abstract class AbstractCloner implements ClonerInterface 'mysqli_driver' => ['Symfony\Component\VarDumper\Caster\MysqliCaster', 'castMysqliDriver'], - 'CurlHandle' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castCurl'], + 'CurlHandle' => ['Symfony\Component\VarDumper\Caster\CurlCaster', 'castCurl'], + 'Dba\Connection' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'], ':dba' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'], ':dba persistent' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'], - 'GdImage' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castGd'], - ':gd' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castGd'], + 'GdImage' => ['Symfony\Component\VarDumper\Caster\GdCaster', 'castGd'], + + 'SQLite3Result' => ['Symfony\Component\VarDumper\Caster\SqliteCaster', 'castSqlite3Result'], + + 'PgSql\Lob' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLargeObject'], + 'PgSql\Connection' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLink'], + 'PgSql\Result' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castResult'], - ':pgsql large object' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLargeObject'], - ':pgsql link' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLink'], - ':pgsql link persistent' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLink'], - ':pgsql result' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castResult'], ':process' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castProcess'], ':stream' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStream'], - 'OpenSSLCertificate' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castOpensslX509'], - ':OpenSSL X.509' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castOpensslX509'], + 'OpenSSLAsymmetricKey' => ['Symfony\Component\VarDumper\Caster\OpenSSLCaster', 'castOpensslAsymmetricKey'], + 'OpenSSLCertificateSigningRequest' => ['Symfony\Component\VarDumper\Caster\OpenSSLCaster', 'castOpensslCsr'], + 'OpenSSLCertificate' => ['Symfony\Component\VarDumper\Caster\OpenSSLCaster', 'castOpensslX509'], ':persistent stream' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStream'], ':stream-context' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStreamContext'], 'XmlParser' => ['Symfony\Component\VarDumper\Caster\XmlResourceCaster', 'castXml'], - ':xml' => ['Symfony\Component\VarDumper\Caster\XmlResourceCaster', 'castXml'], 'RdKafka' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castRdKafka'], 'RdKafka\Conf' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castConf'], diff --git a/app/vendor/symfony/var-dumper/Cloner/Data.php b/app/vendor/symfony/var-dumper/Cloner/Data.php index 71e78a6b7..21e2caa72 100644 --- a/app/vendor/symfony/var-dumper/Cloner/Data.php +++ b/app/vendor/symfony/var-dumper/Cloner/Data.php @@ -115,7 +115,7 @@ public function count(): int public function getIterator(): \Traversable { if (!\is_array($value = $this->getValue())) { - throw new \LogicException(sprintf('"%s" object holds non-iterable type "%s".', self::class, get_debug_type($value))); + throw new \LogicException(\sprintf('"%s" object holds non-iterable type "%s".', self::class, get_debug_type($value))); } yield from $value; @@ -165,7 +165,7 @@ public function __toString(): string return (string) $value; } - return sprintf('%s (count=%d)', $this->getType(), \count($value)); + return \sprintf('%s (count=%d)', $this->getType(), \count($value)); } /** @@ -370,7 +370,7 @@ private function dumpItem(DumperInterface $dumper, Cursor $cursor, array &$refs, break; default: - throw new \RuntimeException(sprintf('Unexpected Stub type: "%s".', $item->type)); + throw new \RuntimeException(\sprintf('Unexpected Stub type: "%s".', $item->type)); } } elseif ('array' === $type) { $dumper->enterHash($cursor, Cursor::HASH_INDEXED, 0, false); diff --git a/app/vendor/symfony/var-dumper/Cloner/Stub.php b/app/vendor/symfony/var-dumper/Cloner/Stub.php index 4070b981d..4455a362b 100644 --- a/app/vendor/symfony/var-dumper/Cloner/Stub.php +++ b/app/vendor/symfony/var-dumper/Cloner/Stub.php @@ -35,7 +35,7 @@ class Stub public int $type = self::TYPE_REF; public string|int|null $class = ''; - public mixed $value; + public mixed $value = null; public int $cut = 0; public int $handle = 0; public int $refCount = 0; diff --git a/app/vendor/symfony/var-dumper/Cloner/VarCloner.php b/app/vendor/symfony/var-dumper/Cloner/VarCloner.php index e168d0d3b..6a7ec2826 100644 --- a/app/vendor/symfony/var-dumper/Cloner/VarCloner.php +++ b/app/vendor/symfony/var-dumper/Cloner/VarCloner.php @@ -28,21 +28,18 @@ protected function doClone(mixed $var): array $objRefs = []; // Map of original object handles to their stub object counterpart $objects = []; // Keep a ref to objects to ensure their handle cannot be reused while cloning $resRefs = []; // Map of original resource handles to their stub object counterpart - $values = []; // Map of stub objects' ids to original values $maxItems = $this->maxItems; $maxString = $this->maxString; $minDepth = $this->minDepth; $currentDepth = 0; // Current tree depth $currentDepthFinalIndex = 0; // Final $queue index for current tree depth $minimumDepthReached = 0 === $minDepth; // Becomes true when minimum tree depth has been reached - $cookie = (object) []; // Unique object used to detect hard references $a = null; // Array cast for nested structures $stub = null; // Stub capturing the main properties of an original item value // or null if the original value is used directly $arrayStub = new Stub(); $arrayStub->type = Stub::TYPE_ARRAY; - $fromObjCast = false; for ($i = 0; $i < $len; ++$i) { // Detect when we move on to the next tree depth @@ -54,7 +51,7 @@ protected function doClone(mixed $var): array } } - $refs = $vals = $queue[$i]; + $vals = $queue[$i]; foreach ($vals as $k => $v) { // $v is the original value or a stub object in case of hard references @@ -213,31 +210,9 @@ protected function doClone(mixed $var): array } } - if ($fromObjCast) { - $fromObjCast = false; - $refs = $vals; - $vals = []; - $j = -1; - foreach ($queue[$i] as $k => $v) { - foreach ([$k => true] as $gk => $gv) { - } - if ($gk !== $k) { - $vals = (object) $vals; - $vals->{$k} = $refs[++$j]; - $vals = (array) $vals; - } else { - $vals[$k] = $refs[++$j]; - } - } - } - $queue[$i] = $vals; } - foreach ($values as $h => $v) { - $hardRefs[$h] = $v; - } - return $queue; } } diff --git a/app/vendor/symfony/var-dumper/Command/Descriptor/CliDescriptor.php b/app/vendor/symfony/var-dumper/Command/Descriptor/CliDescriptor.php index 4450fe986..24590fc85 100644 --- a/app/vendor/symfony/var-dumper/Command/Descriptor/CliDescriptor.php +++ b/app/vendor/symfony/var-dumper/Command/Descriptor/CliDescriptor.php @@ -26,12 +26,11 @@ */ class CliDescriptor implements DumpDescriptorInterface { - private CliDumper $dumper; private mixed $lastIdentifier = null; - public function __construct(CliDumper $dumper) - { - $this->dumper = $dumper; + public function __construct( + private CliDumper $dumper, + ) { } public function describe(OutputInterface $output, Data $data, array $context, int $clientId): void @@ -47,7 +46,7 @@ public function describe(OutputInterface $output, Data $data, array $context, in if (isset($context['request'])) { $request = $context['request']; $this->lastIdentifier = $request['identifier']; - $section = sprintf('%s %s', $request['method'], $request['uri']); + $section = \sprintf('%s %s', $request['method'], $request['uri']); if ($controller = $request['controller']) { $rows[] = ['controller', rtrim($this->dumper->dump($controller, true), "\n")]; } @@ -62,9 +61,9 @@ public function describe(OutputInterface $output, Data $data, array $context, in if (isset($context['source'])) { $source = $context['source']; - $sourceInfo = sprintf('%s on line %d', $source['name'], $source['line']); + $sourceInfo = \sprintf('%s on line %d', $source['name'], $source['line']); if ($fileLink = $source['file_link'] ?? null) { - $sourceInfo = sprintf('%s', $fileLink, $sourceInfo); + $sourceInfo = \sprintf('%s', $fileLink, $sourceInfo); } $rows[] = ['source', $sourceInfo]; $file = $source['file_relative'] ?? $source['file']; diff --git a/app/vendor/symfony/var-dumper/Command/Descriptor/HtmlDescriptor.php b/app/vendor/symfony/var-dumper/Command/Descriptor/HtmlDescriptor.php index 98f150a5e..ab9cd4d6d 100644 --- a/app/vendor/symfony/var-dumper/Command/Descriptor/HtmlDescriptor.php +++ b/app/vendor/symfony/var-dumper/Command/Descriptor/HtmlDescriptor.php @@ -24,12 +24,11 @@ */ class HtmlDescriptor implements DumpDescriptorInterface { - private HtmlDumper $dumper; private bool $initialized = false; - public function __construct(HtmlDumper $dumper) - { - $this->dumper = $dumper; + public function __construct( + private HtmlDumper $dumper, + ) { } public function describe(OutputInterface $output, Data $data, array $context, int $clientId): void @@ -45,22 +44,22 @@ public function describe(OutputInterface $output, Data $data, array $context, in if (isset($context['request'])) { $request = $context['request']; $controller = "{$this->dumper->dump($request['controller'], true, ['maxDepth' => 0])}"; - $title = sprintf('%s %s', $request['method'], $uri = $request['uri'], $uri); + $title = \sprintf('%s %s', $request['method'], $uri = $request['uri'], $uri); $dedupIdentifier = $request['identifier']; } elseif (isset($context['cli'])) { $title = '$ '.$context['cli']['command_line']; $dedupIdentifier = $context['cli']['identifier']; } else { - $dedupIdentifier = uniqid('', true); + $dedupIdentifier = bin2hex(random_bytes(4)); } $sourceDescription = ''; if (isset($context['source'])) { $source = $context['source']; $projectDir = $source['project_dir'] ?? null; - $sourceDescription = sprintf('%s on line %d', $source['name'], $source['line']); + $sourceDescription = \sprintf('%s on line %d', $source['name'], $source['line']); if (isset($source['file_link'])) { - $sourceDescription = sprintf('%s', $source['file_link'], $sourceDescription); + $sourceDescription = \sprintf('%s', $source['file_link'], $sourceDescription); } } @@ -105,7 +104,7 @@ private function renderTags(array $tags): string $renderedTags = ''; foreach ($tags as $key => $value) { - $renderedTags .= sprintf('
  • %s%s
  • ', $key, $value); + $renderedTags .= \sprintf('
  • %s%s
  • ', $key, $value); } return <<server = $server; + public function __construct( + private DumpServer $server, + array $descriptors = [], + ) { $this->descriptors = $descriptors + [ 'cli' => new CliDescriptor(new CliDumper()), 'html' => new HtmlDescriptor(new HtmlDumper()), @@ -57,7 +56,7 @@ public function __construct(DumpServer $server, array $descriptors = []) protected function configure(): void { $this - ->addOption('format', null, InputOption::VALUE_REQUIRED, sprintf('The output format (%s)', implode(', ', $this->getAvailableFormats())), 'cli') + ->addOption('format', null, InputOption::VALUE_REQUIRED, \sprintf('The output format (%s)', implode(', ', $this->getAvailableFormats())), 'cli') ->setHelp(<<<'EOF' %command.name% starts a dump server that collects and displays dumps in a single place for debugging you application: @@ -80,7 +79,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $format = $input->getOption('format'); if (!$descriptor = $this->descriptors[$format] ?? null) { - throw new InvalidArgumentException(sprintf('Unsupported format "%s".', $format)); + throw new InvalidArgumentException(\sprintf('Unsupported format "%s".', $format)); } $errorIo = $io->getErrorStyle(); @@ -88,7 +87,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->server->start(); - $errorIo->success(sprintf('Server listening on %s', $this->server->getHost())); + $errorIo->success(\sprintf('Server listening on %s', $this->server->getHost())); $errorIo->comment('Quit the server with CONTROL-C.'); $this->server->listen(function (Data $data, array $context, int $clientId) use ($descriptor, $io) { diff --git a/app/vendor/symfony/var-dumper/Dumper/AbstractDumper.php b/app/vendor/symfony/var-dumper/Dumper/AbstractDumper.php index ce57b36d3..593a2c69a 100644 --- a/app/vendor/symfony/var-dumper/Dumper/AbstractDumper.php +++ b/app/vendor/symfony/var-dumper/Dumper/AbstractDumper.php @@ -36,7 +36,6 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface protected $outputStream; protected string $decimalPoint = '.'; protected string $indentPad = ' '; - protected int $flags; private string $charset = ''; @@ -45,9 +44,11 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface * @param string|null $charset The default character encoding to use for non-UTF8 strings * @param int $flags A bit field of static::DUMP_* constants to fine tune dumps representation */ - public function __construct($output = null, ?string $charset = null, int $flags = 0) - { - $this->flags = $flags; + public function __construct( + $output = null, + ?string $charset = null, + protected int $flags = 0, + ) { $this->setCharset($charset ?: \ini_get('php.output_encoding') ?: \ini_get('default_charset') ?: 'UTF-8'); $this->setOutput($output ?: static::$defaultOutput); if (!$output && \is_string(static::$defaultOutput)) { @@ -90,7 +91,7 @@ public function setCharset(string $charset): string $prev = $this->charset; $charset = strtoupper($charset); - $charset = null === $charset || 'UTF-8' === $charset || 'UTF8' === $charset ? 'CP1252' : $charset; + $charset = 'UTF-8' === $charset || 'UTF8' === $charset ? 'CP1252' : $charset; $this->charset = $charset; @@ -184,17 +185,48 @@ protected function utf8Encode(?string $s): ?string return $s; } - if (!\function_exists('iconv')) { - throw new \RuntimeException('Unable to convert a non-UTF-8 string to UTF-8: required function iconv() does not exist. You should install ext-iconv or symfony/polyfill-iconv.'); + if (\function_exists('iconv')) { + if (false !== $c = @iconv($this->charset, 'UTF-8', $s)) { + return $c; + } + if ('CP1252' !== $this->charset && false !== $c = @iconv('CP1252', 'UTF-8', $s)) { + return $c; + } } - if (false !== $c = @iconv($this->charset, 'UTF-8', $s)) { - return $c; + $s .= $s; + $len = \strlen($s); + $mapCp1252 = false; + + for ($i = $len >> 1, $j = 0; $i < $len; ++$i, ++$j) { + if ($s[$i] < "\x80") { + $s[$j] = $s[$i]; + } elseif ($s[$i] < "\xC0") { + $s[$j] = "\xC2"; + $s[++$j] = $s[$i]; + if ($s[$i] < "\xA0") { + $mapCp1252 = true; + } + } else { + $s[$j] = "\xC3"; + $s[++$j] = \chr(\ord($s[$i]) - 64); + } } - if ('CP1252' !== $this->charset && false !== $c = @iconv('CP1252', 'UTF-8', $s)) { - return $c; + + $s = substr($s, 0, $j); + + if (!$mapCp1252) { + return $s; } - return iconv('CP850', 'UTF-8', $s); + return strtr($s, [ + "\xC2\x80" => '€', "\xC2\x82" => '‚', "\xC2\x83" => 'ƒ', "\xC2\x84" => '„', + "\xC2\x85" => '…', "\xC2\x86" => '†', "\xC2\x87" => '‡', "\xC2\x88" => 'ˆ', + "\xC2\x89" => '‰', "\xC2\x8A" => 'Š', "\xC2\x8B" => '‹', "\xC2\x8C" => 'Œ', + "\xC2\x8D" => 'Ž', "\xC2\x91" => '‘', "\xC2\x92" => '’', "\xC2\x93" => '“', + "\xC2\x94" => '”', "\xC2\x95" => '•', "\xC2\x96" => '–', "\xC2\x97" => '—', + "\xC2\x98" => '˜', "\xC2\x99" => '™', "\xC2\x9A" => 'š', "\xC2\x9B" => '›', + "\xC2\x9C" => 'œ', "\xC2\x9E" => 'ž', + ]); } } diff --git a/app/vendor/symfony/var-dumper/Dumper/CliDumper.php b/app/vendor/symfony/var-dumper/Dumper/CliDumper.php index 76d295dc5..c6dd88c45 100644 --- a/app/vendor/symfony/var-dumper/Dumper/CliDumper.php +++ b/app/vendor/symfony/var-dumper/Dumper/CliDumper.php @@ -33,12 +33,13 @@ class CliDumper extends AbstractDumper 'default' => '0;38;5;208', 'num' => '1;38;5;38', 'const' => '1;38;5;208', + 'virtual' => '3', 'str' => '1;38;5;113', 'note' => '38;5;38', 'ref' => '38;5;247', - 'public' => '', - 'protected' => '', - 'private' => '', + 'public' => '39', + 'protected' => '39', + 'private' => '39', 'meta' => '38;5;170', 'key' => '38;5;113', 'index' => '38;5;38', @@ -347,7 +348,10 @@ protected function dumpKey(Cursor $cursor): void if ($cursor->hashKeyIsBinary) { $key = $this->utf8Encode($key); } - $attr = ['binary' => $cursor->hashKeyIsBinary]; + $attr = [ + 'binary' => $cursor->hashKeyIsBinary, + 'virtual' => $cursor->attr['virtual'] ?? false, + ]; $bin = $cursor->hashKeyIsBinary ? 'b' : ''; $style = 'key'; switch ($cursor->hashType) { @@ -371,7 +375,7 @@ protected function dumpKey(Cursor $cursor): void // no break case Cursor::HASH_OBJECT: if (!isset($key[0]) || "\0" !== $key[0]) { - $this->line .= '+'.$bin.$this->style('public', $key).': '; + $this->line .= '+'.$bin.$this->style('public', $key, $attr).': '; } elseif (0 < strpos($key, "\0", 1)) { $key = explode("\0", substr($key, 1), 2); @@ -459,7 +463,7 @@ protected function style(string $style, string $value, array $attr = []): string $s = $startCchr; $c = $c[$i = 0]; do { - $s .= $map[$c[$i]] ?? sprintf('\x%02X', \ord($c[$i])); + $s .= $map[$c[$i]] ?? \sprintf('\x%02X', \ord($c[$i])); } while (isset($c[++$i])); return $s.$endCchr; @@ -506,6 +510,9 @@ protected function style(string $style, string $value, array $attr = []): string if ('label' === $style && '' !== $value) { $value .= ' '; } + if ($this->colors && ($attr['virtual'] ?? false)) { + $value = "\033[{$this->styles['virtual']}m".$value; + } return $value; } @@ -552,7 +559,7 @@ protected function supportsColors(): bool protected function dumpLine(int $depth, bool $endOfValue = false): void { if ($this->colors ??= $this->supportsColors()) { - $this->line = sprintf("\033[%sm%s\033[m", $this->styles['default'], $this->line); + $this->line = \sprintf("\033[%sm%s\033[m", $this->styles['default'], $this->line); } parent::dumpLine($depth); } @@ -587,10 +594,15 @@ private function hasColorSupport(mixed $stream): bool } // Follow https://no-color.org/ - if (isset($_SERVER['NO_COLOR']) || false !== getenv('NO_COLOR')) { + if ('' !== (($_SERVER['NO_COLOR'] ?? getenv('NO_COLOR'))[0] ?? '')) { return false; } + // Follow https://force-color.org/ + if ('' !== (($_SERVER['FORCE_COLOR'] ?? getenv('FORCE_COLOR'))[0] ?? '')) { + return true; + } + // Detect msysgit/mingw and assume this is a tty because detection // does not work correctly, see https://github.com/composer/composer/issues/9690 if (!@stream_isatty($stream) && !\in_array(strtoupper((string) getenv('MSYSTEM')), ['MINGW32', 'MINGW64'], true)) { @@ -632,7 +644,7 @@ private function isWindowsTrueColor(): bool || 'Hyper' === getenv('TERM_PROGRAM'); if (!$result) { - $version = sprintf( + $version = \sprintf( '%s.%s.%s', PHP_WINDOWS_VERSION_MAJOR, PHP_WINDOWS_VERSION_MINOR, diff --git a/app/vendor/symfony/var-dumper/Dumper/ContextProvider/CliContextProvider.php b/app/vendor/symfony/var-dumper/Dumper/ContextProvider/CliContextProvider.php index 38f878971..292b1a410 100644 --- a/app/vendor/symfony/var-dumper/Dumper/ContextProvider/CliContextProvider.php +++ b/app/vendor/symfony/var-dumper/Dumper/ContextProvider/CliContextProvider.php @@ -26,7 +26,7 @@ public function getContext(): ?array return [ 'command_line' => $commandLine = implode(' ', $_SERVER['argv'] ?? []), - 'identifier' => hash('crc32b', $commandLine.$_SERVER['REQUEST_TIME_FLOAT']), + 'identifier' => hash('xxh128', $commandLine.'@'.$_SERVER['REQUEST_TIME_FLOAT']), ]; } } diff --git a/app/vendor/symfony/var-dumper/Dumper/ContextProvider/RequestContextProvider.php b/app/vendor/symfony/var-dumper/Dumper/ContextProvider/RequestContextProvider.php index 69dff067b..e3ee48737 100644 --- a/app/vendor/symfony/var-dumper/Dumper/ContextProvider/RequestContextProvider.php +++ b/app/vendor/symfony/var-dumper/Dumper/ContextProvider/RequestContextProvider.php @@ -22,12 +22,11 @@ */ final class RequestContextProvider implements ContextProviderInterface { - private RequestStack $requestStack; private VarCloner $cloner; - public function __construct(RequestStack $requestStack) - { - $this->requestStack = $requestStack; + public function __construct( + private RequestStack $requestStack, + ) { $this->cloner = new VarCloner(); $this->cloner->setMaxItems(0); $this->cloner->addCasters(ReflectionCaster::UNSET_CLOSURE_FILE_INFO); @@ -45,7 +44,7 @@ public function getContext(): ?array 'uri' => $request->getUri(), 'method' => $request->getMethod(), 'controller' => $controller ? $this->cloner->cloneVar($controller) : $controller, - 'identifier' => spl_object_hash($request), + 'identifier' => hash('xxh128', spl_object_id($request).'@'.$_SERVER['REQUEST_TIME_FLOAT']), ]; } } diff --git a/app/vendor/symfony/var-dumper/Dumper/ContextProvider/SourceContextProvider.php b/app/vendor/symfony/var-dumper/Dumper/ContextProvider/SourceContextProvider.php index 9477e5312..01e730a81 100644 --- a/app/vendor/symfony/var-dumper/Dumper/ContextProvider/SourceContextProvider.php +++ b/app/vendor/symfony/var-dumper/Dumper/ContextProvider/SourceContextProvider.php @@ -25,17 +25,12 @@ */ final class SourceContextProvider implements ContextProviderInterface { - private int $limit; - private ?string $charset; - private ?string $projectDir; - private ?FileLinkFormatter $fileLinkFormatter; - - public function __construct(?string $charset = null, ?string $projectDir = null, ?FileLinkFormatter $fileLinkFormatter = null, int $limit = 9) - { - $this->charset = $charset; - $this->projectDir = $projectDir; - $this->fileLinkFormatter = $fileLinkFormatter; - $this->limit = $limit; + public function __construct( + private ?string $charset = null, + private ?string $projectDir = null, + private ?FileLinkFormatter $fileLinkFormatter = null, + private int $limit = 9, + ) { } public function getContext(): ?array diff --git a/app/vendor/symfony/var-dumper/Dumper/ContextualizedDumper.php b/app/vendor/symfony/var-dumper/Dumper/ContextualizedDumper.php index 6de34d97b..6102c4768 100644 --- a/app/vendor/symfony/var-dumper/Dumper/ContextualizedDumper.php +++ b/app/vendor/symfony/var-dumper/Dumper/ContextualizedDumper.php @@ -19,16 +19,13 @@ */ class ContextualizedDumper implements DataDumperInterface { - private DataDumperInterface $wrappedDumper; - private array $contextProviders; - /** * @param ContextProviderInterface[] $contextProviders */ - public function __construct(DataDumperInterface $wrappedDumper, array $contextProviders) - { - $this->wrappedDumper = $wrappedDumper; - $this->contextProviders = $contextProviders; + public function __construct( + private DataDumperInterface $wrappedDumper, + private array $contextProviders, + ) { } public function dump(Data $data): ?string diff --git a/app/vendor/symfony/var-dumper/Dumper/HtmlDumper.php b/app/vendor/symfony/var-dumper/Dumper/HtmlDumper.php index 74468fff1..835d6d94a 100644 --- a/app/vendor/symfony/var-dumper/Dumper/HtmlDumper.php +++ b/app/vendor/symfony/var-dumper/Dumper/HtmlDumper.php @@ -29,6 +29,7 @@ class HtmlDumper extends CliDumper 'default' => 'background-color:#18171B; color:#FF8400; line-height:1.2em; font:12px Menlo, Monaco, Consolas, monospace; word-wrap: break-word; white-space: pre-wrap; position:relative; z-index:99999; word-break: break-all', 'num' => 'font-weight:bold; color:#1299DA', 'const' => 'font-weight:bold', + 'virtual' => 'font-style:italic', 'str' => 'font-weight:bold; color:#56DB3A', 'note' => 'color:#1299DA', 'ref' => 'color:#A0A0A0', @@ -45,6 +46,7 @@ class HtmlDumper extends CliDumper 'default' => 'background:none; color:#CC7832; line-height:1.2em; font:12px Menlo, Monaco, Consolas, monospace; word-wrap: break-word; white-space: pre-wrap; position:relative; z-index:99999; word-break: break-all', 'num' => 'font-weight:bold; color:#1299DA', 'const' => 'font-weight:bold', + 'virtual' => 'font-style:italic', 'str' => 'font-weight:bold; color:#629755;', 'note' => 'color:#6897BB', 'ref' => 'color:#6E6E6E', @@ -91,7 +93,7 @@ public function setStyles(array $styles): void public function setTheme(string $themeName): void { if (!isset(static::$themes[$themeName])) { - throw new \InvalidArgumentException(sprintf('Theme "%s" does not exist in class "%s".', $themeName, static::class)); + throw new \InvalidArgumentException(\sprintf('Theme "%s" does not exist in class "%s".', $themeName, static::class)); } $this->setStyles(static::$themes[$themeName]); @@ -647,7 +649,7 @@ function showCurrent(state) height: 0; clear: both; } -pre.sf-dump span { +pre.sf-dump .sf-dump-ellipsization { display: inline-flex; } pre.sf-dump a { @@ -665,16 +667,12 @@ function showCurrent(state) background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAAAAAA6mKC9AAAAHUlEQVQY02O8zAABilCaiQEN0EeA8QuUcX9g3QEAAjcC5piyhyEAAAAASUVORK5CYII=) #D3D3D3; } pre.sf-dump .sf-dump-ellipsis { - display: inline-block; - overflow: visible; text-overflow: ellipsis; - max-width: 5em; white-space: nowrap; overflow: hidden; - vertical-align: top; } -pre.sf-dump .sf-dump-ellipsis+.sf-dump-ellipsis { - max-width: none; +pre.sf-dump .sf-dump-ellipsis-tail { + flex-shrink: 0; } pre.sf-dump code { display:inline; @@ -777,7 +775,7 @@ public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut): vo $this->line .= $cursor->depth >= $this->displayOptions['maxDepth'] ? ' ' : ' '; $this->endValue($cursor); $this->line .= $this->indentPad; - $this->line .= sprintf('', $cursor->attr['content-type'], base64_encode($cursor->attr['img-data'])); + $this->line .= \sprintf('', $cursor->attr['content-type'], base64_encode($cursor->attr['img-data'])); $this->endValue($cursor); } else { parent::dumpString($cursor, $str, $bin, $cut); @@ -805,7 +803,7 @@ public function enterHash(Cursor $cursor, int $type, string|int|null $class, boo $r = Cursor::HASH_OBJECT !== $type ? 1 - (Cursor::HASH_RESOURCE !== $type) : 2; $r .= $r && 0 < $cursor->softRefHandle ? $cursor->softRefHandle : $cursor->refIndex; - $this->line .= sprintf(' id=%s-ref%s', $this->dumpId, $r); + $this->line .= \sprintf(' id=%s-ref%s', $this->dumpId, $r); } $this->line .= $eol; $this->dumpLine($cursor->depth); @@ -831,73 +829,82 @@ protected function style(string $style, string $value, array $attr = []): string if ('ref' === $style) { if (empty($attr['count'])) { - return sprintf('%s', $v); + return \sprintf('%s', $v); } $r = ('#' !== $v[0] ? 1 - ('@' !== $v[0]) : 2).substr($value, 1); - return sprintf('%s', $this->dumpId, $r, 1 + $attr['count'], $v); + return \sprintf('%s', $this->dumpId, $r, 1 + $attr['count'], $v); } + $dumpClasses = ['sf-dump-'.$style]; + $dumpTitle = ''; + if ('const' === $style && isset($attr['value'])) { - $style .= sprintf(' title="%s"', esc(\is_scalar($attr['value']) ? $attr['value'] : json_encode($attr['value']))); + $dumpTitle = esc(\is_scalar($attr['value']) ? $attr['value'] : json_encode($attr['value'])); } elseif ('public' === $style) { - $style .= sprintf(' title="%s"', empty($attr['dynamic']) ? 'Public property' : 'Runtime added dynamic property'); + $dumpTitle = empty($attr['dynamic']) ? 'Public property' : 'Runtime added dynamic property'; } elseif ('str' === $style && 1 < $attr['length']) { - $style .= sprintf(' title="%d%s characters"', $attr['length'], $attr['binary'] ? ' binary or non-UTF-8' : ''); + $dumpTitle = \sprintf('%d%s characters', $attr['length'], $attr['binary'] ? ' binary or non-UTF-8' : ''); } elseif ('note' === $style && 0 < ($attr['depth'] ?? 0) && false !== $c = strrpos($value, '\\')) { - $style .= ' title=""'; $attr += [ 'ellipsis' => \strlen($value) - $c, 'ellipsis-type' => 'note', 'ellipsis-tail' => 1, ]; } elseif ('protected' === $style) { - $style .= ' title="Protected property"'; + $dumpTitle = 'Protected property'; } elseif ('meta' === $style && isset($attr['title'])) { - $style .= sprintf(' title="%s"', esc($this->utf8Encode($attr['title']))); + $dumpTitle = esc($this->utf8Encode($attr['title'])); } elseif ('private' === $style) { - $style .= sprintf(' title="Private property defined in class: `%s`"', esc($this->utf8Encode($attr['class']))); + $dumpTitle = \sprintf('Private property defined in class: `%s`', esc($this->utf8Encode($attr['class']))); } if (isset($attr['ellipsis'])) { - $class = 'sf-dump-ellipsis'; + $dumpClasses[] = 'sf-dump-ellipsization'; + $ellipsisClass = 'sf-dump-ellipsis'; if (isset($attr['ellipsis-type'])) { - $class = sprintf('"%s sf-dump-ellipsis-%s"', $class, $attr['ellipsis-type']); + $ellipsisClass .= ' sf-dump-ellipsis-'.$attr['ellipsis-type']; } $label = esc(substr($value, -$attr['ellipsis'])); - $style = str_replace(' title="', " title=\"$v\n", $style); - $v = sprintf('%s', $class, substr($v, 0, -\strlen($label))); + $dumpTitle = $v."\n".$dumpTitle; + $v = \sprintf('%s', $ellipsisClass, substr($v, 0, -\strlen($label))); if (!empty($attr['ellipsis-tail'])) { $tail = \strlen(esc(substr($value, -$attr['ellipsis'], $attr['ellipsis-tail']))); - $v .= sprintf('%s%s', $class, substr($label, 0, $tail), substr($label, $tail)); + $v .= \sprintf('%s%s', $ellipsisClass, substr($label, 0, $tail), substr($label, $tail)); } else { - $v .= $label; + $v .= \sprintf('%s', $label); } } $map = static::$controlCharsMap; - $v = "".preg_replace_callback(static::$controlCharsRx, function ($c) use ($map) { - $s = $b = '%s', + 1 === \count($dumpClasses) ? '' : '"', + implode(' ', $dumpClasses), + $dumpTitle ? ' title="'.$dumpTitle.'"' : '', + preg_replace_callback(static::$controlCharsRx, function ($c) use ($map) { + $s = $b = ''; - }, $v).''; + return $s.''; + }, $v) + ); if (!($attr['binary'] ?? false)) { $v = preg_replace_callback(static::$unicodeCharsRx, function ($c) { @@ -913,14 +920,17 @@ protected function style(string $style, string $value, array $attr = []): string $v .= '^'; } $target = isset($attr['file']) ? '' : ' target="_blank"'; - $v = sprintf('%s', esc($this->utf8Encode($attr['href'])), $target, $v); + $v = \sprintf('%s', esc($this->utf8Encode($attr['href'])), $target, $v); } if (isset($attr['lang'])) { - $v = sprintf('%s', esc($attr['lang']), $v); + $v = \sprintf('%s', esc($attr['lang']), $v); } if ('label' === $style) { $v .= ' '; } + if ($attr['virtual'] ?? false) { + $v = ''.$v.''; + } return $v; } @@ -928,7 +938,7 @@ protected function style(string $style, string $value, array $attr = []): string protected function dumpLine(int $depth, bool $endOfValue = false): void { if (-1 === $this->lastDepth) { - $this->line = sprintf($this->dumpPrefix, $this->dumpId, $this->indentPad).$this->line; + $this->line = \sprintf($this->dumpPrefix, $this->dumpId, $this->indentPad).$this->line; } if ($this->headerIsDumped !== ($this->outputStream ?? $this->lineDumper)) { $this->line = $this->getDumpHeader().$this->line; @@ -940,7 +950,7 @@ protected function dumpLine(int $depth, bool $endOfValue = false): void $args[] = json_encode($this->extraDisplayOptions, \JSON_FORCE_OBJECT); } // Replace is for BC - $this->line .= sprintf(str_replace('"%s"', '%s', $this->dumpSuffix), implode(', ', $args)); + $this->line .= \sprintf(str_replace('"%s"', '%s', $this->dumpSuffix), implode(', ', $args)); } $this->lastDepth = $depth; diff --git a/app/vendor/symfony/var-dumper/Dumper/ServerDumper.php b/app/vendor/symfony/var-dumper/Dumper/ServerDumper.php index 0d3552607..4602bcf1d 100644 --- a/app/vendor/symfony/var-dumper/Dumper/ServerDumper.php +++ b/app/vendor/symfony/var-dumper/Dumper/ServerDumper.php @@ -23,17 +23,18 @@ class ServerDumper implements DataDumperInterface { private Connection $connection; - private ?DataDumperInterface $wrappedDumper; /** * @param string $host The server host * @param DataDumperInterface|null $wrappedDumper A wrapped instance used whenever we failed contacting the server * @param ContextProviderInterface[] $contextProviders Context providers indexed by context name */ - public function __construct(string $host, ?DataDumperInterface $wrappedDumper = null, array $contextProviders = []) - { + public function __construct( + string $host, + private ?DataDumperInterface $wrappedDumper = null, + array $contextProviders = [], + ) { $this->connection = new Connection($host, $contextProviders); - $this->wrappedDumper = $wrappedDumper; } public function getContextProviders(): array diff --git a/app/vendor/symfony/var-dumper/Resources/functions/dump.php b/app/vendor/symfony/var-dumper/Resources/functions/dump.php index f2ff74c0c..c99155145 100644 --- a/app/vendor/symfony/var-dumper/Resources/functions/dump.php +++ b/app/vendor/symfony/var-dumper/Resources/functions/dump.php @@ -45,10 +45,16 @@ function dump(mixed ...$vars): mixed if (!function_exists('dd')) { function dd(mixed ...$vars): never { - if (!\in_array(\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true) && !headers_sent()) { + if (!in_array(\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true) && !headers_sent()) { header('HTTP/1.1 500 Internal Server Error'); } + if (!$vars) { + VarDumper::dump(new ScalarStub('🐛')); + + exit(1); + } + if (array_key_exists(0, $vars) && 1 === count($vars)) { VarDumper::dump($vars[0]); } else { diff --git a/app/vendor/symfony/var-dumper/Server/Connection.php b/app/vendor/symfony/var-dumper/Server/Connection.php index 4383278c9..2f1cc1b44 100644 --- a/app/vendor/symfony/var-dumper/Server/Connection.php +++ b/app/vendor/symfony/var-dumper/Server/Connection.php @@ -22,7 +22,6 @@ class Connection { private string $host; - private array $contextProviders; /** * @var resource|null @@ -33,14 +32,15 @@ class Connection * @param string $host The server host * @param ContextProviderInterface[] $contextProviders Context providers indexed by context name */ - public function __construct(string $host, array $contextProviders = []) - { + public function __construct( + string $host, + private array $contextProviders = [], + ) { if (!str_contains($host, '://')) { $host = 'tcp://'.$host; } $this->host = $host; - $this->contextProviders = $contextProviders; } public function getContextProviders(): array diff --git a/app/vendor/symfony/var-dumper/Server/DumpServer.php b/app/vendor/symfony/var-dumper/Server/DumpServer.php index a9228a2ef..149c3c4ee 100644 --- a/app/vendor/symfony/var-dumper/Server/DumpServer.php +++ b/app/vendor/symfony/var-dumper/Server/DumpServer.php @@ -25,27 +25,27 @@ class DumpServer { private string $host; - private ?LoggerInterface $logger; /** * @var resource|null */ private $socket; - public function __construct(string $host, ?LoggerInterface $logger = null) - { + public function __construct( + string $host, + private ?LoggerInterface $logger = null, + ) { if (!str_contains($host, '://')) { $host = 'tcp://'.$host; } $this->host = $host; - $this->logger = $logger; } public function start(): void { if (!$this->socket = stream_socket_server($this->host, $errno, $errstr)) { - throw new \RuntimeException(sprintf('Server start failed on "%s": ', $this->host).$errstr.' '.$errno); + throw new \RuntimeException(\sprintf('Server start failed on "%s": ', $this->host).$errstr.' '.$errno); } } diff --git a/app/vendor/symfony/var-dumper/Test/VarDumperTestTrait.php b/app/vendor/symfony/var-dumper/Test/VarDumperTestTrait.php index 4475efd12..e29121a30 100644 --- a/app/vendor/symfony/var-dumper/Test/VarDumperTestTrait.php +++ b/app/vendor/symfony/var-dumper/Test/VarDumperTestTrait.php @@ -27,6 +27,9 @@ trait VarDumperTestTrait 'flags' => null, ]; + /** + * @param array $casters + */ protected function setUpVarDumper(array $casters, ?int $flags = null): void { $this->varDumperConfig['casters'] = $casters; diff --git a/app/vendor/symfony/var-dumper/composer.json b/app/vendor/symfony/var-dumper/composer.json index cbc671760..d11e55924 100644 --- a/app/vendor/symfony/var-dumper/composer.json +++ b/app/vendor/symfony/var-dumper/composer.json @@ -17,15 +17,15 @@ ], "require": { "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { - "ext-iconv": "*", "symfony/console": "^6.4|^7.0", "symfony/http-kernel": "^6.4|^7.0", "symfony/process": "^6.4|^7.0", "symfony/uid": "^6.4|^7.0", - "twig/twig": "^3.0.4" + "twig/twig": "^3.12" }, "conflict": { "symfony/console": "<6.4" diff --git a/app/vendor/twig/markdown-extra/ErusevMarkdown.php b/app/vendor/twig/markdown-extra/ErusevMarkdown.php index f4f7e1c48..47b030893 100644 --- a/app/vendor/twig/markdown-extra/ErusevMarkdown.php +++ b/app/vendor/twig/markdown-extra/ErusevMarkdown.php @@ -17,7 +17,7 @@ class ErusevMarkdown implements MarkdownInterface { private $converter; - public function __construct(Parsedown $converter = null) + public function __construct(?Parsedown $converter = null) { $this->converter = $converter ?: new Parsedown(); } diff --git a/app/vendor/twig/markdown-extra/LeagueMarkdown.php b/app/vendor/twig/markdown-extra/LeagueMarkdown.php index 2390901c0..be2667702 100644 --- a/app/vendor/twig/markdown-extra/LeagueMarkdown.php +++ b/app/vendor/twig/markdown-extra/LeagueMarkdown.php @@ -18,7 +18,7 @@ class LeagueMarkdown implements MarkdownInterface private $converter; private $legacySupport; - public function __construct(CommonMarkConverter $converter = null) + public function __construct(?CommonMarkConverter $converter = null) { $this->converter = $converter ?: new CommonMarkConverter(); $this->legacySupport = !method_exists($this->converter, 'convert'); diff --git a/app/vendor/twig/markdown-extra/MarkdownExtension.php b/app/vendor/twig/markdown-extra/MarkdownExtension.php index 6c4296bbf..7bc737a29 100644 --- a/app/vendor/twig/markdown-extra/MarkdownExtension.php +++ b/app/vendor/twig/markdown-extra/MarkdownExtension.php @@ -17,32 +17,35 @@ final class MarkdownExtension extends AbstractExtension { - public function getFilters() + public function getFilters(): array { return [ new TwigFilter('markdown_to_html', ['Twig\\Extra\\Markdown\\MarkdownRuntime', 'convert'], ['is_safe' => ['all']]), - new TwigFilter('html_to_markdown', 'Twig\\Extra\\Markdown\\twig_html_to_markdown', ['is_safe' => ['all']]), + new TwigFilter('html_to_markdown', [self::class, 'htmlToMarkdown'], ['is_safe' => ['all']]), ]; } -} -function twig_html_to_markdown(string $body, array $options = []): string -{ - static $converters; + /** + * @internal + */ + public static function htmlToMarkdown(string $body, array $options = []): string + { + static $converters; - if (!class_exists(HtmlConverter::class)) { - throw new \LogicException('You cannot use the "html_to_markdown" filter as league/html-to-markdown is not installed; try running "composer require league/html-to-markdown".'); - } + if (!class_exists(HtmlConverter::class)) { + throw new \LogicException('You cannot use the "html_to_markdown" filter as league/html-to-markdown is not installed; try running "composer require league/html-to-markdown".'); + } - $options += [ - 'hard_break' => true, - 'strip_tags' => true, - 'remove_nodes' => 'head style', - ]; + $options += [ + 'hard_break' => true, + 'strip_tags' => true, + 'remove_nodes' => 'head style', + ]; - if (!isset($converters[$key = serialize($options)])) { - $converters[$key] = new HtmlConverter($options); - } + if (!isset($converters[$key = serialize($options)])) { + $converters[$key] = new HtmlConverter($options); + } - return $converters[$key]->convert($body); + return $converters[$key]->convert($body); + } } diff --git a/app/vendor/twig/markdown-extra/MichelfMarkdown.php b/app/vendor/twig/markdown-extra/MichelfMarkdown.php index 2660a7f04..0acc3a3a4 100644 --- a/app/vendor/twig/markdown-extra/MichelfMarkdown.php +++ b/app/vendor/twig/markdown-extra/MichelfMarkdown.php @@ -17,7 +17,7 @@ class MichelfMarkdown implements MarkdownInterface { private $converter; - public function __construct(MarkdownExtra $converter = null) + public function __construct(?MarkdownExtra $converter = null) { if (null === $converter) { $converter = new MarkdownExtra(); diff --git a/app/vendor/twig/markdown-extra/Resources/functions.php b/app/vendor/twig/markdown-extra/Resources/functions.php new file mode 100644 index 000000000..cf498364d --- /dev/null +++ b/app/vendor/twig/markdown-extra/Resources/functions.php @@ -0,0 +1,24 @@ +=7.2.5", - "twig/twig": "^3.0" + "php": ">=8.1.0", + "symfony/deprecation-contracts": "^2.5|^3", + "twig/twig": "^3.13|^4.0" }, "require-dev": { "symfony/phpunit-bridge": "^6.4|^7.0", - "erusev/parsedown": "^1.7", + "erusev/parsedown": "dev-master as 1.x-dev", "league/commonmark": "^1.0|^2.0", "league/html-to-markdown": "^4.8|^5.0", "michelf/php-markdown": "^1.8|^2.0" }, "autoload": { + "files": [ "Resources/functions.php" ], "psr-4" : { "Twig\\Extra\\Markdown\\" : "" }, "exclude-from-classmap": [ "/Tests/" diff --git a/app/vendor/twig/twig/CHANGELOG b/app/vendor/twig/twig/CHANGELOG index 5d7ea9527..cf202b044 100644 --- a/app/vendor/twig/twig/CHANGELOG +++ b/app/vendor/twig/twig/CHANGELOG @@ -1,3 +1,22 @@ +# 3.21.1 (2025-05-03) + + * Fix ExtensionSet usage of BinaryOperatorExpressionParser + +# 3.21.0 (2025-05-02) + + * Fix wrong array index + * Deprecate `Template::loadTemplate()` + * Fix testing and expression when it evaluates to an instance of `Markup` + * Add `ReturnPrimitiveTypeInterface` (and sub-interfaces for number, boolean, string, and array) + * Add `SupportDefinedTestInterface` for expression nodes supporting the `defined` test + * Deprecate using the `|` operator in an expression with `+` or `-` without using parentheses to clarify precedence + * Deprecate operator precedence outside of the [0, 512] range + * Introduce expression parser classes to describe operators and operands provided by extensions + instead of arrays (it comes with many deprecations that are documented in + the ``deprecated`` documentation chapter) + * Deprecate the `Twig\ExpressionParser`, and `Twig\OperatorPrecedenceChange` classes + * Add attributes `AsTwigFilter`, `AsTwigFunction`, and `AsTwigTest` to ease extension development + # 3.20.0 (2025-02-13) * Fix support for ignoring syntax errors in an undefined handler in guard diff --git a/app/vendor/twig/twig/src/Attribute/AsTwigFilter.php b/app/vendor/twig/twig/src/Attribute/AsTwigFilter.php new file mode 100644 index 000000000..395531d86 --- /dev/null +++ b/app/vendor/twig/twig/src/Attribute/AsTwigFilter.php @@ -0,0 +1,56 @@ +compile($this); if ($this->didUseEcho) { - trigger_deprecation('twig/twig', '3.9', 'Using "%s" is deprecated, use "yield" instead in "%s", then flag the class with #[\Twig\Attribute\YieldReady].', $this->didUseEcho, \get_class($node)); + trigger_deprecation('twig/twig', '3.9', 'Using "%s" is deprecated, use "yield" instead in "%s", then flag the class with #[\Twig\Attribute\YieldReady].', $this->didUseEcho, $node::class); } return $this; @@ -99,7 +99,7 @@ public function subcompile(Node $node, bool $raw = true) $node->compile($this); if ($this->didUseEcho) { - trigger_deprecation('twig/twig', '3.9', 'Using "%s" is deprecated, use "yield" instead in "%s", then flag the class with #[\Twig\Attribute\YieldReady].', $this->didUseEcho, \get_class($node)); + trigger_deprecation('twig/twig', '3.9', 'Using "%s" is deprecated, use "yield" instead in "%s", then flag the class with #[\Twig\Attribute\YieldReady].', $this->didUseEcho, $node::class); } return $this; diff --git a/app/vendor/twig/twig/src/Environment.php b/app/vendor/twig/twig/src/Environment.php index 17765cd2b..ff3f0c588 100644 --- a/app/vendor/twig/twig/src/Environment.php +++ b/app/vendor/twig/twig/src/Environment.php @@ -19,6 +19,7 @@ use Twig\Error\LoaderError; use Twig\Error\RuntimeError; use Twig\Error\SyntaxError; +use Twig\ExpressionParser\ExpressionParsers; use Twig\Extension\CoreExtension; use Twig\Extension\EscaperExtension; use Twig\Extension\ExtensionInterface; @@ -27,8 +28,6 @@ use Twig\Loader\ArrayLoader; use Twig\Loader\ChainLoader; use Twig\Loader\LoaderInterface; -use Twig\Node\Expression\Binary\AbstractBinary; -use Twig\Node\Expression\Unary\AbstractUnary; use Twig\Node\ModuleNode; use Twig\Node\Node; use Twig\NodeVisitor\NodeVisitorInterface; @@ -44,11 +43,11 @@ */ class Environment { - public const VERSION = '3.20.0'; - public const VERSION_ID = 32000; + public const VERSION = '3.21.1'; + public const VERSION_ID = 32101; public const MAJOR_VERSION = 3; - public const MINOR_VERSION = 20; - public const RELEASE_VERSION = 0; + public const MINOR_VERSION = 21; + public const RELEASE_VERSION = 1; public const EXTRA_VERSION = ''; private $charset; @@ -925,22 +924,10 @@ public function mergeGlobals(array $context): array /** * @internal - * - * @return array}> - */ - public function getUnaryOperators(): array - { - return $this->extensionSet->getUnaryOperators(); - } - - /** - * @internal - * - * @return array, associativity: ExpressionParser::OPERATOR_*}> */ - public function getBinaryOperators(): array + public function getExpressionParsers(): ExpressionParsers { - return $this->extensionSet->getBinaryOperators(); + return $this->extensionSet->getExpressionParsers(); } private function updateOptionsHash(): void diff --git a/app/vendor/twig/twig/src/Error/Error.php b/app/vendor/twig/twig/src/Error/Error.php index 61c309fa1..015085e32 100644 --- a/app/vendor/twig/twig/src/Error/Error.php +++ b/app/vendor/twig/twig/src/Error/Error.php @@ -29,20 +29,17 @@ * Whenever possible, you must set these information (original template name * and line number) yourself by passing them to the constructor. If some or all * these information are not available from where you throw the exception, then - * this class will guess them automatically (when the line number is set to -1 - * and/or the name is set to null). As this is a costly operation, this - * can be disabled by passing false for both the name and the line number - * when creating a new instance of this class. + * this class will guess them automatically. * * @author Fabien Potencier */ class Error extends \Exception { private $lineno; - private $name; private $rawMessage; - private $sourcePath; - private $sourceCode; + private ?Source $source; + private string $phpFile; + private int $phpLine; /** * Constructor. @@ -57,16 +54,10 @@ public function __construct(string $message, int $lineno = -1, ?Source $source = { parent::__construct('', 0, $previous); - if (null === $source) { - $name = null; - } else { - $name = $source->getName(); - $this->sourceCode = $source->getCode(); - $this->sourcePath = $source->getPath(); - } - + $this->phpFile = $this->getFile(); + $this->phpLine = $this->getLine(); $this->lineno = $lineno; - $this->name = $name; + $this->source = $source; $this->rawMessage = $message; $this->updateRepr(); } @@ -84,30 +75,26 @@ public function getTemplateLine(): int public function setTemplateLine(int $lineno): void { $this->lineno = $lineno; - $this->updateRepr(); } public function getSourceContext(): ?Source { - return $this->name ? new Source($this->sourceCode, $this->name, $this->sourcePath) : null; + return $this->source; } public function setSourceContext(?Source $source = null): void { - if (null === $source) { - $this->sourceCode = $this->name = $this->sourcePath = null; - } else { - $this->sourceCode = $source->getCode(); - $this->name = $source->getName(); - $this->sourcePath = $source->getPath(); - } - + $this->source = $source; $this->updateRepr(); } public function guess(): void { + if ($this->lineno > -1) { + return; + } + $this->guessTemplateInfo(); $this->updateRepr(); } @@ -120,80 +107,45 @@ public function appendMessage($rawMessage): void private function updateRepr(): void { - $this->message = $this->rawMessage; - - if ($this->sourcePath && $this->lineno > 0) { - $this->file = $this->sourcePath; - $this->line = $this->lineno; - - return; + if ($this->source && $this->source->getPath()) { + // we only update the file and the line together + $this->file = $this->source->getPath(); + if ($this->lineno > 0) { + $this->line = $this->lineno; + } else { + $this->line = -1; + } } - $dot = false; - if (str_ends_with($this->message, '.')) { + $this->message = $this->rawMessage; + $last = substr($this->message, -1); + if ($punctuation = '.' === $last || '?' === $last ? $last : '') { $this->message = substr($this->message, 0, -1); - $dot = true; } - - $questionMark = false; - if (str_ends_with($this->message, '?')) { - $this->message = substr($this->message, 0, -1); - $questionMark = true; + if ($this->source && $this->source->getName()) { + $this->message .= \sprintf(' in "%s"', $this->source->getName()); } - - if ($this->name) { - if (\is_string($this->name) || $this->name instanceof \Stringable) { - $name = \sprintf('"%s"', $this->name); - } else { - $name = json_encode($this->name); - } - $this->message .= \sprintf(' in %s', $name); - } - - if ($this->lineno && $this->lineno >= 0) { + if ($this->lineno > 0) { $this->message .= \sprintf(' at line %d', $this->lineno); } - - if ($dot) { - $this->message .= '.'; - } - - if ($questionMark) { - $this->message .= '?'; + if ($punctuation) { + $this->message .= $punctuation; } } private function guessTemplateInfo(): void { - $template = null; - $templateClass = null; + // $this->source is never null here (see guess() usage in Template) + $this->lineno = 0; + $template = null; $backtrace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS | \DEBUG_BACKTRACE_PROVIDE_OBJECT); foreach ($backtrace as $trace) { - if (isset($trace['object']) && $trace['object'] instanceof Template) { - $currentClass = \get_class($trace['object']); - $isEmbedContainer = null === $templateClass ? false : str_starts_with($templateClass, $currentClass); - if (null === $this->name || ($this->name == $trace['object']->getTemplateName() && !$isEmbedContainer)) { - $template = $trace['object']; - $templateClass = \get_class($trace['object']); - } - } - } + if (isset($trace['object']) && $trace['object'] instanceof Template && $this->source->getName() === $trace['object']->getTemplateName()) { + $template = $trace['object']; - // update template name - if (null !== $template && null === $this->name) { - $this->name = $template->getTemplateName(); - } - - // update template path if any - if (null !== $template && null === $this->sourcePath) { - $src = $template->getSourceContext(); - $this->sourceCode = $src->getCode(); - $this->sourcePath = $src->getPath(); - } - - if (null === $template || $this->lineno > -1) { - return; + break; + } } $r = new \ReflectionObject($template); @@ -206,8 +158,7 @@ private function guessTemplateInfo(): void while ($e = array_pop($exceptions)) { $traces = $e->getTrace(); - array_unshift($traces, ['file' => $e->getFile(), 'line' => $e->getLine()]); - + array_unshift($traces, ['file' => $e instanceof Error ? $e->phpFile : $e->getFile(), 'line' => $e instanceof Error ? $e->phpLine : $e->getLine()]); while ($trace = array_shift($traces)) { if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) { continue; diff --git a/app/vendor/twig/twig/src/ExpressionParser.php b/app/vendor/twig/twig/src/ExpressionParser.php index 233139ee4..727cf7eba 100644 --- a/app/vendor/twig/twig/src/ExpressionParser.php +++ b/app/vendor/twig/twig/src/ExpressionParser.php @@ -12,28 +12,17 @@ namespace Twig; -use Twig\Attribute\FirstClassTwigCallableReady; use Twig\Error\SyntaxError; -use Twig\Node\EmptyNode; -use Twig\Node\Expression\AbstractExpression; +use Twig\ExpressionParser\Infix\DotExpressionParser; +use Twig\ExpressionParser\Infix\FilterExpressionParser; +use Twig\ExpressionParser\Infix\SquareBracketExpressionParser; use Twig\Node\Expression\ArrayExpression; -use Twig\Node\Expression\ArrowFunctionExpression; -use Twig\Node\Expression\Binary\AbstractBinary; -use Twig\Node\Expression\Binary\ConcatBinary; use Twig\Node\Expression\ConstantExpression; -use Twig\Node\Expression\GetAttrExpression; -use Twig\Node\Expression\MacroReferenceExpression; -use Twig\Node\Expression\Ternary\ConditionalTernary; -use Twig\Node\Expression\TestExpression; -use Twig\Node\Expression\Unary\AbstractUnary; use Twig\Node\Expression\Unary\NegUnary; -use Twig\Node\Expression\Unary\NotUnary; use Twig\Node\Expression\Unary\PosUnary; use Twig\Node\Expression\Unary\SpreadUnary; use Twig\Node\Expression\Variable\AssignContextVariable; use Twig\Node\Expression\Variable\ContextVariable; -use Twig\Node\Expression\Variable\LocalVariable; -use Twig\Node\Expression\Variable\TemplateVariable; use Twig\Node\Node; use Twig\Node\Nodes; @@ -46,47 +35,25 @@ * @see https://en.wikipedia.org/wiki/Operator-precedence_parser * * @author Fabien Potencier + * + * @deprecated since Twig 3.21 */ class ExpressionParser { + /** + * @deprecated since Twig 3.21 + */ public const OPERATOR_LEFT = 1; + /** + * @deprecated since Twig 3.21 + */ public const OPERATOR_RIGHT = 2; - /** @var array}> */ - private $unaryOperators; - /** @var array, associativity: self::OPERATOR_*}> */ - private $binaryOperators; - private $readyNodes = []; - private array $precedenceChanges = []; - private bool $deprecationCheck = true; - public function __construct( private Parser $parser, private Environment $env, ) { - $this->unaryOperators = $env->getUnaryOperators(); - $this->binaryOperators = $env->getBinaryOperators(); - - $ops = []; - foreach ($this->unaryOperators as $n => $c) { - $ops[] = $c + ['name' => $n, 'type' => 'unary']; - } - foreach ($this->binaryOperators as $n => $c) { - $ops[] = $c + ['name' => $n, 'type' => 'binary']; - } - foreach ($ops as $config) { - if (!isset($config['precedence_change'])) { - continue; - } - $name = $config['type'].'_'.$config['name']; - $min = min($config['precedence_change']->getNewPrecedence(), $config['precedence']); - $max = max($config['precedence_change']->getNewPrecedence(), $config['precedence']); - foreach ($ops as $c) { - if ($c['precedence'] > $min && $c['precedence'] < $max) { - $this->precedenceChanges[$c['type'].'_'.$c['name']][] = $name; - } - } - } + trigger_deprecation('twig/twig', '3.21', 'Class "%s" is deprecated, use "Parser::parseExpression()" instead.', __CLASS__); } public function parseExpression($precedence = 0) @@ -95,416 +62,78 @@ public function parseExpression($precedence = 0) trigger_deprecation('twig/twig', '3.15', 'Passing a second argument ($allowArrow) to "%s()" is deprecated.', __METHOD__); } - if ($arrow = $this->parseArrow()) { - return $arrow; - } - - $expr = $this->getPrimary(); - $token = $this->parser->getCurrentToken(); - while ($this->isBinary($token) && $this->binaryOperators[$token->getValue()]['precedence'] >= $precedence) { - $op = $this->binaryOperators[$token->getValue()]; - $this->parser->getStream()->next(); - - if ('is not' === $token->getValue()) { - $expr = $this->parseNotTestExpression($expr); - } elseif ('is' === $token->getValue()) { - $expr = $this->parseTestExpression($expr); - } elseif (isset($op['callable'])) { - $expr = $op['callable']($this->parser, $expr); - } else { - $previous = $this->setDeprecationCheck(true); - try { - $expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']); - } finally { - $this->setDeprecationCheck($previous); - } - $class = $op['class']; - $expr = new $class($expr, $expr1, $token->getLine()); - } - - $expr->setAttribute('operator', 'binary_'.$token->getValue()); + trigger_deprecation('twig/twig', '3.21', 'The "%s()" method is deprecated, use "Parser::parseExpression()" instead.', __METHOD__); - $this->triggerPrecedenceDeprecations($expr); - - $token = $this->parser->getCurrentToken(); - } - - if (0 === $precedence) { - return $this->parseConditionalExpression($expr); - } - - return $expr; - } - - private function triggerPrecedenceDeprecations(AbstractExpression $expr): void - { - // Check that the all nodes that are between the 2 precedences have explicit parentheses - if (!$expr->hasAttribute('operator') || !isset($this->precedenceChanges[$expr->getAttribute('operator')])) { - return; - } - - if (str_starts_with($unaryOp = $expr->getAttribute('operator'), 'unary')) { - if ($expr->hasExplicitParentheses()) { - return; - } - $target = explode('_', $unaryOp)[1]; - /** @var AbstractExpression $node */ - $node = $expr->getNode('node'); - foreach ($this->precedenceChanges as $operatorName => $changes) { - if (!\in_array($unaryOp, $changes)) { - continue; - } - if ($node->hasAttribute('operator') && $operatorName === $node->getAttribute('operator')) { - $change = $this->unaryOperators[$target]['precedence_change']; - trigger_deprecation($change->getPackage(), $change->getVersion(), \sprintf('Add explicit parentheses around the "%s" unary operator to avoid behavior change in the next major version as its precedence will change in "%s" at line %d.', $target, $this->parser->getStream()->getSourceContext()->getName(), $node->getTemplateLine())); - } - } - } else { - foreach ($this->precedenceChanges[$expr->getAttribute('operator')] as $operatorName) { - foreach ($expr as $node) { - /** @var AbstractExpression $node */ - if ($node->hasAttribute('operator') && $operatorName === $node->getAttribute('operator') && !$node->hasExplicitParentheses()) { - $op = explode('_', $operatorName)[1]; - $change = $this->binaryOperators[$op]['precedence_change']; - trigger_deprecation($change->getPackage(), $change->getVersion(), \sprintf('Add explicit parentheses around the "%s" binary operator to avoid behavior change in the next major version as its precedence will change in "%s" at line %d.', $op, $this->parser->getStream()->getSourceContext()->getName(), $node->getTemplateLine())); - } - } - } - } + return $this->parser->parseExpression((int) $precedence); } /** - * @return ArrowFunctionExpression|null + * @deprecated since Twig 3.21 */ - private function parseArrow() - { - $stream = $this->parser->getStream(); - - // short array syntax (one argument, no parentheses)? - if ($stream->look(1)->test(Token::ARROW_TYPE)) { - $line = $stream->getCurrent()->getLine(); - $token = $stream->expect(Token::NAME_TYPE); - $names = [new AssignContextVariable($token->getValue(), $token->getLine())]; - $stream->expect(Token::ARROW_TYPE); - - return new ArrowFunctionExpression($this->parseExpression(), new Nodes($names), $line); - } - - // first, determine if we are parsing an arrow function by finding => (long form) - $i = 0; - if (!$stream->look($i)->test(Token::PUNCTUATION_TYPE, '(')) { - return null; - } - ++$i; - while (true) { - // variable name - ++$i; - if (!$stream->look($i)->test(Token::PUNCTUATION_TYPE, ',')) { - break; - } - ++$i; - } - if (!$stream->look($i)->test(Token::PUNCTUATION_TYPE, ')')) { - return null; - } - ++$i; - if (!$stream->look($i)->test(Token::ARROW_TYPE)) { - return null; - } - - // yes, let's parse it properly - $token = $stream->expect(Token::PUNCTUATION_TYPE, '('); - $line = $token->getLine(); - - $names = []; - while (true) { - $token = $stream->expect(Token::NAME_TYPE); - $names[] = new AssignContextVariable($token->getValue(), $token->getLine()); - - if (!$stream->nextIf(Token::PUNCTUATION_TYPE, ',')) { - break; - } - } - $stream->expect(Token::PUNCTUATION_TYPE, ')'); - $stream->expect(Token::ARROW_TYPE); - - return new ArrowFunctionExpression($this->parseExpression(), new Nodes($names), $line); - } - - private function getPrimary(): AbstractExpression - { - $token = $this->parser->getCurrentToken(); - - if ($this->isUnary($token)) { - $operator = $this->unaryOperators[$token->getValue()]; - $this->parser->getStream()->next(); - $expr = $this->parseExpression($operator['precedence']); - $class = $operator['class']; - - $expr = new $class($expr, $token->getLine()); - $expr->setAttribute('operator', 'unary_'.$token->getValue()); - - if ($this->deprecationCheck) { - $this->triggerPrecedenceDeprecations($expr); - } - - return $this->parsePostfixExpression($expr); - } elseif ($token->test(Token::PUNCTUATION_TYPE, '(')) { - $this->parser->getStream()->next(); - $previous = $this->setDeprecationCheck(false); - try { - $expr = $this->parseExpression()->setExplicitParentheses(); - } finally { - $this->setDeprecationCheck($previous); - } - $this->parser->getStream()->expect(Token::PUNCTUATION_TYPE, ')', 'An opened parenthesis is not properly closed'); - - return $this->parsePostfixExpression($expr); - } - - return $this->parsePrimaryExpression(); - } - - private function parseConditionalExpression($expr): AbstractExpression - { - while ($this->parser->getStream()->nextIf(Token::PUNCTUATION_TYPE, '?')) { - $expr2 = $this->parseExpression(); - if ($this->parser->getStream()->nextIf(Token::PUNCTUATION_TYPE, ':')) { - // Ternary operator (expr ? expr2 : expr3) - $expr3 = $this->parseExpression(); - } else { - // Ternary without else (expr ? expr2) - $expr3 = new ConstantExpression('', $this->parser->getCurrentToken()->getLine()); - } - - $expr = new ConditionalTernary($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine()); - } - - return $expr; - } - - private function isUnary(Token $token): bool - { - return $token->test(Token::OPERATOR_TYPE) && isset($this->unaryOperators[$token->getValue()]); - } - - private function isBinary(Token $token): bool - { - return $token->test(Token::OPERATOR_TYPE) && isset($this->binaryOperators[$token->getValue()]); - } - public function parsePrimaryExpression() { - $token = $this->parser->getCurrentToken(); - switch (true) { - case $token->test(Token::NAME_TYPE): - $this->parser->getStream()->next(); - switch ($token->getValue()) { - case 'true': - case 'TRUE': - $node = new ConstantExpression(true, $token->getLine()); - break; - - case 'false': - case 'FALSE': - $node = new ConstantExpression(false, $token->getLine()); - break; - - case 'none': - case 'NONE': - case 'null': - case 'NULL': - $node = new ConstantExpression(null, $token->getLine()); - break; - - default: - if ('(' === $this->parser->getCurrentToken()->getValue()) { - $node = $this->getFunctionNode($token->getValue(), $token->getLine()); - } else { - $node = new ContextVariable($token->getValue(), $token->getLine()); - } - } - break; - - case $token->test(Token::NUMBER_TYPE): - $this->parser->getStream()->next(); - $node = new ConstantExpression($token->getValue(), $token->getLine()); - break; - - case $token->test(Token::STRING_TYPE): - case $token->test(Token::INTERPOLATION_START_TYPE): - $node = $this->parseStringExpression(); - break; + trigger_deprecation('twig/twig', '3.21', 'The "%s()" method is deprecated.', __METHOD__); - case $token->test(Token::PUNCTUATION_TYPE): - $node = match ($token->getValue()) { - '[' => $this->parseSequenceExpression(), - '{' => $this->parseMappingExpression(), - default => throw new SyntaxError(\sprintf('Unexpected token "%s" of value "%s".', $token->toEnglish(), $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext()), - }; - break; - - case $token->test(Token::OPERATOR_TYPE): - if (preg_match(Lexer::REGEX_NAME, $token->getValue(), $matches) && $matches[0] == $token->getValue()) { - // in this context, string operators are variable names - $this->parser->getStream()->next(); - $node = new ContextVariable($token->getValue(), $token->getLine()); - break; - } - - if ('=' === $token->getValue() && ('==' === $this->parser->getStream()->look(-1)->getValue() || '!=' === $this->parser->getStream()->look(-1)->getValue())) { - throw new SyntaxError(\sprintf('Unexpected operator of value "%s". Did you try to use "===" or "!==" for strict comparison? Use "is same as(value)" instead.', $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext()); - } - - // no break - default: - throw new SyntaxError(\sprintf('Unexpected token "%s" of value "%s".', $token->toEnglish(), $token->getValue()), $token->getLine(), $this->parser->getStream()->getSourceContext()); - } - - return $this->parsePostfixExpression($node); + return $this->parseExpression(); } + /** + * @deprecated since Twig 3.21 + */ public function parseStringExpression() { - $stream = $this->parser->getStream(); - - $nodes = []; - // a string cannot be followed by another string in a single expression - $nextCanBeString = true; - while (true) { - if ($nextCanBeString && $token = $stream->nextIf(Token::STRING_TYPE)) { - $nodes[] = new ConstantExpression($token->getValue(), $token->getLine()); - $nextCanBeString = false; - } elseif ($stream->nextIf(Token::INTERPOLATION_START_TYPE)) { - $nodes[] = $this->parseExpression(); - $stream->expect(Token::INTERPOLATION_END_TYPE); - $nextCanBeString = true; - } else { - break; - } - } - - $expr = array_shift($nodes); - foreach ($nodes as $node) { - $expr = new ConcatBinary($expr, $node, $node->getTemplateLine()); - } + trigger_deprecation('twig/twig', '3.21', 'The "%s()" method is deprecated.', __METHOD__); - return $expr; + return $this->parseExpression(); } /** - * @deprecated since Twig 3.11, use parseSequenceExpression() instead + * @deprecated since Twig 3.11, use parseExpression() instead */ public function parseArrayExpression() { - trigger_deprecation('twig/twig', '3.11', 'Calling "%s()" is deprecated, use "parseSequenceExpression()" instead.', __METHOD__); + trigger_deprecation('twig/twig', '3.11', 'Calling "%s()" is deprecated, use "parseExpression()" instead.', __METHOD__); - return $this->parseSequenceExpression(); + return $this->parseExpression(); } + /** + * @deprecated since Twig 3.21 + */ public function parseSequenceExpression() { - $stream = $this->parser->getStream(); - $stream->expect(Token::PUNCTUATION_TYPE, '[', 'A sequence element was expected'); + trigger_deprecation('twig/twig', '3.21', 'The "%s()" method is deprecated.', __METHOD__); - $node = new ArrayExpression([], $stream->getCurrent()->getLine()); - $first = true; - while (!$stream->test(Token::PUNCTUATION_TYPE, ']')) { - if (!$first) { - $stream->expect(Token::PUNCTUATION_TYPE, ',', 'A sequence element must be followed by a comma'); - - // trailing ,? - if ($stream->test(Token::PUNCTUATION_TYPE, ']')) { - break; - } - } - $first = false; - - if ($stream->nextIf(Token::SPREAD_TYPE)) { - $expr = $this->parseExpression(); - $expr->setAttribute('spread', true); - $node->addElement($expr); - } else { - $node->addElement($this->parseExpression()); - } - } - $stream->expect(Token::PUNCTUATION_TYPE, ']', 'An opened sequence is not properly closed'); - - return $node; + return $this->parseExpression(); } /** - * @deprecated since Twig 3.11, use parseMappingExpression() instead + * @deprecated since Twig 3.11, use parseExpression() instead */ public function parseHashExpression() { - trigger_deprecation('twig/twig', '3.11', 'Calling "%s()" is deprecated, use "parseMappingExpression()" instead.', __METHOD__); + trigger_deprecation('twig/twig', '3.11', 'Calling "%s()" is deprecated, use "parseExpression()" instead.', __METHOD__); - return $this->parseMappingExpression(); + return $this->parseExpression(); } + /** + * @deprecated since Twig 3.21 + */ public function parseMappingExpression() { - $stream = $this->parser->getStream(); - $stream->expect(Token::PUNCTUATION_TYPE, '{', 'A mapping element was expected'); - - $node = new ArrayExpression([], $stream->getCurrent()->getLine()); - $first = true; - while (!$stream->test(Token::PUNCTUATION_TYPE, '}')) { - if (!$first) { - $stream->expect(Token::PUNCTUATION_TYPE, ',', 'A mapping value must be followed by a comma'); - - // trailing ,? - if ($stream->test(Token::PUNCTUATION_TYPE, '}')) { - break; - } - } - $first = false; + trigger_deprecation('twig/twig', '3.21', 'The "%s()" method is deprecated.', __METHOD__); - if ($stream->nextIf(Token::SPREAD_TYPE)) { - $value = $this->parseExpression(); - $value->setAttribute('spread', true); - $node->addElement($value); - continue; - } - - // a mapping key can be: - // - // * a number -- 12 - // * a string -- 'a' - // * a name, which is equivalent to a string -- a - // * an expression, which must be enclosed in parentheses -- (1 + 2) - if ($token = $stream->nextIf(Token::NAME_TYPE)) { - $key = new ConstantExpression($token->getValue(), $token->getLine()); - - // {a} is a shortcut for {a:a} - if ($stream->test(Token::PUNCTUATION_TYPE, [',', '}'])) { - $value = new ContextVariable($key->getAttribute('value'), $key->getTemplateLine()); - $node->addElement($value, $key); - continue; - } - } elseif (($token = $stream->nextIf(Token::STRING_TYPE)) || $token = $stream->nextIf(Token::NUMBER_TYPE)) { - $key = new ConstantExpression($token->getValue(), $token->getLine()); - } elseif ($stream->test(Token::PUNCTUATION_TYPE, '(')) { - $key = $this->parseExpression(); - } else { - $current = $stream->getCurrent(); - - throw new SyntaxError(\sprintf('A mapping key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s".', $current->toEnglish(), $current->getValue()), $current->getLine(), $stream->getSourceContext()); - } - - $stream->expect(Token::PUNCTUATION_TYPE, ':', 'A mapping key must be followed by a colon (:)'); - $value = $this->parseExpression(); - - $node->addElement($value, $key); - } - $stream->expect(Token::PUNCTUATION_TYPE, '}', 'An opened mapping is not properly closed'); - - return $node; + return $this->parseExpression(); } + /** + * @deprecated since Twig 3.21 + */ public function parsePostfixExpression($node) { + trigger_deprecation('twig/twig', '3.21', 'The "%s()" method is deprecated.', __METHOD__); + while (true) { $token = $this->parser->getCurrentToken(); if ($token->test(Token::PUNCTUATION_TYPE)) { @@ -523,81 +152,49 @@ public function parsePostfixExpression($node) return $node; } - public function getFunctionNode($name, $line) + /** + * @deprecated since Twig 3.21 + */ + public function parseSubscriptExpression($node) { - if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) { - return new MacroReferenceExpression($alias['node']->getNode('var'), $alias['name'], $this->createArguments($line), $line); - } - - $args = $this->parseNamedArguments(); - $function = $this->getFunction($name, $line); + trigger_deprecation('twig/twig', '3.21', 'The "%s()" method is deprecated.', __METHOD__); - if ($function->getParserCallable()) { - $fakeNode = new EmptyNode($line); - $fakeNode->setSourceContext($this->parser->getStream()->getSourceContext()); + $parsers = new \ReflectionProperty($this->parser, 'parsers'); - return ($function->getParserCallable())($this->parser, $fakeNode, $args, $line); - } - - if (!isset($this->readyNodes[$class = $function->getNodeClass()])) { - $this->readyNodes[$class] = (bool) (new \ReflectionClass($class))->getConstructor()->getAttributes(FirstClassTwigCallableReady::class); - } - - if (!$ready = $this->readyNodes[$class]) { - trigger_deprecation('twig/twig', '3.12', 'Twig node "%s" is not marked as ready for passing a "TwigFunction" in the constructor instead of its name; please update your code and then add #[FirstClassTwigCallableReady] attribute to the constructor.', $class); - } - - return new $class($ready ? $function : $function->getName(), $args, $line); - } - - public function parseSubscriptExpression($node) - { if ('.' === $this->parser->getStream()->next()->getValue()) { - return $this->parseSubscriptExpressionDot($node); + return $parsers->getValue($this->parser)->getByClass(DotExpressionParser::class)->parse($this->parser, $node, $this->parser->getCurrentToken()); } - return $this->parseSubscriptExpressionArray($node); + return $parsers->getValue($this->parser)->getByClass(SquareBracketExpressionParser::class)->parse($this->parser, $node, $this->parser->getCurrentToken()); } + /** + * @deprecated since Twig 3.21 + */ public function parseFilterExpression($node) { + trigger_deprecation('twig/twig', '3.21', 'The "%s()" method is deprecated.', __METHOD__); + $this->parser->getStream()->next(); return $this->parseFilterExpressionRaw($node); } + /** + * @deprecated since Twig 3.21 + */ public function parseFilterExpressionRaw($node) { - if (\func_num_args() > 1) { - trigger_deprecation('twig/twig', '3.12', 'Passing a second argument to "%s()" is deprecated.', __METHOD__); - } - - while (true) { - $token = $this->parser->getStream()->expect(Token::NAME_TYPE); + trigger_deprecation('twig/twig', '3.21', 'The "%s()" method is deprecated.', __METHOD__); - if (!$this->parser->getStream()->test(Token::PUNCTUATION_TYPE, '(')) { - $arguments = new EmptyNode(); - } else { - $arguments = $this->parseNamedArguments(); - } + $parsers = new \ReflectionProperty($this->parser, 'parsers'); - $filter = $this->getFilter($token->getValue(), $token->getLine()); - - $ready = true; - if (!isset($this->readyNodes[$class = $filter->getNodeClass()])) { - $this->readyNodes[$class] = (bool) (new \ReflectionClass($class))->getConstructor()->getAttributes(FirstClassTwigCallableReady::class); - } - - if (!$ready = $this->readyNodes[$class]) { - trigger_deprecation('twig/twig', '3.12', 'Twig node "%s" is not marked as ready for passing a "TwigFilter" in the constructor instead of its name; please update your code and then add #[FirstClassTwigCallableReady] attribute to the constructor.', $class); - } - - $node = new $class($node, $ready ? $filter : new ConstantExpression($filter->getName(), $token->getLine()), $arguments, $token->getLine()); - - if (!$this->parser->getStream()->test(Token::PUNCTUATION_TYPE, '|')) { + $op = $parsers->getValue($this->parser)->getByClass(FilterExpressionParser::class); + while (true) { + $node = $op->parse($this->parser, $node, $this->parser->getCurrentToken()); + if (!$this->parser->getStream()->test(Token::OPERATOR_TYPE, '|')) { break; } - $this->parser->getStream()->next(); } @@ -611,11 +208,13 @@ public function parseFilterExpressionRaw($node) * * @throws SyntaxError * - * @deprecated since Twig 3.19 Use parseNamedArguments() instead + * @deprecated since Twig 3.19 Use Twig\ExpressionParser\Infix\ArgumentsTrait::parseNamedArguments() instead */ public function parseArguments() { - trigger_deprecation('twig/twig', '3.19', \sprintf('The "%s()" method is deprecated, use "%s::parseNamedArguments()" instead.', __METHOD__, __CLASS__)); + trigger_deprecation('twig/twig', '3.19', \sprintf('The "%s()" method is deprecated, use "Twig\ExpressionParser\Infix\ArgumentsTrait::parseNamedArguments()" instead.', __METHOD__)); + + $parsePrimary = new \ReflectionMethod($this->parser, 'parsePrimary'); $namedArguments = false; $definition = false; @@ -630,7 +229,7 @@ public function parseArguments() $args = []; $stream = $this->parser->getStream(); - $stream->expect(Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis'); + $stream->expect(Token::OPERATOR_TYPE, '(', 'A list of arguments must begin with an opening parenthesis'); $hasSpread = false; while (!$stream->test(Token::PUNCTUATION_TYPE, ')')) { if ($args) { @@ -659,12 +258,12 @@ public function parseArguments() $name = null; if ($namedArguments && (($token = $stream->nextIf(Token::OPERATOR_TYPE, '=')) || (!$definition && $token = $stream->nextIf(Token::PUNCTUATION_TYPE, ':')))) { if (!$value instanceof ContextVariable) { - throw new SyntaxError(\sprintf('A parameter name must be a string, "%s" given.', \get_class($value)), $token->getLine(), $stream->getSourceContext()); + throw new SyntaxError(\sprintf('A parameter name must be a string, "%s" given.', $value::class), $token->getLine(), $stream->getSourceContext()); } $name = $value->getAttribute('name'); if ($definition) { - $value = $this->getPrimary(); + $value = $parsePrimary->invoke($this->parser); if (!$this->checkConstantExpression($value)) { throw new SyntaxError('A default value for an argument must be a constant (a boolean, a string, a number, a sequence, or a mapping).', $token->getLine(), $stream->getSourceContext()); @@ -694,8 +293,13 @@ public function parseArguments() return new Nodes($args); } + /** + * @deprecated since Twig 3.21, use "AbstractTokenParser::parseAssignmentExpression()" instead + */ public function parseAssignmentExpression() { + trigger_deprecation('twig/twig', '3.21', 'The "%s()" method is deprecated, use "AbstractTokenParser::parseAssignmentExpression()" instead.', __METHOD__); + $stream = $this->parser->getStream(); $targets = []; while (true) { @@ -716,8 +320,13 @@ public function parseAssignmentExpression() return new Nodes($targets); } + /** + * @deprecated since Twig 3.21 + */ public function parseMultitargetExpression() { + trigger_deprecation('twig/twig', '3.21', 'The "%s()" method is deprecated.', __METHOD__); + $targets = []; while (true) { $targets[] = $this->parseExpression(); @@ -729,133 +338,6 @@ public function parseMultitargetExpression() return new Nodes($targets); } - private function parseNotTestExpression(Node $node): NotUnary - { - return new NotUnary($this->parseTestExpression($node), $this->parser->getCurrentToken()->getLine()); - } - - private function parseTestExpression(Node $node): TestExpression - { - $stream = $this->parser->getStream(); - $test = $this->getTest($node->getTemplateLine()); - - $arguments = null; - if ($stream->test(Token::PUNCTUATION_TYPE, '(')) { - $arguments = $this->parseNamedArguments(); - } elseif ($test->hasOneMandatoryArgument()) { - $arguments = new Nodes([0 => $this->getPrimary()]); - } - - if ('defined' === $test->getName() && $node instanceof ContextVariable && null !== $alias = $this->parser->getImportedSymbol('function', $node->getAttribute('name'))) { - $node = new MacroReferenceExpression($alias['node']->getNode('var'), $alias['name'], new ArrayExpression([], $node->getTemplateLine()), $node->getTemplateLine()); - } - - $ready = $test instanceof TwigTest; - if (!isset($this->readyNodes[$class = $test->getNodeClass()])) { - $this->readyNodes[$class] = (bool) (new \ReflectionClass($class))->getConstructor()->getAttributes(FirstClassTwigCallableReady::class); - } - - if (!$ready = $this->readyNodes[$class]) { - trigger_deprecation('twig/twig', '3.12', 'Twig node "%s" is not marked as ready for passing a "TwigTest" in the constructor instead of its name; please update your code and then add #[FirstClassTwigCallableReady] attribute to the constructor.', $class); - } - - return new $class($node, $ready ? $test : $test->getName(), $arguments, $this->parser->getCurrentToken()->getLine()); - } - - private function getTest(int $line): TwigTest - { - $stream = $this->parser->getStream(); - $name = $stream->expect(Token::NAME_TYPE)->getValue(); - - if ($stream->test(Token::NAME_TYPE)) { - // try 2-words tests - $name = $name.' '.$this->parser->getCurrentToken()->getValue(); - - if ($test = $this->env->getTest($name)) { - $stream->next(); - } - } else { - $test = $this->env->getTest($name); - } - - if (!$test) { - if ($this->parser->shouldIgnoreUnknownTwigCallables()) { - return new TwigTest($name, fn () => ''); - } - $e = new SyntaxError(\sprintf('Unknown "%s" test.', $name), $line, $stream->getSourceContext()); - $e->addSuggestions($name, array_keys($this->env->getTests())); - - throw $e; - } - - if ($test->isDeprecated()) { - $stream = $this->parser->getStream(); - $src = $stream->getSourceContext(); - $test->triggerDeprecation($src->getPath() ?: $src->getName(), $stream->getCurrent()->getLine()); - } - - return $test; - } - - private function getFunction(string $name, int $line): TwigFunction - { - try { - $function = $this->env->getFunction($name); - } catch (SyntaxError $e) { - if (!$this->parser->shouldIgnoreUnknownTwigCallables()) { - throw $e; - } - - $function = null; - } - - if (!$function) { - if ($this->parser->shouldIgnoreUnknownTwigCallables()) { - return new TwigFunction($name, fn () => ''); - } - $e = new SyntaxError(\sprintf('Unknown "%s" function.', $name), $line, $this->parser->getStream()->getSourceContext()); - $e->addSuggestions($name, array_keys($this->env->getFunctions())); - - throw $e; - } - - if ($function->isDeprecated()) { - $src = $this->parser->getStream()->getSourceContext(); - $function->triggerDeprecation($src->getPath() ?: $src->getName(), $line); - } - - return $function; - } - - private function getFilter(string $name, int $line): TwigFilter - { - try { - $filter = $this->env->getFilter($name); - } catch (SyntaxError $e) { - if (!$this->parser->shouldIgnoreUnknownTwigCallables()) { - throw $e; - } - - $filter = null; - } - if (!$filter) { - if ($this->parser->shouldIgnoreUnknownTwigCallables()) { - return new TwigFilter($name, fn () => ''); - } - $e = new SyntaxError(\sprintf('Unknown "%s" filter.', $name), $line, $this->parser->getStream()->getSourceContext()); - $e->addSuggestions($name, array_keys($this->env->getFilters())); - - throw $e; - } - - if ($filter->isDeprecated()) { - $src = $this->parser->getStream()->getSourceContext(); - $filter->triggerDeprecation($src->getPath() ?: $src->getName(), $line); - } - - return $filter; - } - // checks that the node only contains "constant" elements // to be removed in 4.0 private function checkConstantExpression(Node $node): bool @@ -875,159 +357,13 @@ private function checkConstantExpression(Node $node): bool return true; } - private function setDeprecationCheck(bool $deprecationCheck): bool - { - $current = $this->deprecationCheck; - $this->deprecationCheck = $deprecationCheck; - - return $current; - } - - private function createArguments(int $line): ArrayExpression - { - $arguments = new ArrayExpression([], $line); - foreach ($this->parseNamedArguments() as $k => $n) { - $arguments->addElement($n, new LocalVariable($k, $line)); - } - - return $arguments; - } - /** - * @deprecated since Twig 3.19 Use parseNamedArguments() instead + * @deprecated since Twig 3.19 Use Twig\ExpressionParser\Infix\ArgumentsTrait::parseNamedArguments() instead */ public function parseOnlyArguments() { - trigger_deprecation('twig/twig', '3.19', \sprintf('The "%s()" method is deprecated, use "%s::parseNamedArguments()" instead.', __METHOD__, __CLASS__)); - - return $this->parseNamedArguments(); - } - - public function parseNamedArguments(): Nodes - { - $args = []; - $stream = $this->parser->getStream(); - $stream->expect(Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis'); - $hasSpread = false; - while (!$stream->test(Token::PUNCTUATION_TYPE, ')')) { - if ($args) { - $stream->expect(Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma'); - - // if the comma above was a trailing comma, early exit the argument parse loop - if ($stream->test(Token::PUNCTUATION_TYPE, ')')) { - break; - } - } - - if ($stream->nextIf(Token::SPREAD_TYPE)) { - $hasSpread = true; - $value = new SpreadUnary($this->parseExpression(), $stream->getCurrent()->getLine()); - } elseif ($hasSpread) { - throw new SyntaxError('Normal arguments must be placed before argument unpacking.', $stream->getCurrent()->getLine(), $stream->getSourceContext()); - } else { - $value = $this->parseExpression(); - } - - $name = null; - if (($token = $stream->nextIf(Token::OPERATOR_TYPE, '=')) || ($token = $stream->nextIf(Token::PUNCTUATION_TYPE, ':'))) { - if (!$value instanceof ContextVariable) { - throw new SyntaxError(\sprintf('A parameter name must be a string, "%s" given.', \get_class($value)), $token->getLine(), $stream->getSourceContext()); - } - $name = $value->getAttribute('name'); - $value = $this->parseExpression(); - } - - if (null === $name) { - $args[] = $value; - } else { - $args[$name] = $value; - } - } - $stream->expect(Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis'); - - return new Nodes($args); - } - - private function parseSubscriptExpressionDot(Node $node): AbstractExpression - { - $stream = $this->parser->getStream(); - $token = $stream->getCurrent(); - $lineno = $token->getLine(); - $arguments = new ArrayExpression([], $lineno); - $type = Template::ANY_CALL; - - if ($stream->nextIf(Token::PUNCTUATION_TYPE, '(')) { - $attribute = $this->parseExpression(); - $stream->expect(Token::PUNCTUATION_TYPE, ')'); - } else { - $token = $stream->next(); - if ( - $token->test(Token::NAME_TYPE) - || $token->test(Token::NUMBER_TYPE) - || ($token->test(Token::OPERATOR_TYPE) && preg_match(Lexer::REGEX_NAME, $token->getValue())) - ) { - $attribute = new ConstantExpression($token->getValue(), $token->getLine()); - } else { - throw new SyntaxError(\sprintf('Expected name or number, got value "%s" of type %s.', $token->getValue(), $token->toEnglish()), $token->getLine(), $stream->getSourceContext()); - } - } - - if ($stream->test(Token::PUNCTUATION_TYPE, '(')) { - $type = Template::METHOD_CALL; - $arguments = $this->createArguments($token->getLine()); - } - - if ( - $node instanceof ContextVariable - && ( - null !== $this->parser->getImportedSymbol('template', $node->getAttribute('name')) - || '_self' === $node->getAttribute('name') && $attribute instanceof ConstantExpression - ) - ) { - return new MacroReferenceExpression(new TemplateVariable($node->getAttribute('name'), $node->getTemplateLine()), 'macro_'.$attribute->getAttribute('value'), $arguments, $node->getTemplateLine()); - } - - return new GetAttrExpression($node, $attribute, $arguments, $type, $lineno); - } - - private function parseSubscriptExpressionArray(Node $node): AbstractExpression - { - $stream = $this->parser->getStream(); - $token = $stream->getCurrent(); - $lineno = $token->getLine(); - $arguments = new ArrayExpression([], $lineno); - - // slice? - $slice = false; - if ($stream->test(Token::PUNCTUATION_TYPE, ':')) { - $slice = true; - $attribute = new ConstantExpression(0, $token->getLine()); - } else { - $attribute = $this->parseExpression(); - } - - if ($stream->nextIf(Token::PUNCTUATION_TYPE, ':')) { - $slice = true; - } - - if ($slice) { - if ($stream->test(Token::PUNCTUATION_TYPE, ']')) { - $length = new ConstantExpression(null, $token->getLine()); - } else { - $length = $this->parseExpression(); - } - - $filter = $this->getFilter('slice', $token->getLine()); - $arguments = new Nodes([$attribute, $length]); - $filter = new ($filter->getNodeClass())($node, $filter, $arguments, $token->getLine()); - - $stream->expect(Token::PUNCTUATION_TYPE, ']'); - - return $filter; - } - - $stream->expect(Token::PUNCTUATION_TYPE, ']'); + trigger_deprecation('twig/twig', '3.19', \sprintf('The "%s()" method is deprecated, use "Twig\ExpressionParser\Infix\ArgumentsTrait::parseNamedArguments()" instead.', __METHOD__)); - return new GetAttrExpression($node, $attribute, $arguments, Template::ARRAY_CALL, $lineno); + return $this->parseArguments(); } } diff --git a/app/vendor/twig/twig/src/ExpressionParser/AbstractExpressionParser.php b/app/vendor/twig/twig/src/ExpressionParser/AbstractExpressionParser.php new file mode 100644 index 000000000..bc05bfa05 --- /dev/null +++ b/app/vendor/twig/twig/src/ExpressionParser/AbstractExpressionParser.php @@ -0,0 +1,30 @@ +value, $this->getName()); + } + + public function getPrecedenceChange(): ?PrecedenceChange + { + return null; + } + + public function getAliases(): array + { + return []; + } +} diff --git a/app/vendor/twig/twig/src/ExpressionParser/ExpressionParserDescriptionInterface.php b/app/vendor/twig/twig/src/ExpressionParser/ExpressionParserDescriptionInterface.php new file mode 100644 index 000000000..686f8a59f --- /dev/null +++ b/app/vendor/twig/twig/src/ExpressionParser/ExpressionParserDescriptionInterface.php @@ -0,0 +1,17 @@ + + */ + public function getAliases(): array; +} diff --git a/app/vendor/twig/twig/src/ExpressionParser/ExpressionParserType.php b/app/vendor/twig/twig/src/ExpressionParser/ExpressionParserType.php new file mode 100644 index 000000000..8c21a8d76 --- /dev/null +++ b/app/vendor/twig/twig/src/ExpressionParser/ExpressionParserType.php @@ -0,0 +1,33 @@ + + * + * @internal + */ +final class ExpressionParsers implements \IteratorAggregate +{ + /** + * @var array, array> + */ + private array $parsersByName = []; + + /** + * @var array, ExpressionParserInterface> + */ + private array $parsersByClass = []; + + /** + * @var \WeakMap>|null + */ + private ?\WeakMap $precedenceChanges = null; + + /** + * @param array $parsers + */ + public function __construct(array $parsers = []) + { + $this->add($parsers); + } + + /** + * @param array $parsers + * + * @return $this + */ + public function add(array $parsers): static + { + foreach ($parsers as $parser) { + if ($parser->getPrecedence() > 512 || $parser->getPrecedence() < 0) { + trigger_deprecation('twig/twig', '3.21', 'Precedence for "%s" must be between 0 and 512, got %d.', $parser->getName(), $parser->getPrecedence()); + // throw new \InvalidArgumentException(\sprintf('Precedence for "%s" must be between 0 and 512, got %d.', $parser->getName(), $parser->getPrecedence())); + } + $interface = $parser instanceof PrefixExpressionParserInterface ? PrefixExpressionParserInterface::class : InfixExpressionParserInterface::class; + $this->parsersByName[$interface][$parser->getName()] = $parser; + $this->parsersByClass[$parser::class] = $parser; + foreach ($parser->getAliases() as $alias) { + $this->parsersByName[$interface][$alias] = $parser; + } + } + + return $this; + } + + /** + * @template T of ExpressionParserInterface + * + * @param class-string $class + * + * @return T|null + */ + public function getByClass(string $class): ?ExpressionParserInterface + { + return $this->parsersByClass[$class] ?? null; + } + + /** + * @template T of ExpressionParserInterface + * + * @param class-string $interface + * + * @return T|null + */ + public function getByName(string $interface, string $name): ?ExpressionParserInterface + { + return $this->parsersByName[$interface][$name] ?? null; + } + + public function getIterator(): \Traversable + { + foreach ($this->parsersByName as $parsers) { + // we don't yield the keys + yield from $parsers; + } + } + + /** + * @internal + * + * @return \WeakMap> + */ + public function getPrecedenceChanges(): \WeakMap + { + if (null === $this->precedenceChanges) { + $this->precedenceChanges = new \WeakMap(); + foreach ($this as $ep) { + if (!$ep->getPrecedenceChange()) { + continue; + } + $min = min($ep->getPrecedenceChange()->getNewPrecedence(), $ep->getPrecedence()); + $max = max($ep->getPrecedenceChange()->getNewPrecedence(), $ep->getPrecedence()); + foreach ($this as $e) { + if ($e->getPrecedence() > $min && $e->getPrecedence() < $max) { + if (!isset($this->precedenceChanges[$e])) { + $this->precedenceChanges[$e] = []; + } + $this->precedenceChanges[$e][] = $ep; + } + } + } + } + + return $this->precedenceChanges; + } +} diff --git a/app/vendor/twig/twig/src/ExpressionParser/Infix/ArgumentsTrait.php b/app/vendor/twig/twig/src/ExpressionParser/Infix/ArgumentsTrait.php new file mode 100644 index 000000000..1c2ae49dd --- /dev/null +++ b/app/vendor/twig/twig/src/ExpressionParser/Infix/ArgumentsTrait.php @@ -0,0 +1,79 @@ +parseNamedArguments($parser, $parseOpenParenthesis) as $k => $n) { + $arguments->addElement($n, new LocalVariable($k, $line)); + } + + return $arguments; + } + + private function parseNamedArguments(Parser $parser, bool $parseOpenParenthesis = true): Nodes + { + $args = []; + $stream = $parser->getStream(); + if ($parseOpenParenthesis) { + $stream->expect(Token::OPERATOR_TYPE, '(', 'A list of arguments must begin with an opening parenthesis'); + } + $hasSpread = false; + while (!$stream->test(Token::PUNCTUATION_TYPE, ')')) { + if ($args) { + $stream->expect(Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma'); + + // if the comma above was a trailing comma, early exit the argument parse loop + if ($stream->test(Token::PUNCTUATION_TYPE, ')')) { + break; + } + } + + $value = $parser->parseExpression(); + if ($value instanceof SpreadUnary) { + $hasSpread = true; + } elseif ($hasSpread) { + throw new SyntaxError('Normal arguments must be placed before argument unpacking.', $stream->getCurrent()->getLine(), $stream->getSourceContext()); + } + + $name = null; + if (($token = $stream->nextIf(Token::OPERATOR_TYPE, '=')) || ($token = $stream->nextIf(Token::PUNCTUATION_TYPE, ':'))) { + if (!$value instanceof ContextVariable) { + throw new SyntaxError(\sprintf('A parameter name must be a string, "%s" given.', $value::class), $token->getLine(), $stream->getSourceContext()); + } + $name = $value->getAttribute('name'); + $value = $parser->parseExpression(); + } + + if (null === $name) { + $args[] = $value; + } else { + $args[$name] = $value; + } + } + $stream->expect(Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis'); + + return new Nodes($args); + } +} diff --git a/app/vendor/twig/twig/src/ExpressionParser/Infix/ArrowExpressionParser.php b/app/vendor/twig/twig/src/ExpressionParser/Infix/ArrowExpressionParser.php new file mode 100644 index 000000000..c8630da41 --- /dev/null +++ b/app/vendor/twig/twig/src/ExpressionParser/Infix/ArrowExpressionParser.php @@ -0,0 +1,53 @@ +parseExpression(), $expr, $token->getLine()); + } + + public function getName(): string + { + return '=>'; + } + + public function getDescription(): string + { + return 'Arrow function (x => expr)'; + } + + public function getPrecedence(): int + { + return 250; + } + + public function getAssociativity(): InfixAssociativity + { + return InfixAssociativity::Left; + } +} diff --git a/app/vendor/twig/twig/src/ExpressionParser/Infix/BinaryOperatorExpressionParser.php b/app/vendor/twig/twig/src/ExpressionParser/Infix/BinaryOperatorExpressionParser.php new file mode 100644 index 000000000..4c66da73b --- /dev/null +++ b/app/vendor/twig/twig/src/ExpressionParser/Infix/BinaryOperatorExpressionParser.php @@ -0,0 +1,80 @@ + */ + private string $nodeClass, + private string $name, + private int $precedence, + private InfixAssociativity $associativity = InfixAssociativity::Left, + private ?PrecedenceChange $precedenceChange = null, + private ?string $description = null, + private array $aliases = [], + ) { + } + + /** + * @return AbstractBinary + */ + public function parse(Parser $parser, AbstractExpression $left, Token $token): AbstractExpression + { + $right = $parser->parseExpression(InfixAssociativity::Left === $this->getAssociativity() ? $this->getPrecedence() + 1 : $this->getPrecedence()); + + return new ($this->nodeClass)($left, $right, $token->getLine()); + } + + public function getAssociativity(): InfixAssociativity + { + return $this->associativity; + } + + public function getName(): string + { + return $this->name; + } + + public function getDescription(): string + { + return $this->description ?? ''; + } + + public function getPrecedence(): int + { + return $this->precedence; + } + + public function getPrecedenceChange(): ?PrecedenceChange + { + return $this->precedenceChange; + } + + public function getAliases(): array + { + return $this->aliases; + } +} diff --git a/app/vendor/twig/twig/src/ExpressionParser/Infix/ConditionalTernaryExpressionParser.php b/app/vendor/twig/twig/src/ExpressionParser/Infix/ConditionalTernaryExpressionParser.php new file mode 100644 index 000000000..9707c0a04 --- /dev/null +++ b/app/vendor/twig/twig/src/ExpressionParser/Infix/ConditionalTernaryExpressionParser.php @@ -0,0 +1,62 @@ +parseExpression($this->getPrecedence()); + if ($parser->getStream()->nextIf(Token::PUNCTUATION_TYPE, ':')) { + // Ternary operator (expr ? expr2 : expr3) + $else = $parser->parseExpression($this->getPrecedence()); + } else { + // Ternary without else (expr ? expr2) + $else = new ConstantExpression('', $token->getLine()); + } + + return new ConditionalTernary($left, $then, $else, $token->getLine()); + } + + public function getName(): string + { + return '?'; + } + + public function getDescription(): string + { + return 'Conditional operator (a ? b : c)'; + } + + public function getPrecedence(): int + { + return 0; + } + + public function getAssociativity(): InfixAssociativity + { + return InfixAssociativity::Left; + } +} diff --git a/app/vendor/twig/twig/src/ExpressionParser/Infix/DotExpressionParser.php b/app/vendor/twig/twig/src/ExpressionParser/Infix/DotExpressionParser.php new file mode 100644 index 000000000..7d1cf5058 --- /dev/null +++ b/app/vendor/twig/twig/src/ExpressionParser/Infix/DotExpressionParser.php @@ -0,0 +1,99 @@ +getStream(); + $token = $stream->getCurrent(); + $lineno = $token->getLine(); + $arguments = new ArrayExpression([], $lineno); + $type = Template::ANY_CALL; + + if ($stream->nextIf(Token::OPERATOR_TYPE, '(')) { + $attribute = $parser->parseExpression(); + $stream->expect(Token::PUNCTUATION_TYPE, ')'); + } else { + $token = $stream->next(); + if ( + $token->test(Token::NAME_TYPE) + || $token->test(Token::NUMBER_TYPE) + || ($token->test(Token::OPERATOR_TYPE) && preg_match(Lexer::REGEX_NAME, $token->getValue())) + ) { + $attribute = new ConstantExpression($token->getValue(), $token->getLine()); + } else { + throw new SyntaxError(\sprintf('Expected name or number, got value "%s" of type %s.', $token->getValue(), $token->toEnglish()), $token->getLine(), $stream->getSourceContext()); + } + } + + if ($stream->test(Token::OPERATOR_TYPE, '(')) { + $type = Template::METHOD_CALL; + $arguments = $this->parseCallableArguments($parser, $token->getLine()); + } + + if ( + $expr instanceof NameExpression + && ( + null !== $parser->getImportedSymbol('template', $expr->getAttribute('name')) + || '_self' === $expr->getAttribute('name') && $attribute instanceof ConstantExpression + ) + ) { + return new MacroReferenceExpression(new TemplateVariable($expr->getAttribute('name'), $expr->getTemplateLine()), 'macro_'.$attribute->getAttribute('value'), $arguments, $expr->getTemplateLine()); + } + + return new GetAttrExpression($expr, $attribute, $arguments, $type, $lineno); + } + + public function getName(): string + { + return '.'; + } + + public function getDescription(): string + { + return 'Get an attribute on a variable'; + } + + public function getPrecedence(): int + { + return 512; + } + + public function getAssociativity(): InfixAssociativity + { + return InfixAssociativity::Left; + } +} diff --git a/app/vendor/twig/twig/src/ExpressionParser/Infix/FilterExpressionParser.php b/app/vendor/twig/twig/src/ExpressionParser/Infix/FilterExpressionParser.php new file mode 100644 index 000000000..0bbe6b409 --- /dev/null +++ b/app/vendor/twig/twig/src/ExpressionParser/Infix/FilterExpressionParser.php @@ -0,0 +1,85 @@ +getStream(); + $token = $stream->expect(Token::NAME_TYPE); + $line = $token->getLine(); + + if (!$stream->test(Token::OPERATOR_TYPE, '(')) { + $arguments = new EmptyNode(); + } else { + $arguments = $this->parseNamedArguments($parser); + } + + $filter = $parser->getFilter($token->getValue(), $line); + + $ready = true; + if (!isset($this->readyNodes[$class = $filter->getNodeClass()])) { + $this->readyNodes[$class] = (bool) (new \ReflectionClass($class))->getConstructor()->getAttributes(FirstClassTwigCallableReady::class); + } + + if (!$ready = $this->readyNodes[$class]) { + trigger_deprecation('twig/twig', '3.12', 'Twig node "%s" is not marked as ready for passing a "TwigFilter" in the constructor instead of its name; please update your code and then add #[FirstClassTwigCallableReady] attribute to the constructor.', $class); + } + + return new $class($expr, $ready ? $filter : new ConstantExpression($filter->getName(), $line), $arguments, $line); + } + + public function getName(): string + { + return '|'; + } + + public function getDescription(): string + { + return 'Twig filter call'; + } + + public function getPrecedence(): int + { + return 512; + } + + public function getPrecedenceChange(): ?PrecedenceChange + { + return new PrecedenceChange('twig/twig', '3.21', 300); + } + + public function getAssociativity(): InfixAssociativity + { + return InfixAssociativity::Left; + } +} diff --git a/app/vendor/twig/twig/src/ExpressionParser/Infix/FunctionExpressionParser.php b/app/vendor/twig/twig/src/ExpressionParser/Infix/FunctionExpressionParser.php new file mode 100644 index 000000000..e9cd77517 --- /dev/null +++ b/app/vendor/twig/twig/src/ExpressionParser/Infix/FunctionExpressionParser.php @@ -0,0 +1,90 @@ +getLine(); + if (!$expr instanceof NameExpression) { + throw new SyntaxError('Function name must be an identifier.', $line, $parser->getStream()->getSourceContext()); + } + + $name = $expr->getAttribute('name'); + + if (null !== $alias = $parser->getImportedSymbol('function', $name)) { + return new MacroReferenceExpression($alias['node']->getNode('var'), $alias['name'], $this->parseCallableArguments($parser, $line, false), $line); + } + + $args = $this->parseNamedArguments($parser, false); + + $function = $parser->getFunction($name, $line); + + if ($function->getParserCallable()) { + $fakeNode = new EmptyNode($line); + $fakeNode->setSourceContext($parser->getStream()->getSourceContext()); + + return ($function->getParserCallable())($parser, $fakeNode, $args, $line); + } + + if (!isset($this->readyNodes[$class = $function->getNodeClass()])) { + $this->readyNodes[$class] = (bool) (new \ReflectionClass($class))->getConstructor()->getAttributes(FirstClassTwigCallableReady::class); + } + + if (!$ready = $this->readyNodes[$class]) { + trigger_deprecation('twig/twig', '3.12', 'Twig node "%s" is not marked as ready for passing a "TwigFunction" in the constructor instead of its name; please update your code and then add #[FirstClassTwigCallableReady] attribute to the constructor.', $class); + } + + return new $class($ready ? $function : $function->getName(), $args, $line); + } + + public function getName(): string + { + return '('; + } + + public function getDescription(): string + { + return 'Twig function call'; + } + + public function getPrecedence(): int + { + return 512; + } + + public function getAssociativity(): InfixAssociativity + { + return InfixAssociativity::Left; + } +} diff --git a/app/vendor/twig/twig/src/ExpressionParser/Infix/IsExpressionParser.php b/app/vendor/twig/twig/src/ExpressionParser/Infix/IsExpressionParser.php new file mode 100644 index 000000000..88d54f70a --- /dev/null +++ b/app/vendor/twig/twig/src/ExpressionParser/Infix/IsExpressionParser.php @@ -0,0 +1,84 @@ +getStream(); + $test = $parser->getTest($token->getLine()); + + $arguments = null; + if ($stream->test(Token::OPERATOR_TYPE, '(')) { + $arguments = $this->parseNamedArguments($parser); + } elseif ($test->hasOneMandatoryArgument()) { + $arguments = new Nodes([0 => $parser->parseExpression($this->getPrecedence())]); + } + + if ('defined' === $test->getName() && $expr instanceof NameExpression && null !== $alias = $parser->getImportedSymbol('function', $expr->getAttribute('name'))) { + $expr = new MacroReferenceExpression($alias['node']->getNode('var'), $alias['name'], new ArrayExpression([], $expr->getTemplateLine()), $expr->getTemplateLine()); + } + + $ready = $test instanceof TwigTest; + if (!isset($this->readyNodes[$class = $test->getNodeClass()])) { + $this->readyNodes[$class] = (bool) (new \ReflectionClass($class))->getConstructor()->getAttributes(FirstClassTwigCallableReady::class); + } + + if (!$ready = $this->readyNodes[$class]) { + trigger_deprecation('twig/twig', '3.12', 'Twig node "%s" is not marked as ready for passing a "TwigTest" in the constructor instead of its name; please update your code and then add #[FirstClassTwigCallableReady] attribute to the constructor.', $class); + } + + return new $class($expr, $ready ? $test : $test->getName(), $arguments, $stream->getCurrent()->getLine()); + } + + public function getPrecedence(): int + { + return 100; + } + + public function getName(): string + { + return 'is'; + } + + public function getDescription(): string + { + return 'Twig tests'; + } + + public function getAssociativity(): InfixAssociativity + { + return InfixAssociativity::Left; + } +} diff --git a/app/vendor/twig/twig/src/ExpressionParser/Infix/IsNotExpressionParser.php b/app/vendor/twig/twig/src/ExpressionParser/Infix/IsNotExpressionParser.php new file mode 100644 index 000000000..1e1085aa8 --- /dev/null +++ b/app/vendor/twig/twig/src/ExpressionParser/Infix/IsNotExpressionParser.php @@ -0,0 +1,33 @@ +getLine()); + } + + public function getName(): string + { + return 'is not'; + } +} diff --git a/app/vendor/twig/twig/src/ExpressionParser/Infix/SquareBracketExpressionParser.php b/app/vendor/twig/twig/src/ExpressionParser/Infix/SquareBracketExpressionParser.php new file mode 100644 index 000000000..c47c91dee --- /dev/null +++ b/app/vendor/twig/twig/src/ExpressionParser/Infix/SquareBracketExpressionParser.php @@ -0,0 +1,91 @@ +getStream(); + $lineno = $token->getLine(); + $arguments = new ArrayExpression([], $lineno); + + // slice? + $slice = false; + if ($stream->test(Token::PUNCTUATION_TYPE, ':')) { + $slice = true; + $attribute = new ConstantExpression(0, $token->getLine()); + } else { + $attribute = $parser->parseExpression(); + } + + if ($stream->nextIf(Token::PUNCTUATION_TYPE, ':')) { + $slice = true; + } + + if ($slice) { + if ($stream->test(Token::PUNCTUATION_TYPE, ']')) { + $length = new ConstantExpression(null, $token->getLine()); + } else { + $length = $parser->parseExpression(); + } + + $filter = $parser->getFilter('slice', $token->getLine()); + $arguments = new Nodes([$attribute, $length]); + $filter = new ($filter->getNodeClass())($expr, $filter, $arguments, $token->getLine()); + + $stream->expect(Token::PUNCTUATION_TYPE, ']'); + + return $filter; + } + + $stream->expect(Token::PUNCTUATION_TYPE, ']'); + + return new GetAttrExpression($expr, $attribute, $arguments, Template::ARRAY_CALL, $lineno); + } + + public function getName(): string + { + return '['; + } + + public function getDescription(): string + { + return 'Array access'; + } + + public function getPrecedence(): int + { + return 512; + } + + public function getAssociativity(): InfixAssociativity + { + return InfixAssociativity::Left; + } +} diff --git a/app/vendor/twig/twig/src/ExpressionParser/InfixAssociativity.php b/app/vendor/twig/twig/src/ExpressionParser/InfixAssociativity.php new file mode 100644 index 000000000..3aeccce45 --- /dev/null +++ b/app/vendor/twig/twig/src/ExpressionParser/InfixAssociativity.php @@ -0,0 +1,18 @@ + + */ +class PrecedenceChange +{ + public function __construct( + private string $package, + private string $version, + private int $newPrecedence, + ) { + } + + public function getPackage(): string + { + return $this->package; + } + + public function getVersion(): string + { + return $this->version; + } + + public function getNewPrecedence(): int + { + return $this->newPrecedence; + } +} diff --git a/app/vendor/twig/twig/src/ExpressionParser/Prefix/GroupingExpressionParser.php b/app/vendor/twig/twig/src/ExpressionParser/Prefix/GroupingExpressionParser.php new file mode 100644 index 000000000..5c6608da4 --- /dev/null +++ b/app/vendor/twig/twig/src/ExpressionParser/Prefix/GroupingExpressionParser.php @@ -0,0 +1,78 @@ +getStream(); + $expr = $parser->parseExpression($this->getPrecedence()); + + if ($stream->nextIf(Token::PUNCTUATION_TYPE, ')')) { + if (!$stream->test(Token::OPERATOR_TYPE, '=>')) { + return $expr->setExplicitParentheses(); + } + + return new ListExpression([$expr], $token->getLine()); + } + + // determine if we are parsing an arrow function arguments + if (!$stream->test(Token::PUNCTUATION_TYPE, ',')) { + $stream->expect(Token::PUNCTUATION_TYPE, ')', 'An opened parenthesis is not properly closed'); + } + + $names = [$expr]; + while (true) { + if ($stream->nextIf(Token::PUNCTUATION_TYPE, ')')) { + break; + } + $stream->expect(Token::PUNCTUATION_TYPE, ','); + $token = $stream->expect(Token::NAME_TYPE); + $names[] = new ContextVariable($token->getValue(), $token->getLine()); + } + + if (!$stream->test(Token::OPERATOR_TYPE, '=>')) { + throw new SyntaxError('A list of variables must be followed by an arrow.', $stream->getCurrent()->getLine(), $stream->getSourceContext()); + } + + return new ListExpression($names, $token->getLine()); + } + + public function getName(): string + { + return '('; + } + + public function getDescription(): string + { + return 'Explicit group expression (a)'; + } + + public function getPrecedence(): int + { + return 0; + } +} diff --git a/app/vendor/twig/twig/src/ExpressionParser/Prefix/LiteralExpressionParser.php b/app/vendor/twig/twig/src/ExpressionParser/Prefix/LiteralExpressionParser.php new file mode 100644 index 000000000..d98c9adf1 --- /dev/null +++ b/app/vendor/twig/twig/src/ExpressionParser/Prefix/LiteralExpressionParser.php @@ -0,0 +1,244 @@ +getStream(); + switch (true) { + case $token->test(Token::NAME_TYPE): + $stream->next(); + switch ($token->getValue()) { + case 'true': + case 'TRUE': + $this->type = 'constant'; + + return new ConstantExpression(true, $token->getLine()); + + case 'false': + case 'FALSE': + $this->type = 'constant'; + + return new ConstantExpression(false, $token->getLine()); + + case 'none': + case 'NONE': + case 'null': + case 'NULL': + $this->type = 'constant'; + + return new ConstantExpression(null, $token->getLine()); + + default: + $this->type = 'variable'; + + return new ContextVariable($token->getValue(), $token->getLine()); + } + + // no break + case $token->test(Token::NUMBER_TYPE): + $stream->next(); + $this->type = 'constant'; + + return new ConstantExpression($token->getValue(), $token->getLine()); + + case $token->test(Token::STRING_TYPE): + case $token->test(Token::INTERPOLATION_START_TYPE): + $this->type = 'string'; + + return $this->parseStringExpression($parser); + + case $token->test(Token::PUNCTUATION_TYPE): + // In 4.0, we should always return the node or throw an error for default + if ($node = match ($token->getValue()) { + '{' => $this->parseMappingExpression($parser), + default => null, + }) { + return $node; + } + + // no break + case $token->test(Token::OPERATOR_TYPE): + if ('[' === $token->getValue()) { + return $this->parseSequenceExpression($parser); + } + + if (preg_match(Lexer::REGEX_NAME, $token->getValue(), $matches) && $matches[0] == $token->getValue()) { + // in this context, string operators are variable names + $stream->next(); + $this->type = 'variable'; + + return new ContextVariable($token->getValue(), $token->getLine()); + } + + if ('=' === $token->getValue() && ('==' === $stream->look(-1)->getValue() || '!=' === $stream->look(-1)->getValue())) { + throw new SyntaxError(\sprintf('Unexpected operator of value "%s". Did you try to use "===" or "!==" for strict comparison? Use "is same as(value)" instead.', $token->getValue()), $token->getLine(), $stream->getSourceContext()); + } + + // no break + default: + throw new SyntaxError(\sprintf('Unexpected token "%s" of value "%s".', $token->toEnglish(), $token->getValue()), $token->getLine(), $stream->getSourceContext()); + } + } + + public function getName(): string + { + return $this->type; + } + + public function getDescription(): string + { + return 'A literal value (boolean, string, number, sequence, mapping, ...)'; + } + + public function getPrecedence(): int + { + // not used + return 0; + } + + private function parseStringExpression(Parser $parser) + { + $stream = $parser->getStream(); + + $nodes = []; + // a string cannot be followed by another string in a single expression + $nextCanBeString = true; + while (true) { + if ($nextCanBeString && $token = $stream->nextIf(Token::STRING_TYPE)) { + $nodes[] = new ConstantExpression($token->getValue(), $token->getLine()); + $nextCanBeString = false; + } elseif ($stream->nextIf(Token::INTERPOLATION_START_TYPE)) { + $nodes[] = $parser->parseExpression(); + $stream->expect(Token::INTERPOLATION_END_TYPE); + $nextCanBeString = true; + } else { + break; + } + } + + $expr = array_shift($nodes); + foreach ($nodes as $node) { + $expr = new ConcatBinary($expr, $node, $node->getTemplateLine()); + } + + return $expr; + } + + private function parseSequenceExpression(Parser $parser) + { + $this->type = 'sequence'; + + $stream = $parser->getStream(); + $stream->expect(Token::OPERATOR_TYPE, '[', 'A sequence element was expected'); + + $node = new ArrayExpression([], $stream->getCurrent()->getLine()); + $first = true; + while (!$stream->test(Token::PUNCTUATION_TYPE, ']')) { + if (!$first) { + $stream->expect(Token::PUNCTUATION_TYPE, ',', 'A sequence element must be followed by a comma'); + + // trailing ,? + if ($stream->test(Token::PUNCTUATION_TYPE, ']')) { + break; + } + } + $first = false; + + $node->addElement($parser->parseExpression()); + } + $stream->expect(Token::PUNCTUATION_TYPE, ']', 'An opened sequence is not properly closed'); + + return $node; + } + + private function parseMappingExpression(Parser $parser) + { + $this->type = 'mapping'; + + $stream = $parser->getStream(); + $stream->expect(Token::PUNCTUATION_TYPE, '{', 'A mapping element was expected'); + + $node = new ArrayExpression([], $stream->getCurrent()->getLine()); + $first = true; + while (!$stream->test(Token::PUNCTUATION_TYPE, '}')) { + if (!$first) { + $stream->expect(Token::PUNCTUATION_TYPE, ',', 'A mapping value must be followed by a comma'); + + // trailing ,? + if ($stream->test(Token::PUNCTUATION_TYPE, '}')) { + break; + } + } + $first = false; + + if ($stream->test(Token::OPERATOR_TYPE, '...')) { + $node->addElement($parser->parseExpression()); + + continue; + } + + // a mapping key can be: + // + // * a number -- 12 + // * a string -- 'a' + // * a name, which is equivalent to a string -- a + // * an expression, which must be enclosed in parentheses -- (1 + 2) + if ($token = $stream->nextIf(Token::NAME_TYPE)) { + $key = new ConstantExpression($token->getValue(), $token->getLine()); + + // {a} is a shortcut for {a:a} + if ($stream->test(Token::PUNCTUATION_TYPE, [',', '}'])) { + $value = new ContextVariable($key->getAttribute('value'), $key->getTemplateLine()); + $node->addElement($value, $key); + continue; + } + } elseif (($token = $stream->nextIf(Token::STRING_TYPE)) || $token = $stream->nextIf(Token::NUMBER_TYPE)) { + $key = new ConstantExpression($token->getValue(), $token->getLine()); + } elseif ($stream->test(Token::OPERATOR_TYPE, '(')) { + $key = $parser->parseExpression(); + } else { + $current = $stream->getCurrent(); + + throw new SyntaxError(\sprintf('A mapping key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s".', $current->toEnglish(), $current->getValue()), $current->getLine(), $stream->getSourceContext()); + } + + $stream->expect(Token::PUNCTUATION_TYPE, ':', 'A mapping key must be followed by a colon (:)'); + $value = $parser->parseExpression(); + + $node->addElement($value, $key); + } + $stream->expect(Token::PUNCTUATION_TYPE, '}', 'An opened mapping is not properly closed'); + + return $node; + } +} diff --git a/app/vendor/twig/twig/src/ExpressionParser/Prefix/UnaryOperatorExpressionParser.php b/app/vendor/twig/twig/src/ExpressionParser/Prefix/UnaryOperatorExpressionParser.php new file mode 100644 index 000000000..35468940a --- /dev/null +++ b/app/vendor/twig/twig/src/ExpressionParser/Prefix/UnaryOperatorExpressionParser.php @@ -0,0 +1,71 @@ + */ + private string $nodeClass, + private string $name, + private int $precedence, + private ?PrecedenceChange $precedenceChange = null, + private ?string $description = null, + private array $aliases = [], + ) { + } + + /** + * @return AbstractUnary + */ + public function parse(Parser $parser, Token $token): AbstractExpression + { + return new ($this->nodeClass)($parser->parseExpression($this->precedence), $token->getLine()); + } + + public function getName(): string + { + return $this->name; + } + + public function getDescription(): string + { + return $this->description ?? ''; + } + + public function getPrecedence(): int + { + return $this->precedence; + } + + public function getPrecedenceChange(): ?PrecedenceChange + { + return $this->precedenceChange; + } + + public function getAliases(): array + { + return $this->aliases; + } +} diff --git a/app/vendor/twig/twig/src/ExpressionParser/PrefixExpressionParserInterface.php b/app/vendor/twig/twig/src/ExpressionParser/PrefixExpressionParserInterface.php new file mode 100644 index 000000000..587997c51 --- /dev/null +++ b/app/vendor/twig/twig/src/ExpressionParser/PrefixExpressionParserInterface.php @@ -0,0 +1,21 @@ +getFileName(); diff --git a/app/vendor/twig/twig/src/Extension/AttributeExtension.php b/app/vendor/twig/twig/src/Extension/AttributeExtension.php new file mode 100644 index 000000000..44e4f3f6b --- /dev/null +++ b/app/vendor/twig/twig/src/Extension/AttributeExtension.php @@ -0,0 +1,174 @@ + + */ +final class AttributeExtension extends AbstractExtension +{ + private array $filters; + private array $functions; + private array $tests; + + /** + * Use a runtime class using PHP attributes to define filters, functions, and tests. + * + * @param class-string $class + */ + public function __construct(private string $class) + { + } + + /** + * @return class-string + */ + public function getClass(): string + { + return $this->class; + } + + public function getFilters(): array + { + if (!isset($this->filters)) { + $this->initFromAttributes(); + } + + return $this->filters; + } + + public function getFunctions(): array + { + if (!isset($this->functions)) { + $this->initFromAttributes(); + } + + return $this->functions; + } + + public function getTests(): array + { + if (!isset($this->tests)) { + $this->initFromAttributes(); + } + + return $this->tests; + } + + public function getLastModified(): int + { + return max( + filemtime(__FILE__), + is_file($filename = (new \ReflectionClass($this->getClass()))->getFileName()) ? filemtime($filename) : 0, + ); + } + + private function initFromAttributes(): void + { + $filters = $functions = $tests = []; + $reflectionClass = new \ReflectionClass($this->getClass()); + foreach ($reflectionClass->getMethods() as $method) { + foreach ($method->getAttributes(AsTwigFilter::class) as $reflectionAttribute) { + /** @var AsTwigFilter $attribute */ + $attribute = $reflectionAttribute->newInstance(); + + $callable = new TwigFilter($attribute->name, [$reflectionClass->name, $method->getName()], [ + 'needs_context' => $attribute->needsContext ?? false, + 'needs_environment' => $attribute->needsEnvironment ?? $this->needsEnvironment($method), + 'needs_charset' => $attribute->needsCharset ?? false, + 'is_variadic' => $method->isVariadic(), + 'is_safe' => $attribute->isSafe, + 'is_safe_callback' => $attribute->isSafeCallback, + 'pre_escape' => $attribute->preEscape, + 'preserves_safety' => $attribute->preservesSafety, + 'deprecation_info' => $attribute->deprecationInfo, + ]); + + if ($callable->getMinimalNumberOfRequiredArguments() > $method->getNumberOfParameters()) { + throw new \LogicException(sprintf('"%s::%s()" needs at least %d arguments to be used AsTwigFilter, but only %d defined.', $reflectionClass->getName(), $method->getName(), $callable->getMinimalNumberOfRequiredArguments(), $method->getNumberOfParameters())); + } + + $filters[$attribute->name] = $callable; + } + + foreach ($method->getAttributes(AsTwigFunction::class) as $reflectionAttribute) { + /** @var AsTwigFunction $attribute */ + $attribute = $reflectionAttribute->newInstance(); + + $callable = new TwigFunction($attribute->name, [$reflectionClass->name, $method->getName()], [ + 'needs_context' => $attribute->needsContext ?? false, + 'needs_environment' => $attribute->needsEnvironment ?? $this->needsEnvironment($method), + 'needs_charset' => $attribute->needsCharset ?? false, + 'is_variadic' => $method->isVariadic(), + 'is_safe' => $attribute->isSafe, + 'is_safe_callback' => $attribute->isSafeCallback, + 'deprecation_info' => $attribute->deprecationInfo, + ]); + + if ($callable->getMinimalNumberOfRequiredArguments() > $method->getNumberOfParameters()) { + throw new \LogicException(sprintf('"%s::%s()" needs at least %d arguments to be used AsTwigFunction, but only %d defined.', $reflectionClass->getName(), $method->getName(), $callable->getMinimalNumberOfRequiredArguments(), $method->getNumberOfParameters())); + } + + $functions[$attribute->name] = $callable; + } + + foreach ($method->getAttributes(AsTwigTest::class) as $reflectionAttribute) { + + /** @var AsTwigTest $attribute */ + $attribute = $reflectionAttribute->newInstance(); + + $callable = new TwigTest($attribute->name, [$reflectionClass->name, $method->getName()], [ + 'needs_context' => $attribute->needsContext ?? false, + 'needs_environment' => $attribute->needsEnvironment ?? $this->needsEnvironment($method), + 'needs_charset' => $attribute->needsCharset ?? false, + 'is_variadic' => $method->isVariadic(), + 'deprecation_info' => $attribute->deprecationInfo, + ]); + + if ($callable->getMinimalNumberOfRequiredArguments() > $method->getNumberOfParameters()) { + throw new \LogicException(sprintf('"%s::%s()" needs at least %d arguments to be used AsTwigTest, but only %d defined.', $reflectionClass->getName(), $method->getName(), $callable->getMinimalNumberOfRequiredArguments(), $method->getNumberOfParameters())); + } + + $tests[$attribute->name] = $callable; + } + } + + // Assign all at the end to avoid inconsistent state in case of exception + $this->filters = array_values($filters); + $this->functions = array_values($functions); + $this->tests = array_values($tests); + } + + /** + * Detect if the first argument of the method is the environment. + */ + private function needsEnvironment(\ReflectionFunctionAbstract $function): bool + { + if (!$parameters = $function->getParameters()) { + return false; + } + + return $parameters[0]->getType() instanceof \ReflectionNamedType + && Environment::class === $parameters[0]->getType()->getName() + && !$parameters[0]->isVariadic(); + } +} diff --git a/app/vendor/twig/twig/src/Extension/CoreExtension.php b/app/vendor/twig/twig/src/Extension/CoreExtension.php index a351f570a..f7e4250ae 100644 --- a/app/vendor/twig/twig/src/Extension/CoreExtension.php +++ b/app/vendor/twig/twig/src/Extension/CoreExtension.php @@ -16,7 +16,20 @@ use Twig\Error\LoaderError; use Twig\Error\RuntimeError; use Twig\Error\SyntaxError; -use Twig\ExpressionParser; +use Twig\ExpressionParser\Infix\ArrowExpressionParser; +use Twig\ExpressionParser\Infix\BinaryOperatorExpressionParser; +use Twig\ExpressionParser\Infix\ConditionalTernaryExpressionParser; +use Twig\ExpressionParser\Infix\DotExpressionParser; +use Twig\ExpressionParser\Infix\FilterExpressionParser; +use Twig\ExpressionParser\Infix\FunctionExpressionParser; +use Twig\ExpressionParser\Infix\IsExpressionParser; +use Twig\ExpressionParser\Infix\IsNotExpressionParser; +use Twig\ExpressionParser\Infix\SquareBracketExpressionParser; +use Twig\ExpressionParser\InfixAssociativity; +use Twig\ExpressionParser\PrecedenceChange; +use Twig\ExpressionParser\Prefix\GroupingExpressionParser; +use Twig\ExpressionParser\Prefix\LiteralExpressionParser; +use Twig\ExpressionParser\Prefix\UnaryOperatorExpressionParser; use Twig\Markup; use Twig\Node\Expression\AbstractExpression; use Twig\Node\Expression\Binary\AddBinary; @@ -63,11 +76,12 @@ use Twig\Node\Expression\Test\NullTest; use Twig\Node\Expression\Test\OddTest; use Twig\Node\Expression\Test\SameasTest; +use Twig\Node\Expression\Test\TrueTest; use Twig\Node\Expression\Unary\NegUnary; use Twig\Node\Expression\Unary\NotUnary; use Twig\Node\Expression\Unary\PosUnary; +use Twig\Node\Expression\Unary\SpreadUnary; use Twig\Node\Node; -use Twig\OperatorPrecedenceChange; use Twig\Parser; use Twig\Sandbox\SecurityNotAllowedMethodError; use Twig\Sandbox\SecurityNotAllowedPropertyError; @@ -305,6 +319,7 @@ public function getTests(): array new TwigTest('iterable', 'is_iterable'), new TwigTest('sequence', [self::class, 'testSequence']), new TwigTest('mapping', [self::class, 'testMapping']), + new TwigTest('true', null, ['node_class' => TrueTest::class]), ]; } @@ -313,50 +328,69 @@ public function getNodeVisitors(): array return []; } - public function getOperators(): array + public function getExpressionParsers(): array { return [ - [ - 'not' => ['precedence' => 50, 'precedence_change' => new OperatorPrecedenceChange('twig/twig', '3.15', 70), 'class' => NotUnary::class], - '-' => ['precedence' => 500, 'class' => NegUnary::class], - '+' => ['precedence' => 500, 'class' => PosUnary::class], - ], - [ - '? :' => ['precedence' => 5, 'class' => ElvisBinary::class, 'associativity' => ExpressionParser::OPERATOR_RIGHT], - '?:' => ['precedence' => 5, 'class' => ElvisBinary::class, 'associativity' => ExpressionParser::OPERATOR_RIGHT], - '??' => ['precedence' => 300, 'precedence_change' => new OperatorPrecedenceChange('twig/twig', '3.15', 5), 'class' => NullCoalesceBinary::class, 'associativity' => ExpressionParser::OPERATOR_RIGHT], - 'or' => ['precedence' => 10, 'class' => OrBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'xor' => ['precedence' => 12, 'class' => XorBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'and' => ['precedence' => 15, 'class' => AndBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'b-or' => ['precedence' => 16, 'class' => BitwiseOrBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'b-xor' => ['precedence' => 17, 'class' => BitwiseXorBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'b-and' => ['precedence' => 18, 'class' => BitwiseAndBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - '==' => ['precedence' => 20, 'class' => EqualBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - '!=' => ['precedence' => 20, 'class' => NotEqualBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - '<=>' => ['precedence' => 20, 'class' => SpaceshipBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - '<' => ['precedence' => 20, 'class' => LessBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - '>' => ['precedence' => 20, 'class' => GreaterBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - '>=' => ['precedence' => 20, 'class' => GreaterEqualBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - '<=' => ['precedence' => 20, 'class' => LessEqualBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'not in' => ['precedence' => 20, 'class' => NotInBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'in' => ['precedence' => 20, 'class' => InBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'matches' => ['precedence' => 20, 'class' => MatchesBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'starts with' => ['precedence' => 20, 'class' => StartsWithBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'ends with' => ['precedence' => 20, 'class' => EndsWithBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'has some' => ['precedence' => 20, 'class' => HasSomeBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'has every' => ['precedence' => 20, 'class' => HasEveryBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - '..' => ['precedence' => 25, 'class' => RangeBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - '+' => ['precedence' => 30, 'class' => AddBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - '-' => ['precedence' => 30, 'class' => SubBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - '~' => ['precedence' => 40, 'precedence_change' => new OperatorPrecedenceChange('twig/twig', '3.15', 27), 'class' => ConcatBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - '*' => ['precedence' => 60, 'class' => MulBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - '/' => ['precedence' => 60, 'class' => DivBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - '//' => ['precedence' => 60, 'class' => FloorDivBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - '%' => ['precedence' => 60, 'class' => ModBinary::class, 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'is' => ['precedence' => 100, 'associativity' => ExpressionParser::OPERATOR_LEFT], - 'is not' => ['precedence' => 100, 'associativity' => ExpressionParser::OPERATOR_LEFT], - '**' => ['precedence' => 200, 'class' => PowerBinary::class, 'associativity' => ExpressionParser::OPERATOR_RIGHT], - ], + // unary operators + new UnaryOperatorExpressionParser(NotUnary::class, 'not', 50, new PrecedenceChange('twig/twig', '3.15', 70)), + new UnaryOperatorExpressionParser(SpreadUnary::class, '...', 512, description: 'Spread operator'), + new UnaryOperatorExpressionParser(NegUnary::class, '-', 500), + new UnaryOperatorExpressionParser(PosUnary::class, '+', 500), + + // binary operators + new BinaryOperatorExpressionParser(ElvisBinary::class, '?:', 5, InfixAssociativity::Right, description: 'Elvis operator (a ?: b)', aliases: ['? :']), + new BinaryOperatorExpressionParser(NullCoalesceBinary::class, '??', 300, InfixAssociativity::Right, new PrecedenceChange('twig/twig', '3.15', 5), description: 'Null coalescing operator (a ?? b)'), + new BinaryOperatorExpressionParser(OrBinary::class, 'or', 10), + new BinaryOperatorExpressionParser(XorBinary::class, 'xor', 12), + new BinaryOperatorExpressionParser(AndBinary::class, 'and', 15), + new BinaryOperatorExpressionParser(BitwiseOrBinary::class, 'b-or', 16), + new BinaryOperatorExpressionParser(BitwiseXorBinary::class, 'b-xor', 17), + new BinaryOperatorExpressionParser(BitwiseAndBinary::class, 'b-and', 18), + new BinaryOperatorExpressionParser(EqualBinary::class, '==', 20), + new BinaryOperatorExpressionParser(NotEqualBinary::class, '!=', 20), + new BinaryOperatorExpressionParser(SpaceshipBinary::class, '<=>', 20), + new BinaryOperatorExpressionParser(LessBinary::class, '<', 20), + new BinaryOperatorExpressionParser(GreaterBinary::class, '>', 20), + new BinaryOperatorExpressionParser(GreaterEqualBinary::class, '>=', 20), + new BinaryOperatorExpressionParser(LessEqualBinary::class, '<=', 20), + new BinaryOperatorExpressionParser(NotInBinary::class, 'not in', 20), + new BinaryOperatorExpressionParser(InBinary::class, 'in', 20), + new BinaryOperatorExpressionParser(MatchesBinary::class, 'matches', 20), + new BinaryOperatorExpressionParser(StartsWithBinary::class, 'starts with', 20), + new BinaryOperatorExpressionParser(EndsWithBinary::class, 'ends with', 20), + new BinaryOperatorExpressionParser(HasSomeBinary::class, 'has some', 20), + new BinaryOperatorExpressionParser(HasEveryBinary::class, 'has every', 20), + new BinaryOperatorExpressionParser(RangeBinary::class, '..', 25), + new BinaryOperatorExpressionParser(AddBinary::class, '+', 30), + new BinaryOperatorExpressionParser(SubBinary::class, '-', 30), + new BinaryOperatorExpressionParser(ConcatBinary::class, '~', 40, precedenceChange: new PrecedenceChange('twig/twig', '3.15', 27)), + new BinaryOperatorExpressionParser(MulBinary::class, '*', 60), + new BinaryOperatorExpressionParser(DivBinary::class, '/', 60), + new BinaryOperatorExpressionParser(FloorDivBinary::class, '//', 60, description: 'Floor division'), + new BinaryOperatorExpressionParser(ModBinary::class, '%', 60), + new BinaryOperatorExpressionParser(PowerBinary::class, '**', 200, InfixAssociativity::Right, description: 'Exponentiation operator'), + + // ternary operator + new ConditionalTernaryExpressionParser(), + + // Twig callables + new IsExpressionParser(), + new IsNotExpressionParser(), + new FilterExpressionParser(), + new FunctionExpressionParser(), + + // get attribute operators + new DotExpressionParser(), + new SquareBracketExpressionParser(), + + // group expression + new GroupingExpressionParser(), + + // arrow function + new ArrowExpressionParser(), + + // all literals + new LiteralExpressionParser(), ]; } @@ -510,7 +544,6 @@ public function modifyDate($date, $modifier) * Returns a formatted string. * * @param string|null $format - * @param ...$values * * @internal */ @@ -969,8 +1002,6 @@ public static function reverse(string $charset, $item, $preserveKeys = false) * * @param array|\Traversable|string|null $item * - * @return mixed - * * @internal */ public static function shuffle(string $charset, $item) @@ -1405,8 +1436,6 @@ public static function testEmpty($value): bool * {# ... #} * {% endif %} * - * @param mixed $value - * * @internal */ public static function testSequence($value): bool @@ -1430,8 +1459,6 @@ public static function testSequence($value): bool * {# ... #} * {% endif %} * - * @param mixed $value - * * @internal */ public static function testMapping($value): bool @@ -1581,10 +1608,10 @@ public static function constant($constant, $object = null, bool $checkDefined = { if (null !== $object) { if ('class' === $constant) { - return $checkDefined ? true : \get_class($object); + return $checkDefined ? true : $object::class; } - $constant = \get_class($object).'::'.$constant; + $constant = $object::class.'::'.$constant; } if (!\defined($constant)) { @@ -1688,9 +1715,9 @@ public static function getAttribute(Environment $env, Source $source, $object, $ } if ($object instanceof \ArrayAccess) { - $message = \sprintf('Key "%s" in object with ArrayAccess of class "%s" does not exist.', $arrayItem, \get_class($object)); + $message = \sprintf('Key "%s" in object with ArrayAccess of class "%s" does not exist.', $arrayItem, $object::class); } elseif (\is_object($object)) { - $message = \sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface.', $item, \get_class($object)); + $message = \sprintf('Impossible to access a key "%s" on an object of class "%s" that does not implement ArrayAccess interface.', $item, $object::class); } elseif (\is_array($object)) { if (!$object) { $message = \sprintf('Key "%s" does not exist as the sequence/mapping is empty.', $arrayItem); @@ -1786,7 +1813,7 @@ public static function getAttribute(Environment $env, Source $source, $object, $ static $cache = []; - $class = \get_class($object); + $class = $object::class; // object method // precedence: getXxx() > isXxx() > hasXxx() @@ -1811,7 +1838,7 @@ public static function getAttribute(Environment $env, Source $source, $object, $ } elseif ('h' === $lcName[0] && str_starts_with($lcName, 'has')) { $name = substr($method, 3); $lcName = substr($lcName, 3); - if (\in_array('is'.$lcName, $lcMethods)) { + if (\in_array('is'.$lcName, $lcMethods, true)) { continue; } } else { diff --git a/app/vendor/twig/twig/src/Extension/ExtensionInterface.php b/app/vendor/twig/twig/src/Extension/ExtensionInterface.php index d51cd3ee2..44356f627 100644 --- a/app/vendor/twig/twig/src/Extension/ExtensionInterface.php +++ b/app/vendor/twig/twig/src/Extension/ExtensionInterface.php @@ -11,11 +11,9 @@ namespace Twig\Extension; -use Twig\ExpressionParser; -use Twig\Node\Expression\Binary\AbstractBinary; -use Twig\Node\Expression\Unary\AbstractUnary; +use Twig\ExpressionParser\ExpressionParserInterface; +use Twig\ExpressionParser\PrecedenceChange; use Twig\NodeVisitor\NodeVisitorInterface; -use Twig\OperatorPrecedenceChange; use Twig\TokenParser\TokenParserInterface; use Twig\TwigFilter; use Twig\TwigFunction; @@ -25,6 +23,8 @@ * Interface implemented by extension classes. * * @author Fabien Potencier + * + * @method array getExpressionParsers() */ interface ExtensionInterface { @@ -66,11 +66,11 @@ public function getFunctions(); /** * Returns a list of operators to add to the existing list. * - * @return array First array of unary operators, second array of binary operators + * @return array * * @psalm-return array{ - * array}>, - * array, associativity: ExpressionParser::OPERATOR_*}> + * array}>, + * array, associativity: ExpressionParser::OPERATOR_*}> * } */ public function getOperators(); diff --git a/app/vendor/twig/twig/src/Extension/SandboxExtension.php b/app/vendor/twig/twig/src/Extension/SandboxExtension.php index a9681c8d6..5d0f64443 100644 --- a/app/vendor/twig/twig/src/Extension/SandboxExtension.php +++ b/app/vendor/twig/twig/src/Extension/SandboxExtension.php @@ -118,10 +118,6 @@ public function checkPropertyAllowed($obj, $property, int $lineno = -1, ?Source } /** - * @param mixed $obj - * - * @return mixed - * * @throws SecurityNotAllowedMethodError */ public function ensureToStringAllowed($obj, int $lineno = -1, ?Source $source = null) diff --git a/app/vendor/twig/twig/src/ExtensionSet.php b/app/vendor/twig/twig/src/ExtensionSet.php index b069232b4..85a98cf3c 100644 --- a/app/vendor/twig/twig/src/ExtensionSet.php +++ b/app/vendor/twig/twig/src/ExtensionSet.php @@ -12,12 +12,18 @@ namespace Twig; use Twig\Error\RuntimeError; +use Twig\ExpressionParser\ExpressionParsers; +use Twig\ExpressionParser\Infix\BinaryOperatorExpressionParser; +use Twig\ExpressionParser\InfixAssociativity; +use Twig\ExpressionParser\InfixExpressionParserInterface; +use Twig\ExpressionParser\PrecedenceChange; +use Twig\ExpressionParser\Prefix\UnaryOperatorExpressionParser; +use Twig\Extension\AttributeExtension; use Twig\Extension\ExtensionInterface; use Twig\Extension\GlobalsInterface; use Twig\Extension\LastModifiedExtensionInterface; use Twig\Extension\StagingExtension; -use Twig\Node\Expression\Binary\AbstractBinary; -use Twig\Node\Expression\Unary\AbstractUnary; +use Twig\Node\Expression\AbstractExpression; use Twig\NodeVisitor\NodeVisitorInterface; use Twig\TokenParser\TokenParserInterface; @@ -46,10 +52,7 @@ final class ExtensionSet private $functions; /** @var array */ private $dynamicFunctions; - /** @var array}> */ - private $unaryOperators; - /** @var array, associativity: ExpressionParser::OPERATOR_*}> */ - private $binaryOperators; + private ExpressionParsers $expressionParsers; /** @var array|null */ private $globals; /** @var array */ @@ -140,7 +143,11 @@ public function getLastModified(): int public function addExtension(ExtensionInterface $extension): void { - $class = \get_class($extension); + if ($extension instanceof AttributeExtension) { + $class = $extension->getClass(); + } else { + $class = $extension::class; + } if ($this->initialized) { throw new \LogicException(\sprintf('Unable to register extension "%s" as extensions have already been initialized.', $class)); @@ -406,28 +413,13 @@ public function getTest(string $name): ?TwigTest return null; } - /** - * @return array}> - */ - public function getUnaryOperators(): array + public function getExpressionParsers(): ExpressionParsers { if (!$this->initialized) { $this->initExtensions(); } - return $this->unaryOperators; - } - - /** - * @return array, associativity: ExpressionParser::OPERATOR_*}> - */ - public function getBinaryOperators(): array - { - if (!$this->initialized) { - $this->initExtensions(); - } - - return $this->binaryOperators; + return $this->expressionParsers; } private function initExtensions(): void @@ -440,8 +432,7 @@ private function initExtensions(): void $this->dynamicFunctions = []; $this->dynamicTests = []; $this->visitors = []; - $this->unaryOperators = []; - $this->binaryOperators = []; + $this->expressionParsers = new ExpressionParsers(); foreach ($this->extensions as $extension) { $this->initExtension($extension); @@ -491,18 +482,66 @@ private function initExtension(ExtensionInterface $extension): void $this->visitors[] = $visitor; } - // operators - if ($operators = $extension->getOperators()) { - if (!\is_array($operators)) { - throw new \InvalidArgumentException(\sprintf('"%s::getOperators()" must return an array with operators, got "%s".', \get_class($extension), get_debug_type($operators).(\is_resource($operators) ? '' : '#'.$operators))); - } + // expression parsers + if (method_exists($extension, 'getExpressionParsers')) { + $this->expressionParsers->add($extension->getExpressionParsers()); + } + + $operators = $extension->getOperators(); + if (!\is_array($operators)) { + throw new \InvalidArgumentException(\sprintf('"%s::getOperators()" must return an array with operators, got "%s".', $extension::class, get_debug_type($operators).(\is_resource($operators) ? '' : '#'.$operators))); + } + + if (2 !== \count($operators)) { + throw new \InvalidArgumentException(\sprintf('"%s::getOperators()" must return an array of 2 elements, got %d.', $extension::class, \count($operators))); + } + + $expressionParsers = []; + foreach ($operators[0] as $operator => $op) { + $expressionParsers[] = new UnaryOperatorExpressionParser($op['class'], $operator, $op['precedence'], $op['precedence_change'] ?? null, '', $op['aliases'] ?? []); + } + foreach ($operators[1] as $operator => $op) { + $op['associativity'] = match ($op['associativity']) { + 1 => InfixAssociativity::Left, + 2 => InfixAssociativity::Right, + default => throw new \InvalidArgumentException(\sprintf('Invalid associativity "%s" for operator "%s".', $op['associativity'], $operator)), + }; - if (2 !== \count($operators)) { - throw new \InvalidArgumentException(\sprintf('"%s::getOperators()" must return an array of 2 elements, got %d.', \get_class($extension), \count($operators))); + if (isset($op['callable'])) { + $expressionParsers[] = $this->convertInfixExpressionParser($op['class'], $operator, $op['precedence'], $op['associativity'], $op['precedence_change'] ?? null, $op['aliases'] ?? [], $op['callable']); + } else { + $expressionParsers[] = new BinaryOperatorExpressionParser($op['class'], $operator, $op['precedence'], $op['associativity'], $op['precedence_change'] ?? null, '', $op['aliases'] ?? []); } + } + + if (\count($expressionParsers)) { + trigger_deprecation('twig/twig', '3.21', \sprintf('Extension "%s" uses the old signature for "getOperators()", please implement "getExpressionParsers()" instead.', $extension::class)); - $this->unaryOperators = array_merge($this->unaryOperators, $operators[0]); - $this->binaryOperators = array_merge($this->binaryOperators, $operators[1]); + $this->expressionParsers->add($expressionParsers); } } + + private function convertInfixExpressionParser(string $nodeClass, string $operator, int $precedence, InfixAssociativity $associativity, ?PrecedenceChange $precedenceChange, array $aliases, callable $callable): InfixExpressionParserInterface + { + trigger_deprecation('twig/twig', '3.21', \sprintf('Using a non-ExpressionParserInterface object to define the "%s" binary operator is deprecated.', $operator)); + + return new class($nodeClass, $operator, $precedence, $associativity, $precedenceChange, $aliases, $callable) extends BinaryOperatorExpressionParser { + public function __construct( + string $nodeClass, + string $operator, + int $precedence, + InfixAssociativity $associativity = InfixAssociativity::Left, + ?PrecedenceChange $precedenceChange = null, + array $aliases = [], + private $callable = null, + ) { + parent::__construct($nodeClass, $operator, $precedence, $associativity, $precedenceChange, $aliases); + } + + public function parse(Parser $parser, AbstractExpression $expr, Token $token): AbstractExpression + { + return ($this->callable)($parser, $expr); + } + }; + } } diff --git a/app/vendor/twig/twig/src/FileExtensionEscapingStrategy.php b/app/vendor/twig/twig/src/FileExtensionEscapingStrategy.php index 5308158d3..2785ab7f4 100644 --- a/app/vendor/twig/twig/src/FileExtensionEscapingStrategy.php +++ b/app/vendor/twig/twig/src/FileExtensionEscapingStrategy.php @@ -33,7 +33,7 @@ class FileExtensionEscapingStrategy */ public static function guess(string $name) { - if (\in_array(substr($name, -1), ['/', '\\'])) { + if (\in_array(substr($name, -1), ['/', '\\'], true)) { return 'html'; // return html for directories } diff --git a/app/vendor/twig/twig/src/Lexer.php b/app/vendor/twig/twig/src/Lexer.php index 929673c60..027771acc 100644 --- a/app/vendor/twig/twig/src/Lexer.php +++ b/app/vendor/twig/twig/src/Lexer.php @@ -36,6 +36,8 @@ class Lexer private $position; private $positions; private $currentVarBlockLine; + private array $openingBrackets = ['{', '(', '[']; + private array $closingBrackets = ['}', ')', ']']; public const STATE_DATA = 0; public const STATE_BLOCK = 1; @@ -332,19 +334,13 @@ private function lexExpression(): void } } - // spread operator - if ('.' === $this->code[$this->cursor] && ($this->cursor + 2 < $this->end) && '.' === $this->code[$this->cursor + 1] && '.' === $this->code[$this->cursor + 2]) { - $this->pushToken(Token::SPREAD_TYPE, '...'); - $this->moveCursor('...'); - } - // arrow function - elseif ('=' === $this->code[$this->cursor] && ($this->cursor + 1 < $this->end) && '>' === $this->code[$this->cursor + 1]) { - $this->pushToken(Token::ARROW_TYPE, '=>'); - $this->moveCursor('=>'); - } // operators - elseif (preg_match($this->regexes['operator'], $this->code, $match, 0, $this->cursor)) { - $this->pushToken(Token::OPERATOR_TYPE, preg_replace('/\s+/', ' ', $match[0])); + if (preg_match($this->regexes['operator'], $this->code, $match, 0, $this->cursor)) { + $operator = preg_replace('/\s+/', ' ', $match[0]); + if (\in_array($operator, $this->openingBrackets, true)) { + $this->checkBrackets($operator); + } + $this->pushToken(Token::OPERATOR_TYPE, $operator); $this->moveCursor($match[0]); } // names @@ -359,22 +355,7 @@ private function lexExpression(): void } // punctuation elseif (str_contains(self::PUNCTUATION, $this->code[$this->cursor])) { - // opening bracket - if (str_contains('([{', $this->code[$this->cursor])) { - $this->brackets[] = [$this->code[$this->cursor], $this->lineno]; - } - // closing bracket - elseif (str_contains(')]}', $this->code[$this->cursor])) { - if (!$this->brackets) { - throw new SyntaxError(\sprintf('Unexpected "%s".', $this->code[$this->cursor]), $this->lineno, $this->source); - } - - [$expect, $lineno] = array_pop($this->brackets); - if ($this->code[$this->cursor] != strtr($expect, '([{', ')]}')) { - throw new SyntaxError(\sprintf('Unclosed "%s".', $expect), $lineno, $this->source); - } - } - + $this->checkBrackets($this->code[$this->cursor]); $this->pushToken(Token::PUNCTUATION_TYPE, $this->code[$this->cursor]); ++$this->cursor; } @@ -544,26 +525,25 @@ private function moveCursor($text): void private function getOperatorRegex(): string { - $operators = array_merge( - ['='], - array_keys($this->env->getUnaryOperators()), - array_keys($this->env->getBinaryOperators()) - ); + $expressionParsers = ['=']; + foreach ($this->env->getExpressionParsers() as $expressionParser) { + $expressionParsers = array_merge($expressionParsers, [$expressionParser->getName()], $expressionParser->getAliases()); + } - $operators = array_combine($operators, array_map('strlen', $operators)); - arsort($operators); + $expressionParsers = array_combine($expressionParsers, array_map('strlen', $expressionParsers)); + arsort($expressionParsers); $regex = []; - foreach ($operators as $operator => $length) { + foreach ($expressionParsers as $expressionParser => $length) { // an operator that ends with a character must be followed by // a whitespace, a parenthesis, an opening map [ or sequence { - $r = preg_quote($operator, '/'); - if (ctype_alpha($operator[$length - 1])) { + $r = preg_quote($expressionParser, '/'); + if (ctype_alpha($expressionParser[$length - 1])) { $r .= '(?=[\s()\[{])'; } // an operator that begins with a character must not have a dot or pipe before - if (ctype_alpha($operator[0])) { + if (ctype_alpha($expressionParser[0])) { $r = '(?state = array_pop($this->states); } + + private function checkBrackets(string $code): void + { + // opening bracket + if (\in_array($code, $this->openingBrackets, true)) { + $this->brackets[] = [$code, $this->lineno]; + } elseif (\in_array($code, $this->closingBrackets, true)) { + // closing bracket + if (!$this->brackets) { + throw new SyntaxError(\sprintf('Unexpected "%s".', $code), $this->lineno, $this->source); + } + + [$expect, $lineno] = array_pop($this->brackets); + if ($code !== str_replace($this->openingBrackets, $this->closingBrackets, $expect)) { + throw new SyntaxError(\sprintf('Unclosed "%s".', $expect), $lineno, $this->source); + } + } + } } diff --git a/app/vendor/twig/twig/src/Loader/ChainLoader.php b/app/vendor/twig/twig/src/Loader/ChainLoader.php index 6e4f9511c..0859dcd2f 100644 --- a/app/vendor/twig/twig/src/Loader/ChainLoader.php +++ b/app/vendor/twig/twig/src/Loader/ChainLoader.php @@ -104,7 +104,7 @@ public function getCacheKey(string $name): string try { return $loader->getCacheKey($name); } catch (LoaderError $e) { - $exceptions[] = \get_class($loader).': '.$e->getMessage(); + $exceptions[] = $loader::class.': '.$e->getMessage(); } } @@ -123,7 +123,7 @@ public function isFresh(string $name, int $time): bool try { return $loader->isFresh($name, $time); } catch (LoaderError $e) { - $exceptions[] = \get_class($loader).': '.$e->getMessage(); + $exceptions[] = $loader::class.': '.$e->getMessage(); } } diff --git a/app/vendor/twig/twig/src/Node/EmbedNode.php b/app/vendor/twig/twig/src/Node/EmbedNode.php index 597f95e44..fe4365b57 100644 --- a/app/vendor/twig/twig/src/Node/EmbedNode.php +++ b/app/vendor/twig/twig/src/Node/EmbedNode.php @@ -36,11 +36,9 @@ public function __construct(string $name, int $index, ?AbstractExpression $varia protected function addGetTemplate(Compiler $compiler, string $template = ''): void { $compiler - ->raw('$this->loadTemplate(') + ->raw('$this->load(') ->string($this->getAttribute('name')) ->raw(', ') - ->repr($this->getTemplateName()) - ->raw(', ') ->repr($this->getTemplateLine()) ->raw(', ') ->string($this->getAttribute('index')) diff --git a/app/vendor/twig/twig/src/Node/Expression/ArrayExpression.php b/app/vendor/twig/twig/src/Node/Expression/ArrayExpression.php index 61a5063f3..b6f8a6ba4 100644 --- a/app/vendor/twig/twig/src/Node/Expression/ArrayExpression.php +++ b/app/vendor/twig/twig/src/Node/Expression/ArrayExpression.php @@ -12,11 +12,14 @@ namespace Twig\Node\Expression; use Twig\Compiler; +use Twig\Node\Expression\Unary\SpreadUnary; use Twig\Node\Expression\Unary\StringCastUnary; use Twig\Node\Expression\Variable\ContextVariable; -class ArrayExpression extends AbstractExpression +class ArrayExpression extends AbstractExpression implements SupportDefinedTestInterface, ReturnArrayInterface { + use SupportDefinedTestTrait; + private $index; public function __construct(array $elements, int $lineno) @@ -68,76 +71,42 @@ public function addElement(AbstractExpression $value, ?AbstractExpression $key = public function compile(Compiler $compiler): void { - $keyValuePairs = $this->getKeyValuePairs(); - $needsArrayMergeSpread = \PHP_VERSION_ID < 80100 && $this->hasSpreadItem($keyValuePairs); + if ($this->definedTest) { + $compiler->repr(true); - if ($needsArrayMergeSpread) { - $compiler->raw('CoreExtension::merge('); + return; } + $compiler->raw('['); - $first = true; - $reopenAfterMergeSpread = false; - $nextIndex = 0; - foreach ($keyValuePairs as $pair) { - if ($reopenAfterMergeSpread) { - $compiler->raw(', ['); - $reopenAfterMergeSpread = false; + $isSequence = true; + foreach ($this->getKeyValuePairs() as $i => $pair) { + if (0 !== $i) { + $compiler->raw(', '); } - if ($needsArrayMergeSpread && $pair['value']->hasAttribute('spread')) { - $compiler->raw('], ')->subcompile($pair['value']); - $first = true; - $reopenAfterMergeSpread = true; - continue; - } - if (!$first) { - $compiler->raw(', '); + $key = null; + if ($pair['key'] instanceof ContextVariable) { + $pair['key'] = new StringCastUnary($pair['key'], $pair['key']->getTemplateLine()); + } elseif ($pair['key'] instanceof TempNameExpression) { + $key = $pair['key']->getAttribute('name'); + $pair['key'] = new ConstantExpression($key, $pair['key']->getTemplateLine()); + } elseif ($pair['key'] instanceof ConstantExpression) { + $key = $pair['key']->getAttribute('value'); } - $first = false; - - if ($pair['value']->hasAttribute('spread') && !$needsArrayMergeSpread) { - $compiler->raw('...')->subcompile($pair['value']); - ++$nextIndex; - } else { - $key = null; - if ($pair['key'] instanceof ContextVariable) { - $pair['key'] = new StringCastUnary($pair['key'], $pair['key']->getTemplateLine()); - } - if ($pair['key'] instanceof TempNameExpression) { - $key = $pair['key']->getAttribute('name'); - $pair['key'] = new ConstantExpression($key, $pair['key']->getTemplateLine()); - } - if ($pair['key'] instanceof ConstantExpression) { - $key = $pair['key']->getAttribute('value'); - } - - if ($nextIndex !== $key) { - $compiler - ->subcompile($pair['key']) - ->raw(' => ') - ; - } - ++$nextIndex; - - $compiler->subcompile($pair['value']); + + if ($key !== $i) { + $isSequence = false; } - } - if (!$reopenAfterMergeSpread) { - $compiler->raw(']'); - } - if ($needsArrayMergeSpread) { - $compiler->raw(')'); - } - } - private function hasSpreadItem(array $pairs): bool - { - foreach ($pairs as $pair) { - if ($pair['value']->hasAttribute('spread')) { - return true; + if (!$isSequence && !$pair['value'] instanceof SpreadUnary) { + $compiler + ->subcompile($pair['key']) + ->raw(' => ') + ; } - } - return false; + $compiler->subcompile($pair['value']); + } + $compiler->raw(']'); } } diff --git a/app/vendor/twig/twig/src/Node/Expression/ArrowFunctionExpression.php b/app/vendor/twig/twig/src/Node/Expression/ArrowFunctionExpression.php index 2bae4edd7..552b8fe91 100644 --- a/app/vendor/twig/twig/src/Node/Expression/ArrowFunctionExpression.php +++ b/app/vendor/twig/twig/src/Node/Expression/ArrowFunctionExpression.php @@ -12,6 +12,9 @@ namespace Twig\Node\Expression; use Twig\Compiler; +use Twig\Error\SyntaxError; +use Twig\Node\Expression\Variable\AssignContextVariable; +use Twig\Node\Expression\Variable\ContextVariable; use Twig\Node\Node; /** @@ -23,6 +26,14 @@ class ArrowFunctionExpression extends AbstractExpression { public function __construct(AbstractExpression $expr, Node $names, $lineno) { + if (!$names instanceof ListExpression && !$names instanceof ContextVariable) { + throw new SyntaxError('The arrow function argument must be a list of variables or a single variable.', $names->getTemplateLine(), $names->getSourceContext()); + } + + if ($names instanceof ContextVariable) { + $names = new ListExpression([new AssignContextVariable($names->getAttribute('name'), $names->getTemplateLine())], $lineno); + } + parent::__construct(['expr' => $expr, 'names' => $names], [], $lineno); } @@ -31,19 +42,7 @@ public function compile(Compiler $compiler): void $compiler ->addDebugInfo($this) ->raw('function (') - ; - foreach ($this->getNode('names') as $i => $name) { - if ($i) { - $compiler->raw(', '); - } - - $compiler - ->raw('$__') - ->raw($name->getAttribute('name')) - ->raw('__') - ; - } - $compiler + ->subcompile($this->getNode('names')) ->raw(') use ($context, $macros) { ') ; foreach ($this->getNode('names') as $name) { diff --git a/app/vendor/twig/twig/src/Node/Expression/AssignNameExpression.php b/app/vendor/twig/twig/src/Node/Expression/AssignNameExpression.php index c194660da..9a7f0f92b 100644 --- a/app/vendor/twig/twig/src/Node/Expression/AssignNameExpression.php +++ b/app/vendor/twig/twig/src/Node/Expression/AssignNameExpression.php @@ -26,7 +26,7 @@ public function __construct(string $name, int $lineno) } // All names supported by ExpressionParser::parsePrimaryExpression() should be excluded - if (\in_array(strtolower($name), ['true', 'false', 'none', 'null'])) { + if (\in_array(strtolower($name), ['true', 'false', 'none', 'null'], true)) { throw new SyntaxError(\sprintf('You cannot assign a value to "%s".', $name), $lineno); } diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/AbstractBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/AbstractBinary.php index bd6cc6c02..b4bf6662e 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/AbstractBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/AbstractBinary.php @@ -25,10 +25,10 @@ abstract class AbstractBinary extends AbstractExpression implements BinaryInterf public function __construct(Node $left, Node $right, int $lineno) { if (!$left instanceof AbstractExpression) { - trigger_deprecation('twig/twig', '3.15', 'Not passing a "%s" instance to the "left" argument of "%s" is deprecated ("%s" given).', AbstractExpression::class, static::class, \get_class($left)); + trigger_deprecation('twig/twig', '3.15', 'Not passing a "%s" instance to the "left" argument of "%s" is deprecated ("%s" given).', AbstractExpression::class, static::class, $left::class); } if (!$right instanceof AbstractExpression) { - trigger_deprecation('twig/twig', '3.15', 'Not passing a "%s" instance to the "right" argument of "%s" is deprecated ("%s" given).', AbstractExpression::class, static::class, \get_class($right)); + trigger_deprecation('twig/twig', '3.15', 'Not passing a "%s" instance to the "right" argument of "%s" is deprecated ("%s" given).', AbstractExpression::class, static::class, $right::class); } parent::__construct(['left' => $left, 'right' => $right], [], $lineno); diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/AddBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/AddBinary.php index ee4307e33..42377aea0 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/AddBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/AddBinary.php @@ -13,8 +13,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnNumberInterface; -class AddBinary extends AbstractBinary +class AddBinary extends AbstractBinary implements ReturnNumberInterface { public function operator(Compiler $compiler): Compiler { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/AndBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/AndBinary.php index 5f2380da5..454ea70e5 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/AndBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/AndBinary.php @@ -13,8 +13,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnBoolInterface; -class AndBinary extends AbstractBinary +class AndBinary extends AbstractBinary implements ReturnBoolInterface { public function operator(Compiler $compiler): Compiler { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/BitwiseAndBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/BitwiseAndBinary.php index db7d6d612..1c26f9893 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/BitwiseAndBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/BitwiseAndBinary.php @@ -13,8 +13,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnNumberInterface; -class BitwiseAndBinary extends AbstractBinary +class BitwiseAndBinary extends AbstractBinary implements ReturnNumberInterface { public function operator(Compiler $compiler): Compiler { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/BitwiseOrBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/BitwiseOrBinary.php index ce803dd90..ec17e2280 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/BitwiseOrBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/BitwiseOrBinary.php @@ -13,8 +13,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnNumberInterface; -class BitwiseOrBinary extends AbstractBinary +class BitwiseOrBinary extends AbstractBinary implements ReturnNumberInterface { public function operator(Compiler $compiler): Compiler { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/BitwiseXorBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/BitwiseXorBinary.php index 5c2978501..e6432a7ae 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/BitwiseXorBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/BitwiseXorBinary.php @@ -13,8 +13,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnNumberInterface; -class BitwiseXorBinary extends AbstractBinary +class BitwiseXorBinary extends AbstractBinary implements ReturnNumberInterface { public function operator(Compiler $compiler): Compiler { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/ConcatBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/ConcatBinary.php index f825ab874..75ee65473 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/ConcatBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/ConcatBinary.php @@ -13,8 +13,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnStringInterface; -class ConcatBinary extends AbstractBinary +class ConcatBinary extends AbstractBinary implements ReturnStringInterface { public function operator(Compiler $compiler): Compiler { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/DivBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/DivBinary.php index e3817d1cd..11c061e18 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/DivBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/DivBinary.php @@ -13,8 +13,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnNumberInterface; -class DivBinary extends AbstractBinary +class DivBinary extends AbstractBinary implements ReturnNumberInterface { public function operator(Compiler $compiler): Compiler { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/EndsWithBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/EndsWithBinary.php index a73a5608d..e689d668a 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/EndsWithBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/EndsWithBinary.php @@ -12,8 +12,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnBoolInterface; -class EndsWithBinary extends AbstractBinary +class EndsWithBinary extends AbstractBinary implements ReturnBoolInterface { public function compile(Compiler $compiler): void { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/EqualBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/EqualBinary.php index 5f423196f..8c3650355 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/EqualBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/EqualBinary.php @@ -12,8 +12,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnBoolInterface; -class EqualBinary extends AbstractBinary +class EqualBinary extends AbstractBinary implements ReturnBoolInterface { public function compile(Compiler $compiler): void { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/FloorDivBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/FloorDivBinary.php index d7e7980ef..a60ab3b21 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/FloorDivBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/FloorDivBinary.php @@ -12,8 +12,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnNumberInterface; -class FloorDivBinary extends AbstractBinary +class FloorDivBinary extends AbstractBinary implements ReturnNumberInterface { public function compile(Compiler $compiler): void { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/GreaterBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/GreaterBinary.php index f42de3f86..71a980b3e 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/GreaterBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/GreaterBinary.php @@ -12,8 +12,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnBoolInterface; -class GreaterBinary extends AbstractBinary +class GreaterBinary extends AbstractBinary implements ReturnBoolInterface { public function compile(Compiler $compiler): void { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/GreaterEqualBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/GreaterEqualBinary.php index 0c4f43fd9..c92e61b37 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/GreaterEqualBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/GreaterEqualBinary.php @@ -12,8 +12,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnBoolInterface; -class GreaterEqualBinary extends AbstractBinary +class GreaterEqualBinary extends AbstractBinary implements ReturnBoolInterface { public function compile(Compiler $compiler): void { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/HasEveryBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/HasEveryBinary.php index c57bb20e9..22b380118 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/HasEveryBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/HasEveryBinary.php @@ -12,8 +12,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnBoolInterface; -class HasEveryBinary extends AbstractBinary +class HasEveryBinary extends AbstractBinary implements ReturnBoolInterface { public function compile(Compiler $compiler): void { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/HasSomeBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/HasSomeBinary.php index 12293f84c..a2a363e99 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/HasSomeBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/HasSomeBinary.php @@ -12,8 +12,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnBoolInterface; -class HasSomeBinary extends AbstractBinary +class HasSomeBinary extends AbstractBinary implements ReturnBoolInterface { public function compile(Compiler $compiler): void { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/InBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/InBinary.php index 68a98fe15..31a21e7d6 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/InBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/InBinary.php @@ -12,8 +12,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnBoolInterface; -class InBinary extends AbstractBinary +class InBinary extends AbstractBinary implements ReturnBoolInterface { public function compile(Compiler $compiler): void { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/LessBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/LessBinary.php index fb3264a2d..293d98d51 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/LessBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/LessBinary.php @@ -12,8 +12,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnBoolInterface; -class LessBinary extends AbstractBinary +class LessBinary extends AbstractBinary implements ReturnBoolInterface { public function compile(Compiler $compiler): void { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/LessEqualBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/LessEqualBinary.php index 8f3653892..239d9fdfe 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/LessEqualBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/LessEqualBinary.php @@ -12,8 +12,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnBoolInterface; -class LessEqualBinary extends AbstractBinary +class LessEqualBinary extends AbstractBinary implements ReturnBoolInterface { public function compile(Compiler $compiler): void { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/MatchesBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/MatchesBinary.php index 0a523c216..32e8d34e4 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/MatchesBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/MatchesBinary.php @@ -13,10 +13,11 @@ use Twig\Compiler; use Twig\Error\SyntaxError; +use Twig\Node\Expression\ReturnBoolInterface; use Twig\Node\Expression\ConstantExpression; use Twig\Node\Node; -class MatchesBinary extends AbstractBinary +class MatchesBinary extends AbstractBinary implements ReturnBoolInterface { public function __construct(Node $left, Node $right, int $lineno) { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/ModBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/ModBinary.php index 271b45cac..aef48f3d0 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/ModBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/ModBinary.php @@ -13,8 +13,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnNumberInterface; -class ModBinary extends AbstractBinary +class ModBinary extends AbstractBinary implements ReturnNumberInterface { public function operator(Compiler $compiler): Compiler { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/MulBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/MulBinary.php index 6d4c1e0b6..beb881ae3 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/MulBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/MulBinary.php @@ -13,8 +13,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnNumberInterface; -class MulBinary extends AbstractBinary +class MulBinary extends AbstractBinary implements ReturnNumberInterface { public function operator(Compiler $compiler): Compiler { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/NotEqualBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/NotEqualBinary.php index d137ef627..fd24ef911 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/NotEqualBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/NotEqualBinary.php @@ -12,8 +12,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnBoolInterface; -class NotEqualBinary extends AbstractBinary +class NotEqualBinary extends AbstractBinary implements ReturnBoolInterface { public function compile(Compiler $compiler): void { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/NotInBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/NotInBinary.php index 80c8755d8..9fd27311f 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/NotInBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/NotInBinary.php @@ -12,8 +12,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnBoolInterface; -class NotInBinary extends AbstractBinary +class NotInBinary extends AbstractBinary implements ReturnBoolInterface { public function compile(Compiler $compiler): void { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/OrBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/OrBinary.php index 21f87c91b..82dcb7e95 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/OrBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/OrBinary.php @@ -13,8 +13,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnBoolInterface; -class OrBinary extends AbstractBinary +class OrBinary extends AbstractBinary implements ReturnBoolInterface { public function operator(Compiler $compiler): Compiler { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/PowerBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/PowerBinary.php index c9f4c6697..5325e8eb0 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/PowerBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/PowerBinary.php @@ -12,8 +12,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnNumberInterface; -class PowerBinary extends AbstractBinary +class PowerBinary extends AbstractBinary implements ReturnNumberInterface { public function operator(Compiler $compiler): Compiler { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/RangeBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/RangeBinary.php index 55982c819..f318d8e55 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/RangeBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/RangeBinary.php @@ -12,8 +12,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnArrayInterface; -class RangeBinary extends AbstractBinary +class RangeBinary extends AbstractBinary implements ReturnArrayInterface { public function compile(Compiler $compiler): void { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/SpaceshipBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/SpaceshipBinary.php index ae5a4a493..c0a28b0a8 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/SpaceshipBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/SpaceshipBinary.php @@ -12,8 +12,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnNumberInterface; -class SpaceshipBinary extends AbstractBinary +class SpaceshipBinary extends AbstractBinary implements ReturnNumberInterface { public function operator(Compiler $compiler): Compiler { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/StartsWithBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/StartsWithBinary.php index 4519f30d9..ef2fc9502 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/StartsWithBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/StartsWithBinary.php @@ -12,8 +12,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnBoolInterface; -class StartsWithBinary extends AbstractBinary +class StartsWithBinary extends AbstractBinary implements ReturnBoolInterface { public function compile(Compiler $compiler): void { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/SubBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/SubBinary.php index eeb87faca..10663f5c1 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/SubBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/SubBinary.php @@ -13,8 +13,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnNumberInterface; -class SubBinary extends AbstractBinary +class SubBinary extends AbstractBinary implements ReturnNumberInterface { public function operator(Compiler $compiler): Compiler { diff --git a/app/vendor/twig/twig/src/Node/Expression/Binary/XorBinary.php b/app/vendor/twig/twig/src/Node/Expression/Binary/XorBinary.php index d8ccd7853..6f412d22f 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Binary/XorBinary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Binary/XorBinary.php @@ -13,8 +13,9 @@ namespace Twig\Node\Expression\Binary; use Twig\Compiler; +use Twig\Node\Expression\ReturnBoolInterface; -class XorBinary extends AbstractBinary +class XorBinary extends AbstractBinary implements ReturnBoolInterface { public function operator(Compiler $compiler): Compiler { diff --git a/app/vendor/twig/twig/src/Node/Expression/BlockReferenceExpression.php b/app/vendor/twig/twig/src/Node/Expression/BlockReferenceExpression.php index a5a3cee3f..cb7d38c57 100644 --- a/app/vendor/twig/twig/src/Node/Expression/BlockReferenceExpression.php +++ b/app/vendor/twig/twig/src/Node/Expression/BlockReferenceExpression.php @@ -20,15 +20,18 @@ * * @author Fabien Potencier */ -class BlockReferenceExpression extends AbstractExpression +class BlockReferenceExpression extends AbstractExpression implements SupportDefinedTestInterface { + use SupportDefinedTestDeprecationTrait; + use SupportDefinedTestTrait; + /** * @param AbstractExpression $name */ public function __construct(Node $name, ?Node $template, int $lineno) { if (!$name instanceof AbstractExpression) { - trigger_deprecation('twig/twig', '3.15', 'Not passing a "%s" instance to the "node" argument of "%s" is deprecated ("%s" given).', AbstractExpression::class, static::class, \get_class($name)); + trigger_deprecation('twig/twig', '3.15', 'Not passing a "%s" instance to the "node" argument of "%s" is deprecated ("%s" given).', AbstractExpression::class, static::class, $name::class); } $nodes = ['name' => $name]; @@ -36,12 +39,12 @@ public function __construct(Node $name, ?Node $template, int $lineno) $nodes['template'] = $template; } - parent::__construct($nodes, ['is_defined_test' => false, 'output' => false], $lineno); + parent::__construct($nodes, ['output' => false], $lineno); } public function compile(Compiler $compiler): void { - if ($this->getAttribute('is_defined_test')) { + if ($this->definedTest) { $this->compileTemplateCall($compiler, 'hasBlock'); } else { if ($this->getAttribute('output')) { @@ -63,11 +66,9 @@ private function compileTemplateCall(Compiler $compiler, string $method): Compil $compiler->write('$this'); } else { $compiler - ->write('$this->loadTemplate(') + ->write('$this->load(') ->subcompile($this->getNode('template')) ->raw(', ') - ->repr($this->getTemplateName()) - ->raw(', ') ->repr($this->getTemplateLine()) ->raw(')') ; diff --git a/app/vendor/twig/twig/src/Node/Expression/ConstantExpression.php b/app/vendor/twig/twig/src/Node/Expression/ConstantExpression.php index 2a8909d54..12dc0621f 100644 --- a/app/vendor/twig/twig/src/Node/Expression/ConstantExpression.php +++ b/app/vendor/twig/twig/src/Node/Expression/ConstantExpression.php @@ -17,8 +17,10 @@ /** * @final */ -class ConstantExpression extends AbstractExpression +class ConstantExpression extends AbstractExpression implements SupportDefinedTestInterface, ReturnPrimitiveTypeInterface { + use SupportDefinedTestTrait; + public function __construct($value, int $lineno) { parent::__construct([], ['value' => $value], $lineno); @@ -26,6 +28,6 @@ public function __construct($value, int $lineno) public function compile(Compiler $compiler): void { - $compiler->repr($this->getAttribute('value')); + $compiler->repr($this->definedTest ? true : $this->getAttribute('value')); } } diff --git a/app/vendor/twig/twig/src/Node/Expression/Filter/DefaultFilter.php b/app/vendor/twig/twig/src/Node/Expression/Filter/DefaultFilter.php index bccd7f0a4..04ef06cc4 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Filter/DefaultFilter.php +++ b/app/vendor/twig/twig/src/Node/Expression/Filter/DefaultFilter.php @@ -42,7 +42,7 @@ class DefaultFilter extends FilterExpression public function __construct(Node $node, TwigFilter|ConstantExpression $filter, Node $arguments, int $lineno) { if (!$node instanceof AbstractExpression) { - trigger_deprecation('twig/twig', '3.15', 'Not passing a "%s" instance to the "node" argument of "%s" is deprecated ("%s" given).', AbstractExpression::class, static::class, \get_class($node)); + trigger_deprecation('twig/twig', '3.15', 'Not passing a "%s" instance to the "node" argument of "%s" is deprecated ("%s" given).', AbstractExpression::class, static::class, $node::class); } if ($filter instanceof TwigFilter) { diff --git a/app/vendor/twig/twig/src/Node/Expression/Filter/RawFilter.php b/app/vendor/twig/twig/src/Node/Expression/Filter/RawFilter.php index 0a49e7c4f..707e8ec24 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Filter/RawFilter.php +++ b/app/vendor/twig/twig/src/Node/Expression/Filter/RawFilter.php @@ -32,7 +32,7 @@ class RawFilter extends FilterExpression public function __construct(Node $node, TwigFilter|ConstantExpression|null $filter = null, ?Node $arguments = null, int $lineno = 0) { if (!$node instanceof AbstractExpression) { - trigger_deprecation('twig/twig', '3.15', 'Not passing a "%s" instance to the "node" argument of "%s" is deprecated ("%s" given).', AbstractExpression::class, static::class, \get_class($node)); + trigger_deprecation('twig/twig', '3.15', 'Not passing a "%s" instance to the "node" argument of "%s" is deprecated ("%s" given).', AbstractExpression::class, static::class, $node::class); } parent::__construct($node, $filter ?: new TwigFilter('raw', null, ['is_safe' => ['all']]), $arguments ?: new EmptyNode(), $lineno ?: $node->getTemplateLine()); diff --git a/app/vendor/twig/twig/src/Node/Expression/FilterExpression.php b/app/vendor/twig/twig/src/Node/Expression/FilterExpression.php index 6e0c486ab..a66b0266d 100644 --- a/app/vendor/twig/twig/src/Node/Expression/FilterExpression.php +++ b/app/vendor/twig/twig/src/Node/Expression/FilterExpression.php @@ -27,7 +27,7 @@ class FilterExpression extends CallExpression public function __construct(Node $node, TwigFilter|ConstantExpression $filter, Node $arguments, int $lineno) { if (!$node instanceof AbstractExpression) { - trigger_deprecation('twig/twig', '3.15', 'Not passing a "%s" instance to the "node" argument of "%s" is deprecated ("%s" given).', AbstractExpression::class, static::class, \get_class($node)); + trigger_deprecation('twig/twig', '3.15', 'Not passing a "%s" instance to the "node" argument of "%s" is deprecated ("%s" given).', AbstractExpression::class, static::class, $node::class); } if ($filter instanceof TwigFilter) { diff --git a/app/vendor/twig/twig/src/Node/Expression/FunctionExpression.php b/app/vendor/twig/twig/src/Node/Expression/FunctionExpression.php index 5e22e73e8..183145c41 100644 --- a/app/vendor/twig/twig/src/Node/Expression/FunctionExpression.php +++ b/app/vendor/twig/twig/src/Node/Expression/FunctionExpression.php @@ -17,8 +17,11 @@ use Twig\Node\Node; use Twig\TwigFunction; -class FunctionExpression extends CallExpression +class FunctionExpression extends CallExpression implements SupportDefinedTestInterface { + use SupportDefinedTestDeprecationTrait; + use SupportDefinedTestTrait; + #[FirstClassTwigCallableReady] public function __construct(TwigFunction|string $function, Node $arguments, int $lineno) { @@ -29,7 +32,7 @@ public function __construct(TwigFunction|string $function, Node $arguments, int trigger_deprecation('twig/twig', '3.12', 'Not passing an instance of "TwigFunction" when creating a "%s" function of type "%s" is deprecated.', $name, static::class); } - parent::__construct(['arguments' => $arguments], ['name' => $name, 'type' => 'function', 'is_defined_test' => false], $lineno); + parent::__construct(['arguments' => $arguments], ['name' => $name, 'type' => 'function'], $lineno); if ($function instanceof TwigFunction) { $this->setAttribute('twig_callable', $function); @@ -44,6 +47,13 @@ public function __construct(TwigFunction|string $function, Node $arguments, int $this->deprecateAttribute('dynamic_name', new NameDeprecation('twig/twig', '3.12')); } + public function enableDefinedTest(): void + { + if ('constant' === $this->getAttribute('name')) { + $this->definedTest = true; + } + } + /** * @return void */ @@ -62,7 +72,7 @@ public function compile(Compiler $compiler) $this->setAttribute('twig_callable', $compiler->getEnvironment()->getFunction($name)); } - if ('constant' === $name && $this->getAttribute('is_defined_test')) { + if ('constant' === $name && $this->isDefinedTestEnabled()) { $this->getNode('arguments')->setNode('checkDefined', new ConstantExpression(true, $this->getTemplateLine())); } diff --git a/app/vendor/twig/twig/src/Node/Expression/GetAttrExpression.php b/app/vendor/twig/twig/src/Node/Expression/GetAttrExpression.php index e072f2a0b..781c8af38 100644 --- a/app/vendor/twig/twig/src/Node/Expression/GetAttrExpression.php +++ b/app/vendor/twig/twig/src/Node/Expression/GetAttrExpression.php @@ -17,8 +17,11 @@ use Twig\Node\Expression\Variable\ContextVariable; use Twig\Template; -class GetAttrExpression extends AbstractExpression +class GetAttrExpression extends AbstractExpression implements SupportDefinedTestInterface { + use SupportDefinedTestDeprecationTrait; + use SupportDefinedTestTrait; + /** * @param ArrayExpression|NameExpression|null $arguments */ @@ -33,7 +36,13 @@ public function __construct(AbstractExpression $node, AbstractExpression $attrib trigger_deprecation('twig/twig', '3.15', \sprintf('Not passing a "%s" instance as the "arguments" argument of the "%s" constructor is deprecated ("%s" given).', ArrayExpression::class, static::class, $arguments::class)); } - parent::__construct($nodes, ['type' => $type, 'is_defined_test' => false, 'ignore_strict_check' => false, 'optimizable' => true], $lineno); + parent::__construct($nodes, ['type' => $type, 'ignore_strict_check' => false, 'optimizable' => true], $lineno); + } + + public function enableDefinedTest(): void + { + $this->definedTest = true; + $this->changeIgnoreStrictCheck($this); } public function compile(Compiler $compiler): void @@ -45,7 +54,7 @@ public function compile(Compiler $compiler): void if ( $this->getAttribute('optimizable') && (!$env->isStrictVariables() || $this->getAttribute('ignore_strict_check')) - && !$this->getAttribute('is_defined_test') + && !$this->definedTest && Template::ARRAY_CALL === $this->getAttribute('type') ) { $var = '$'.$compiler->getVarName(); @@ -104,7 +113,7 @@ public function compile(Compiler $compiler): void $compiler->raw(', ') ->repr($this->getAttribute('type')) - ->raw(', ')->repr($this->getAttribute('is_defined_test')) + ->raw(', ')->repr($this->definedTest) ->raw(', ')->repr($this->getAttribute('ignore_strict_check')) ->raw(', ')->repr($env->hasExtension(SandboxExtension::class)) ->raw(', ')->repr($this->getNode('node')->getTemplateLine()) @@ -115,4 +124,14 @@ public function compile(Compiler $compiler): void $compiler->raw(')'); } } + + private function changeIgnoreStrictCheck(GetAttrExpression $node): void + { + $node->setAttribute('optimizable', false); + $node->setAttribute('ignore_strict_check', true); + + if ($node->getNode('node') instanceof GetAttrExpression) { + $this->changeIgnoreStrictCheck($node->getNode('node')); + } + } } diff --git a/app/vendor/twig/twig/src/Node/Expression/ListExpression.php b/app/vendor/twig/twig/src/Node/Expression/ListExpression.php new file mode 100644 index 000000000..dd7fc1f9c --- /dev/null +++ b/app/vendor/twig/twig/src/Node/Expression/ListExpression.php @@ -0,0 +1,41 @@ + $items + */ + public function __construct(array $items, int $lineno) + { + parent::__construct($items, [], $lineno); + } + + public function compile(Compiler $compiler): void + { + foreach ($this as $i => $name) { + if ($i) { + $compiler->raw(', '); + } + + $compiler + ->raw('$__') + ->raw($name->getAttribute('name')) + ->raw('__') + ; + } + } +} diff --git a/app/vendor/twig/twig/src/Node/Expression/MacroReferenceExpression.php b/app/vendor/twig/twig/src/Node/Expression/MacroReferenceExpression.php index abe99aa35..fd7f1e733 100644 --- a/app/vendor/twig/twig/src/Node/Expression/MacroReferenceExpression.php +++ b/app/vendor/twig/twig/src/Node/Expression/MacroReferenceExpression.php @@ -19,16 +19,19 @@ * * @author Fabien Potencier */ -class MacroReferenceExpression extends AbstractExpression +class MacroReferenceExpression extends AbstractExpression implements SupportDefinedTestInterface { + use SupportDefinedTestDeprecationTrait; + use SupportDefinedTestTrait; + public function __construct(TemplateVariable $template, string $name, AbstractExpression $arguments, int $lineno) { - parent::__construct(['template' => $template, 'arguments' => $arguments], ['name' => $name, 'is_defined_test' => false], $lineno); + parent::__construct(['template' => $template, 'arguments' => $arguments], ['name' => $name], $lineno); } public function compile(Compiler $compiler): void { - if ($this->getAttribute('is_defined_test')) { + if ($this->definedTest) { $compiler ->subcompile($this->getNode('template')) ->raw('->hasMacro(') diff --git a/app/vendor/twig/twig/src/Node/Expression/MethodCallExpression.php b/app/vendor/twig/twig/src/Node/Expression/MethodCallExpression.php index 922b98b10..4b180534d 100644 --- a/app/vendor/twig/twig/src/Node/Expression/MethodCallExpression.php +++ b/app/vendor/twig/twig/src/Node/Expression/MethodCallExpression.php @@ -14,13 +14,16 @@ use Twig\Compiler; use Twig\Node\Expression\Variable\ContextVariable; -class MethodCallExpression extends AbstractExpression +class MethodCallExpression extends AbstractExpression implements SupportDefinedTestInterface { + use SupportDefinedTestDeprecationTrait; + use SupportDefinedTestTrait; + public function __construct(AbstractExpression $node, string $method, ArrayExpression $arguments, int $lineno) { trigger_deprecation('twig/twig', '3.15', 'The "%s" class is deprecated, use "%s" instead.', __CLASS__, MacroReferenceExpression::class); - parent::__construct(['node' => $node, 'arguments' => $arguments], ['method' => $method, 'safe' => false, 'is_defined_test' => false], $lineno); + parent::__construct(['node' => $node, 'arguments' => $arguments], ['method' => $method, 'safe' => false], $lineno); if ($node instanceof ContextVariable) { $node->setAttribute('always_defined', true); @@ -29,7 +32,7 @@ public function __construct(AbstractExpression $node, string $method, ArrayExpre public function compile(Compiler $compiler): void { - if ($this->getAttribute('is_defined_test')) { + if ($this->definedTest) { $compiler ->raw('method_exists($macros[') ->repr($this->getNode('node')->getAttribute('name')) diff --git a/app/vendor/twig/twig/src/Node/Expression/NameExpression.php b/app/vendor/twig/twig/src/Node/Expression/NameExpression.php index 2872ba413..0e0367420 100644 --- a/app/vendor/twig/twig/src/Node/Expression/NameExpression.php +++ b/app/vendor/twig/twig/src/Node/Expression/NameExpression.php @@ -15,8 +15,11 @@ use Twig\Compiler; use Twig\Node\Expression\Variable\ContextVariable; -class NameExpression extends AbstractExpression +class NameExpression extends AbstractExpression implements SupportDefinedTestInterface { + use SupportDefinedTestDeprecationTrait; + use SupportDefinedTestTrait; + private $specialVars = [ '_self' => '$this->getTemplateName()', '_context' => '$context', @@ -29,7 +32,7 @@ public function __construct(string $name, int $lineno) trigger_deprecation('twig/twig', '3.15', 'The "%s" class is deprecated, use "%s" instead.', self::class, ContextVariable::class); } - parent::__construct([], ['name' => $name, 'is_defined_test' => false, 'ignore_strict_check' => false, 'always_defined' => false], $lineno); + parent::__construct([], ['name' => $name, 'ignore_strict_check' => false, 'always_defined' => false], $lineno); } public function compile(Compiler $compiler): void @@ -38,7 +41,7 @@ public function compile(Compiler $compiler): void $compiler->addDebugInfo($this); - if ($this->getAttribute('is_defined_test')) { + if ($this->definedTest) { if (isset($this->specialVars[$name]) || $this->getAttribute('always_defined')) { $compiler->repr(true); } elseif (\PHP_VERSION_ID >= 70400) { @@ -107,6 +110,6 @@ public function isSimple() { trigger_deprecation('twig/twig', '3.11', 'The "%s()" method is deprecated and will be removed in Twig 4.0.', __METHOD__); - return !$this->isSpecial() && !$this->getAttribute('is_defined_test'); + return !isset($this->specialVars[$this->getAttribute('name')]) && !$this->definedTest; } } diff --git a/app/vendor/twig/twig/src/Node/Expression/NullCoalesceExpression.php b/app/vendor/twig/twig/src/Node/Expression/NullCoalesceExpression.php index 74ddaf791..f397f71f0 100644 --- a/app/vendor/twig/twig/src/Node/Expression/NullCoalesceExpression.php +++ b/app/vendor/twig/twig/src/Node/Expression/NullCoalesceExpression.php @@ -33,10 +33,10 @@ public function __construct(Node $left, Node $right, int $lineno) trigger_deprecation('twig/twig', '3.17', \sprintf('"%s" is deprecated; use "%s" instead.', __CLASS__, NullCoalesceBinary::class)); if (!$left instanceof AbstractExpression) { - trigger_deprecation('twig/twig', '3.15', 'Not passing a "%s" instance to the "left" argument of "%s" is deprecated ("%s" given).', AbstractExpression::class, static::class, \get_class($left)); + trigger_deprecation('twig/twig', '3.15', 'Not passing a "%s" instance to the "left" argument of "%s" is deprecated ("%s" given).', AbstractExpression::class, static::class, $left::class); } if (!$right instanceof AbstractExpression) { - trigger_deprecation('twig/twig', '3.15', 'Not passing a "%s" instance to the "right" argument of "%s" is deprecated ("%s" given).', AbstractExpression::class, static::class, \get_class($right)); + trigger_deprecation('twig/twig', '3.15', 'Not passing a "%s" instance to the "right" argument of "%s" is deprecated ("%s" given).', AbstractExpression::class, static::class, $right::class); } $test = new DefinedTest(clone $left, new TwigTest('defined'), new EmptyNode(), $left->getTemplateLine()); diff --git a/app/vendor/twig/twig/src/Node/Expression/ReturnArrayInterface.php b/app/vendor/twig/twig/src/Node/Expression/ReturnArrayInterface.php new file mode 100644 index 000000000..a74864b5d --- /dev/null +++ b/app/vendor/twig/twig/src/Node/Expression/ReturnArrayInterface.php @@ -0,0 +1,16 @@ + + */ +trait SupportDefinedTestDeprecationTrait +{ + public function getAttribute($name, $default = null) + { + if ('is_defined_test' === $name) { + trigger_deprecation('twig/twig', '3.21', 'The "is_defined_test" attribute is deprecated, call "isDefinedTestEnabled()" instead.'); + + return $this->isDefinedTestEnabled(); + } + + return parent::getAttribute($name, $default); + } + + public function setAttribute(string $name, $value): void + { + if ('is_defined_test' === $name) { + trigger_deprecation('twig/twig', '3.21', 'The "is_defined_test" attribute is deprecated, call "enableDefinedTest()" instead.'); + + $this->definedTest = (bool) $value; + } else { + parent::setAttribute($name, $value); + } + } +} diff --git a/app/vendor/twig/twig/src/Node/Expression/SupportDefinedTestInterface.php b/app/vendor/twig/twig/src/Node/Expression/SupportDefinedTestInterface.php new file mode 100644 index 000000000..450c691c5 --- /dev/null +++ b/app/vendor/twig/twig/src/Node/Expression/SupportDefinedTestInterface.php @@ -0,0 +1,24 @@ + + */ +interface SupportDefinedTestInterface +{ + public function enableDefinedTest(): void; + + public function isDefinedTestEnabled(): bool; +} diff --git a/app/vendor/twig/twig/src/Node/Expression/SupportDefinedTestTrait.php b/app/vendor/twig/twig/src/Node/Expression/SupportDefinedTestTrait.php new file mode 100644 index 000000000..4cf1a58d5 --- /dev/null +++ b/app/vendor/twig/twig/src/Node/Expression/SupportDefinedTestTrait.php @@ -0,0 +1,27 @@ +definedTest = true; + } + + public function isDefinedTestEnabled(): bool + { + return $this->definedTest; + } +} diff --git a/app/vendor/twig/twig/src/Node/Expression/TempNameExpression.php b/app/vendor/twig/twig/src/Node/Expression/TempNameExpression.php index 8cb66a193..f996aab05 100644 --- a/app/vendor/twig/twig/src/Node/Expression/TempNameExpression.php +++ b/app/vendor/twig/twig/src/Node/Expression/TempNameExpression.php @@ -21,7 +21,7 @@ class TempNameExpression extends AbstractExpression public function __construct(string|int|null $name, int $lineno) { // All names supported by ExpressionParser::parsePrimaryExpression() should be excluded - if ($name && \in_array(strtolower($name), ['true', 'false', 'none', 'null'])) { + if ($name && \in_array(strtolower($name), ['true', 'false', 'none', 'null'], true)) { throw new SyntaxError(\sprintf('You cannot assign a value to "%s".', $name), $lineno); } @@ -31,7 +31,7 @@ public function __construct(string|int|null $name, int $lineno) if (null !== $name && (\is_int($name) || ctype_digit($name))) { $name = (int) $name; - } elseif (\in_array($name, self::RESERVED_NAMES)) { + } elseif (\in_array($name, self::RESERVED_NAMES, true)) { $name = "\u{035C}".$name; } diff --git a/app/vendor/twig/twig/src/Node/Expression/Ternary/ConditionalTernary.php b/app/vendor/twig/twig/src/Node/Expression/Ternary/ConditionalTernary.php index 627da7a43..f7cd78c5c 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Ternary/ConditionalTernary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Ternary/ConditionalTernary.php @@ -14,11 +14,18 @@ use Twig\Compiler; use Twig\Node\Expression\AbstractExpression; use Twig\Node\Expression\OperatorEscapeInterface; +use Twig\Node\Expression\ReturnPrimitiveTypeInterface; +use Twig\Node\Expression\Test\TrueTest; +use Twig\TwigTest; final class ConditionalTernary extends AbstractExpression implements OperatorEscapeInterface { public function __construct(AbstractExpression $test, AbstractExpression $left, AbstractExpression $right, int $lineno) { + if (!$test instanceof ReturnPrimitiveTypeInterface) { + $test = new TrueTest($test, new TwigTest('true'), null, $test->getTemplateLine()); + } + parent::__construct(['test' => $test, 'left' => $left, 'right' => $right], [], $lineno); } diff --git a/app/vendor/twig/twig/src/Node/Expression/Test/DefinedTest.php b/app/vendor/twig/twig/src/Node/Expression/Test/DefinedTest.php index 5e32c38bb..f17715bc6 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Test/DefinedTest.php +++ b/app/vendor/twig/twig/src/Node/Expression/Test/DefinedTest.php @@ -22,6 +22,7 @@ use Twig\Node\Expression\GetAttrExpression; use Twig\Node\Expression\MacroReferenceExpression; use Twig\Node\Expression\MethodCallExpression; +use Twig\Node\Expression\SupportDefinedTestInterface; use Twig\Node\Expression\TestExpression; use Twig\Node\Expression\Variable\ContextVariable; use Twig\Node\Node; @@ -46,28 +47,15 @@ class DefinedTest extends TestExpression public function __construct(Node $node, TwigTest|string $name, ?Node $arguments, int $lineno) { if (!$node instanceof AbstractExpression) { - trigger_deprecation('twig/twig', '3.15', 'Not passing a "%s" instance to the "node" argument of "%s" is deprecated ("%s" given).', AbstractExpression::class, static::class, \get_class($node)); + trigger_deprecation('twig/twig', '3.15', 'Not passing a "%s" instance to the "node" argument of "%s" is deprecated ("%s" given).', AbstractExpression::class, static::class, $node::class); } - if ($node instanceof ContextVariable) { - $node->setAttribute('is_defined_test', true); - } elseif ($node instanceof GetAttrExpression) { - $node->setAttribute('is_defined_test', true); - $this->changeIgnoreStrictCheck($node); - } elseif ($node instanceof BlockReferenceExpression) { - $node->setAttribute('is_defined_test', true); - } elseif ($node instanceof MacroReferenceExpression) { - $node->setAttribute('is_defined_test', true); - } elseif ($node instanceof FunctionExpression && 'constant' === $node->getAttribute('name')) { - $node->setAttribute('is_defined_test', true); - } elseif ($node instanceof ConstantExpression || $node instanceof ArrayExpression) { - $node = new ConstantExpression(true, $node->getTemplateLine()); - } elseif ($node instanceof MethodCallExpression) { - $node->setAttribute('is_defined_test', true); - } else { + if (!$node instanceof SupportDefinedTestInterface) { throw new SyntaxError('The "defined" test only works with simple variables.', $lineno); } + $node->enableDefinedTest(); + if (\is_string($name) && 'defined' !== $name) { trigger_deprecation('twig/twig', '3.12', 'Creating a "DefinedTest" instance with a test name that is not "defined" is deprecated.'); } @@ -75,16 +63,6 @@ public function __construct(Node $node, TwigTest|string $name, ?Node $arguments, parent::__construct($node, $name, $arguments, $lineno); } - private function changeIgnoreStrictCheck(GetAttrExpression $node): void - { - $node->setAttribute('optimizable', false); - $node->setAttribute('ignore_strict_check', true); - - if ($node->getNode('node') instanceof GetAttrExpression) { - $this->changeIgnoreStrictCheck($node->getNode('node')); - } - } - public function compile(Compiler $compiler): void { $compiler->subcompile($this->getNode('node')); diff --git a/app/vendor/twig/twig/src/Node/Expression/Test/NullTest.php b/app/vendor/twig/twig/src/Node/Expression/Test/NullTest.php index 45b54ae37..be5d38891 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Test/NullTest.php +++ b/app/vendor/twig/twig/src/Node/Expression/Test/NullTest.php @@ -15,7 +15,7 @@ use Twig\Node\Expression\TestExpression; /** - * Checks that a variable is null. + * Checks that an expression is null. * * {{ var is none }} * diff --git a/app/vendor/twig/twig/src/Node/Expression/Test/TrueTest.php b/app/vendor/twig/twig/src/Node/Expression/Test/TrueTest.php new file mode 100644 index 000000000..22186a689 --- /dev/null +++ b/app/vendor/twig/twig/src/Node/Expression/Test/TrueTest.php @@ -0,0 +1,34 @@ + + */ +class TrueTest extends TestExpression +{ + public function compile(Compiler $compiler): void + { + $compiler + ->raw('(($tmp = ') + ->subcompile($this->getNode('node')) + ->raw(') && $tmp instanceof Markup ? (string) $tmp : $tmp)') + ; + } +} diff --git a/app/vendor/twig/twig/src/Node/Expression/TestExpression.php b/app/vendor/twig/twig/src/Node/Expression/TestExpression.php index 7b9a54138..3b51dd320 100644 --- a/app/vendor/twig/twig/src/Node/Expression/TestExpression.php +++ b/app/vendor/twig/twig/src/Node/Expression/TestExpression.php @@ -17,7 +17,7 @@ use Twig\Node\Node; use Twig\TwigTest; -class TestExpression extends CallExpression +class TestExpression extends CallExpression implements ReturnBoolInterface { #[FirstClassTwigCallableReady] /** @@ -26,7 +26,7 @@ class TestExpression extends CallExpression public function __construct(Node $node, string|TwigTest $test, ?Node $arguments, int $lineno) { if (!$node instanceof AbstractExpression) { - trigger_deprecation('twig/twig', '3.15', 'Not passing a "%s" instance to the "node" argument of "%s" is deprecated ("%s" given).', AbstractExpression::class, static::class, \get_class($node)); + trigger_deprecation('twig/twig', '3.15', 'Not passing a "%s" instance to the "node" argument of "%s" is deprecated ("%s" given).', AbstractExpression::class, static::class, $node::class); } $nodes = ['node' => $node]; diff --git a/app/vendor/twig/twig/src/Node/Expression/Unary/AbstractUnary.php b/app/vendor/twig/twig/src/Node/Expression/Unary/AbstractUnary.php index b00027d1a..09f3d0984 100644 --- a/app/vendor/twig/twig/src/Node/Expression/Unary/AbstractUnary.php +++ b/app/vendor/twig/twig/src/Node/Expression/Unary/AbstractUnary.php @@ -24,7 +24,7 @@ abstract class AbstractUnary extends AbstractExpression implements UnaryInterfac public function __construct(Node $node, int $lineno) { if (!$node instanceof AbstractExpression) { - trigger_deprecation('twig/twig', '3.15', 'Not passing a "%s" instance argument to "%s" is deprecated ("%s" given).', AbstractExpression::class, static::class, \get_class($node)); + trigger_deprecation('twig/twig', '3.15', 'Not passing a "%s" instance argument to "%s" is deprecated ("%s" given).', AbstractExpression::class, static::class, $node::class); } parent::__construct(['node' => $node], ['with_parentheses' => false], $lineno); diff --git a/app/vendor/twig/twig/src/Node/IfNode.php b/app/vendor/twig/twig/src/Node/IfNode.php index 2af48fa81..2c0e2a8e9 100644 --- a/app/vendor/twig/twig/src/Node/IfNode.php +++ b/app/vendor/twig/twig/src/Node/IfNode.php @@ -14,6 +14,9 @@ use Twig\Attribute\YieldReady; use Twig\Compiler; +use Twig\Node\Expression\ReturnPrimitiveTypeInterface; +use Twig\Node\Expression\Test\TrueTest; +use Twig\TwigTest; /** * Represents an if node. @@ -25,6 +28,12 @@ class IfNode extends Node { public function __construct(Node $tests, ?Node $else, int $lineno) { + for ($i = 0, $count = \count($tests); $i < $count; $i += 2) { + $test = $tests->getNode((string) $i); + if (!$test instanceof ReturnPrimitiveTypeInterface) { + $tests->setNode($i, new TrueTest($test, new TwigTest('true'), null, $test->getTemplateLine())); + } + } $nodes = ['tests' => $tests]; if (null !== $else) { $nodes['else'] = $else; diff --git a/app/vendor/twig/twig/src/Node/ImportNode.php b/app/vendor/twig/twig/src/Node/ImportNode.php index 77a9af939..92bdd5ebf 100644 --- a/app/vendor/twig/twig/src/Node/ImportNode.php +++ b/app/vendor/twig/twig/src/Node/ImportNode.php @@ -48,11 +48,9 @@ public function compile(Compiler $compiler): void $compiler->raw('$this'); } else { $compiler - ->raw('$this->loadTemplate(') + ->raw('$this->load(') ->subcompile($this->getNode('expr')) ->raw(', ') - ->repr($this->getTemplateName()) - ->raw(', ') ->repr($this->getTemplateLine()) ->raw(')->unwrap()') ; diff --git a/app/vendor/twig/twig/src/Node/IncludeNode.php b/app/vendor/twig/twig/src/Node/IncludeNode.php index 4761cb832..6e17300f0 100644 --- a/app/vendor/twig/twig/src/Node/IncludeNode.php +++ b/app/vendor/twig/twig/src/Node/IncludeNode.php @@ -84,11 +84,9 @@ public function compile(Compiler $compiler): void protected function addGetTemplate(Compiler $compiler/* , string $template = '' */) { $compiler - ->raw('$this->loadTemplate(') + ->raw('$this->load(') ->subcompile($this->getNode('expr')) ->raw(', ') - ->repr($this->getTemplateName()) - ->raw(', ') ->repr($this->getTemplateLine()) ->raw(')') ; diff --git a/app/vendor/twig/twig/src/Node/ModuleNode.php b/app/vendor/twig/twig/src/Node/ModuleNode.php index b3f4e6c2a..71c572019 100644 --- a/app/vendor/twig/twig/src/Node/ModuleNode.php +++ b/app/vendor/twig/twig/src/Node/ModuleNode.php @@ -38,6 +38,15 @@ public function __construct(Node $body, ?AbstractExpression $parent, Node $block if (!$body instanceof BodyNode) { trigger_deprecation('twig/twig', '3.12', \sprintf('Not passing a "%s" instance as the "body" argument of the "%s" constructor is deprecated.', BodyNode::class, static::class)); } + if (!$embeddedTemplates instanceof Node) { + trigger_deprecation('twig/twig', '3.21', \sprintf('Not passing a "%s" instance as the "embedded_templates" argument of the "%s" constructor is deprecated.', Node::class, static::class)); + + if (null !== $embeddedTemplates) { + $embeddedTemplates = new Nodes($embeddedTemplates); + } else { + $embeddedTemplates = new EmptyNode(); + } + } $nodes = [ 'body' => $body, @@ -134,11 +143,9 @@ protected function compileGetParent(Compiler $compiler) $compiler->subcompile($parent); } else { $compiler - ->raw('$this->loadTemplate(') + ->raw('$this->load(') ->subcompile($parent) ->raw(', ') - ->repr($this->getSourceContext()->getName()) - ->raw(', ') ->repr($parent->getTemplateLine()) ->raw(')') ; @@ -218,11 +225,9 @@ protected function compileConstructor(Compiler $compiler) $compiler ->addDebugInfo($node) - ->write(\sprintf('$_trait_%s = $this->loadTemplate(', $i)) + ->write(\sprintf('$_trait_%s = $this->load(', $i)) ->subcompile($node) ->raw(', ') - ->repr($node->getTemplateName()) - ->raw(', ') ->repr($node->getTemplateLine()) ->raw(");\n") ->write(\sprintf("if (!\$_trait_%s->unwrap()->isTraitable()) {\n", $i)) @@ -353,11 +358,9 @@ protected function compileDisplay(Compiler $compiler) $compiler->addDebugInfo($parent); if ($parent instanceof ConstantExpression) { $compiler - ->write('$this->parent = $this->loadTemplate(') + ->write('$this->parent = $this->load(') ->subcompile($parent) ->raw(', ') - ->repr($this->getSourceContext()->getName()) - ->raw(', ') ->repr($parent->getTemplateLine()) ->raw(");\n") ; diff --git a/app/vendor/twig/twig/src/Node/Node.php b/app/vendor/twig/twig/src/Node/Node.php index 389119b55..dcf912c21 100644 --- a/app/vendor/twig/twig/src/Node/Node.php +++ b/app/vendor/twig/twig/src/Node/Node.php @@ -149,9 +149,6 @@ public function hasAttribute(string $name): bool return \array_key_exists($name, $this->attributes); } - /** - * @return mixed - */ public function getAttribute(string $name) { if (!\array_key_exists($name, $this->attributes)) { diff --git a/app/vendor/twig/twig/src/Node/SetNode.php b/app/vendor/twig/twig/src/Node/SetNode.php index 4d97adb22..7b063b00b 100644 --- a/app/vendor/twig/twig/src/Node/SetNode.php +++ b/app/vendor/twig/twig/src/Node/SetNode.php @@ -34,7 +34,7 @@ public function __construct(bool $capture, Node $names, Node $values, int $linen if ($capture) { $safe = true; // Node::class === get_class($values) should be removed in Twig 4.0 - if (($values instanceof Nodes || Node::class === \get_class($values)) && !\count($values)) { + if (($values instanceof Nodes || Node::class === $values::class) && !\count($values)) { $values = new ConstantExpression('', $values->getTemplateLine()); $capture = false; } elseif ($values instanceof TextNode) { diff --git a/app/vendor/twig/twig/src/NodeVisitor/EscaperNodeVisitor.php b/app/vendor/twig/twig/src/NodeVisitor/EscaperNodeVisitor.php index b35ae8817..a9f829770 100644 --- a/app/vendor/twig/twig/src/NodeVisitor/EscaperNodeVisitor.php +++ b/app/vendor/twig/twig/src/NodeVisitor/EscaperNodeVisitor.php @@ -154,7 +154,7 @@ private function isSafeFor(string $type, AbstractExpression $expression, Environ $safe = $this->safeAnalysis->getSafe($expression); } - return \in_array($type, $safe) || \in_array('all', $safe); + return \in_array($type, $safe, true) || \in_array('all', $safe, true); } /** diff --git a/app/vendor/twig/twig/src/NodeVisitor/OptimizerNodeVisitor.php b/app/vendor/twig/twig/src/NodeVisitor/OptimizerNodeVisitor.php index 9283737f5..b778ba40e 100644 --- a/app/vendor/twig/twig/src/NodeVisitor/OptimizerNodeVisitor.php +++ b/app/vendor/twig/twig/src/NodeVisitor/OptimizerNodeVisitor.php @@ -143,7 +143,7 @@ private function enterOptimizeFor(Node $node): void } // optimize access to loop targets - elseif ($node instanceof ContextVariable && \in_array($node->getAttribute('name'), $this->loopsTargets)) { + elseif ($node instanceof ContextVariable && \in_array($node->getAttribute('name'), $this->loopsTargets, true)) { $node->setAttribute('always_defined', true); } diff --git a/app/vendor/twig/twig/src/NodeVisitor/SafeAnalysisNodeVisitor.php b/app/vendor/twig/twig/src/NodeVisitor/SafeAnalysisNodeVisitor.php index a5361fbf7..8cb5f7a39 100644 --- a/app/vendor/twig/twig/src/NodeVisitor/SafeAnalysisNodeVisitor.php +++ b/app/vendor/twig/twig/src/NodeVisitor/SafeAnalysisNodeVisitor.php @@ -52,7 +52,7 @@ public function getSafe(Node $node) continue; } - if (\in_array('html_attr', $bucket['value'])) { + if (\in_array('html_attr', $bucket['value'], true)) { $bucket['value'][] = 'html'; } @@ -148,7 +148,7 @@ public function leaveNode(Node $node, Environment $env): ?Node $this->setSafe($node, ['all']); } elseif ($node instanceof GetAttrExpression && $node->getNode('node') instanceof ContextVariable) { $name = $node->getNode('node')->getAttribute('name'); - if (\in_array($name, $this->safeVars)) { + if (\in_array($name, $this->safeVars, true)) { $this->setSafe($node, ['all']); } } @@ -162,11 +162,11 @@ private function intersectSafe(array $a, array $b): array return []; } - if (\in_array('all', $a)) { + if (\in_array('all', $a, true)) { return $b; } - if (\in_array('all', $b)) { + if (\in_array('all', $b, true)) { return $a; } diff --git a/app/vendor/twig/twig/src/NodeVisitor/SandboxNodeVisitor.php b/app/vendor/twig/twig/src/NodeVisitor/SandboxNodeVisitor.php index 7e89ef83a..9dd48f5be 100644 --- a/app/vendor/twig/twig/src/NodeVisitor/SandboxNodeVisitor.php +++ b/app/vendor/twig/twig/src/NodeVisitor/SandboxNodeVisitor.php @@ -123,12 +123,7 @@ private function wrapNode(Node $node, string $name): void { $expr = $node->getNode($name); if (($expr instanceof ContextVariable || $expr instanceof GetAttrExpression) && !$expr->isGenerator()) { - // Simplify in 4.0 as the spread attribute has been removed there - $new = new CheckToStringNode($expr); - if ($expr->hasAttribute('spread')) { - $new->setAttribute('spread', $expr->getAttribute('spread')); - } - $node->setNode($name, $new); + $node->setNode($name, new CheckToStringNode($expr)); } elseif ($expr instanceof SpreadUnary) { $this->wrapNode($expr, 'node'); } elseif ($expr instanceof ArrayExpression) { diff --git a/app/vendor/twig/twig/src/NodeVisitor/YieldNotReadyNodeVisitor.php b/app/vendor/twig/twig/src/NodeVisitor/YieldNotReadyNodeVisitor.php index 3c9786275..4d6cf60a0 100644 --- a/app/vendor/twig/twig/src/NodeVisitor/YieldNotReadyNodeVisitor.php +++ b/app/vendor/twig/twig/src/NodeVisitor/YieldNotReadyNodeVisitor.php @@ -30,7 +30,7 @@ public function __construct( public function enterNode(Node $node, Environment $env): Node { - $class = \get_class($node); + $class = $node::class; if ($node instanceof AbstractExpression || isset($this->yieldReadyNodes[$class])) { return $node; diff --git a/app/vendor/twig/twig/src/OperatorPrecedenceChange.php b/app/vendor/twig/twig/src/OperatorPrecedenceChange.php index 1d9edefd1..31ebaef48 100644 --- a/app/vendor/twig/twig/src/OperatorPrecedenceChange.php +++ b/app/vendor/twig/twig/src/OperatorPrecedenceChange.php @@ -11,32 +11,24 @@ namespace Twig; +use Twig\ExpressionParser\PrecedenceChange; + /** - * Represents a precedence change for an operator. + * Represents a precedence change. * * @author Fabien Potencier + * + * @deprecated since Twig 1.20 Use Twig\ExpressionParser\PrecedenceChange instead */ -class OperatorPrecedenceChange +class OperatorPrecedenceChange extends PrecedenceChange { public function __construct( private string $package, private string $version, private int $newPrecedence, ) { - } - - public function getPackage(): string - { - return $this->package; - } - - public function getVersion(): string - { - return $this->version; - } + trigger_deprecation('twig/twig', '3.21', 'The "%s" class is deprecated since Twig 3.21. Use "%s" instead.', self::class, PrecedenceChange::class); - public function getNewPrecedence(): int - { - return $this->newPrecedence; + parent::__construct($package, $version, $newPrecedence); } } diff --git a/app/vendor/twig/twig/src/Parser.php b/app/vendor/twig/twig/src/Parser.php index ff1772c16..1937b7e15 100644 --- a/app/vendor/twig/twig/src/Parser.php +++ b/app/vendor/twig/twig/src/Parser.php @@ -13,6 +13,12 @@ namespace Twig; use Twig\Error\SyntaxError; +use Twig\ExpressionParser\ExpressionParserInterface; +use Twig\ExpressionParser\ExpressionParsers; +use Twig\ExpressionParser\ExpressionParserType; +use Twig\ExpressionParser\InfixExpressionParserInterface; +use Twig\ExpressionParser\Prefix\LiteralExpressionParser; +use Twig\ExpressionParser\PrefixExpressionParserInterface; use Twig\Node\BlockNode; use Twig\Node\BlockReferenceNode; use Twig\Node\BodyNode; @@ -37,6 +43,7 @@ class Parser { private $stack = []; + private ?\WeakMap $expressionRefs = null; private $stream; private $parent; private $visitors; @@ -49,10 +56,12 @@ class Parser private $embeddedTemplates = []; private $varNameSalt = 0; private $ignoreUnknownTwigCallables = false; + private ExpressionParsers $parsers; public function __construct( private Environment $env, ) { + $this->parsers = $env->getExpressionParsers(); } public function getEnvironment(): Environment @@ -78,10 +87,6 @@ public function parse(TokenStream $stream, $test = null, bool $dropNeedle = fals $this->visitors = $this->env->getNodeVisitors(); } - if (null === $this->expressionParser) { - $this->expressionParser = new ExpressionParser($this, $this->env); - } - $this->stream = $stream; $this->parent = null; $this->blocks = []; @@ -90,6 +95,7 @@ public function parse(TokenStream $stream, $test = null, bool $dropNeedle = fals $this->blockStack = []; $this->importedSymbols = [[]]; $this->embeddedTemplates = []; + $this->expressionRefs = new \WeakMap(); try { $body = $this->subparse($test, $dropNeedle); @@ -107,9 +113,19 @@ public function parse(TokenStream $stream, $test = null, bool $dropNeedle = fals } throw $e; + } finally { + $this->expressionRefs = null; } - $node = new ModuleNode(new BodyNode([$body]), $this->parent, new Nodes($this->blocks), new Nodes($this->macros), new Nodes($this->traits), $this->embeddedTemplates, $stream->getSourceContext()); + $node = new ModuleNode( + new BodyNode([$body]), + $this->parent, + $this->blocks ? new Nodes($this->blocks) : new EmptyNode(), + $this->macros ? new Nodes($this->macros) : new EmptyNode(), + $this->traits ? new Nodes($this->traits) : new EmptyNode(), + $this->embeddedTemplates ? new Nodes($this->embeddedTemplates) : new EmptyNode(), + $stream->getSourceContext(), + ); $traverser = new NodeTraverser($this->env, $this->visitors); @@ -155,7 +171,7 @@ public function subparse($test, bool $dropNeedle = false): Node case $this->stream->getCurrent()->test(Token::VAR_START_TYPE): $token = $this->stream->next(); - $expr = $this->expressionParser->parseExpression(); + $expr = $this->parseExpression(); $this->stream->expect(Token::VAR_END_TYPE); $rv[] = new PrintNode($expr, $token->getLine()); break; @@ -337,11 +353,42 @@ public function popLocalScope(): void array_shift($this->importedSymbols); } + /** + * @deprecated since Twig 3.21 + */ public function getExpressionParser(): ExpressionParser { + trigger_deprecation('twig/twig', '3.21', 'Method "%s()" is deprecated, use "parseExpression()" instead.', __METHOD__); + + if (null === $this->expressionParser) { + $this->expressionParser = new ExpressionParser($this, $this->env); + } + return $this->expressionParser; } + public function parseExpression(int $precedence = 0): AbstractExpression + { + $token = $this->getCurrentToken(); + if ($token->test(Token::OPERATOR_TYPE) && $ep = $this->parsers->getByName(PrefixExpressionParserInterface::class, $token->getValue())) { + $this->getStream()->next(); + $expr = $ep->parse($this, $token); + $this->checkPrecedenceDeprecations($ep, $expr); + } else { + $expr = $this->parsers->getByClass(LiteralExpressionParser::class)->parse($this, $token); + } + + $token = $this->getCurrentToken(); + while ($token->test(Token::OPERATOR_TYPE) && ($ep = $this->parsers->getByName(InfixExpressionParserInterface::class, $token->getValue())) && $ep->getPrecedence() >= $precedence) { + $this->getStream()->next(); + $expr = $ep->parse($this, $expr, $token); + $this->checkPrecedenceDeprecations($ep, $expr); + $token = $this->getCurrentToken(); + } + + return $expr; + } + public function getParent(): ?Node { trigger_deprecation('twig/twig', '3.12', 'Method "%s()" is deprecated.', __METHOD__); @@ -380,6 +427,98 @@ public function getCurrentToken(): Token return $this->stream->getCurrent(); } + public function getFunction(string $name, int $line): TwigFunction + { + try { + $function = $this->env->getFunction($name); + } catch (SyntaxError $e) { + if (!$this->shouldIgnoreUnknownTwigCallables()) { + throw $e; + } + + $function = null; + } + + if (!$function) { + if ($this->shouldIgnoreUnknownTwigCallables()) { + return new TwigFunction($name, fn () => ''); + } + $e = new SyntaxError(\sprintf('Unknown "%s" function.', $name), $line, $this->stream->getSourceContext()); + $e->addSuggestions($name, array_keys($this->env->getFunctions())); + + throw $e; + } + + if ($function->isDeprecated()) { + $src = $this->stream->getSourceContext(); + $function->triggerDeprecation($src->getPath() ?: $src->getName(), $line); + } + + return $function; + } + + public function getFilter(string $name, int $line): TwigFilter + { + try { + $filter = $this->env->getFilter($name); + } catch (SyntaxError $e) { + if (!$this->shouldIgnoreUnknownTwigCallables()) { + throw $e; + } + + $filter = null; + } + if (!$filter) { + if ($this->shouldIgnoreUnknownTwigCallables()) { + return new TwigFilter($name, fn () => ''); + } + $e = new SyntaxError(\sprintf('Unknown "%s" filter.', $name), $line, $this->stream->getSourceContext()); + $e->addSuggestions($name, array_keys($this->env->getFilters())); + + throw $e; + } + + if ($filter->isDeprecated()) { + $src = $this->stream->getSourceContext(); + $filter->triggerDeprecation($src->getPath() ?: $src->getName(), $line); + } + + return $filter; + } + + public function getTest(int $line): TwigTest + { + $name = $this->stream->expect(Token::NAME_TYPE)->getValue(); + + if ($this->stream->test(Token::NAME_TYPE)) { + // try 2-words tests + $name = $name.' '.$this->getCurrentToken()->getValue(); + + if ($test = $this->env->getTest($name)) { + $this->stream->next(); + } + } else { + $test = $this->env->getTest($name); + } + + if (!$test) { + if ($this->shouldIgnoreUnknownTwigCallables()) { + return new TwigTest($name, fn () => ''); + } + $e = new SyntaxError(\sprintf('Unknown "%s" test.', $name), $line, $this->stream->getSourceContext()); + $e->addSuggestions($name, array_keys($this->env->getTests())); + + throw $e; + } + + if ($test->isDeprecated()) { + $src = $this->stream->getSourceContext(); + $test->triggerDeprecation($src->getPath() ?: $src->getName(), $this->stream->getCurrent()->getLine()); + } + + return $test; + } + private function filterBodyNodes(Node $node, bool $nested = false): ?Node { // check that the body does not contain non-empty output nodes @@ -418,7 +557,7 @@ private function filterBodyNodes(Node $node, bool $nested = false): ?Node // here, $nested means "being at the root level of a child template" // we need to discard the wrapping "Node" for the "body" node // Node::class !== \get_class($node) should be removed in Twig 4.0 - $nested = $nested || (Node::class !== \get_class($node) && !$node instanceof Nodes); + $nested = $nested || (Node::class !== $node::class && !$node instanceof Nodes); foreach ($node as $k => $n) { if (null !== $n && null === $this->filterBodyNodes($n, $nested)) { $node->removeNode($k); @@ -427,4 +566,43 @@ private function filterBodyNodes(Node $node, bool $nested = false): ?Node return $node; } + + private function checkPrecedenceDeprecations(ExpressionParserInterface $expressionParser, AbstractExpression $expr) + { + $this->expressionRefs[$expr] = $expressionParser; + $precedenceChanges = $this->parsers->getPrecedenceChanges(); + + // Check that the all nodes that are between the 2 precedences have explicit parentheses + if (!isset($precedenceChanges[$expressionParser])) { + return; + } + + if ($expr->hasExplicitParentheses()) { + return; + } + + if ($expressionParser instanceof PrefixExpressionParserInterface) { + /** @var AbstractExpression $node */ + $node = $expr->getNode('node'); + foreach ($precedenceChanges as $ep => $changes) { + if (!\in_array($expressionParser, $changes, true)) { + continue; + } + if (isset($this->expressionRefs[$node]) && $ep === $this->expressionRefs[$node]) { + $change = $expressionParser->getPrecedenceChange(); + trigger_deprecation($change->getPackage(), $change->getVersion(), \sprintf('As the "%s" %s operator will change its precedence in the next major version, add explicit parentheses to avoid behavior change in "%s" at line %d.', $expressionParser->getName(), ExpressionParserType::getType($expressionParser)->value, $this->getStream()->getSourceContext()->getName(), $node->getTemplateLine())); + } + } + } + + foreach ($precedenceChanges[$expressionParser] as $ep) { + foreach ($expr as $node) { + /** @var AbstractExpression $node */ + if (isset($this->expressionRefs[$node]) && $ep === $this->expressionRefs[$node] && !$node->hasExplicitParentheses()) { + $change = $ep->getPrecedenceChange(); + trigger_deprecation($change->getPackage(), $change->getVersion(), \sprintf('As the "%s" %s operator will change its precedence in the next major version, add explicit parentheses to avoid behavior change in "%s" at line %d.', $ep->getName(), ExpressionParserType::getType($ep)->value, $this->getStream()->getSourceContext()->getName(), $node->getTemplateLine())); + } + } + } + } } diff --git a/app/vendor/twig/twig/src/Runtime/EscaperRuntime.php b/app/vendor/twig/twig/src/Runtime/EscaperRuntime.php index 719a5696a..17ed76cc9 100644 --- a/app/vendor/twig/twig/src/Runtime/EscaperRuntime.php +++ b/app/vendor/twig/twig/src/Runtime/EscaperRuntime.php @@ -106,7 +106,7 @@ public function escape($string, string $strategy = 'html', ?string $charset = nu if (!\is_string($string)) { if ($string instanceof \Stringable) { if ($autoescape) { - $c = \get_class($string); + $c = $string::class; if (!isset($this->safeClasses[$c])) { $this->safeClasses[$c] = []; foreach (class_parents($string) + class_implements($string) as $class) { @@ -124,7 +124,7 @@ public function escape($string, string $strategy = 'html', ?string $charset = nu } $string = (string) $string; - } elseif (\in_array($strategy, ['html', 'js', 'css', 'html_attr', 'url'])) { + } elseif (\in_array($strategy, ['html', 'js', 'css', 'html_attr', 'url'], true)) { // we return the input as is (which can be of any type) return $string; } diff --git a/app/vendor/twig/twig/src/Sandbox/SecurityPolicy.php b/app/vendor/twig/twig/src/Sandbox/SecurityPolicy.php index b0d054260..b2c83ee10 100644 --- a/app/vendor/twig/twig/src/Sandbox/SecurityPolicy.php +++ b/app/vendor/twig/twig/src/Sandbox/SecurityPolicy.php @@ -67,7 +67,7 @@ public function setAllowedFunctions(array $functions): void public function checkSecurity($tags, $filters, $functions): void { foreach ($tags as $tag) { - if (!\in_array($tag, $this->allowedTags)) { + if (!\in_array($tag, $this->allowedTags, true)) { if ('extends' === $tag) { trigger_deprecation('twig/twig', '3.12', 'The "extends" tag is always allowed in sandboxes, but won\'t be in 4.0, please enable it explicitly in your sandbox policy if needed.'); } elseif ('use' === $tag) { @@ -79,13 +79,13 @@ public function checkSecurity($tags, $filters, $functions): void } foreach ($filters as $filter) { - if (!\in_array($filter, $this->allowedFilters)) { + if (!\in_array($filter, $this->allowedFilters, true)) { throw new SecurityNotAllowedFilterError(\sprintf('Filter "%s" is not allowed.', $filter), $filter); } } foreach ($functions as $function) { - if (!\in_array($function, $this->allowedFunctions)) { + if (!\in_array($function, $this->allowedFunctions, true)) { throw new SecurityNotAllowedFunctionError(\sprintf('Function "%s" is not allowed.', $function), $function); } } @@ -100,14 +100,14 @@ public function checkMethodAllowed($obj, $method): void $allowed = false; $method = strtolower($method); foreach ($this->allowedMethods as $class => $methods) { - if ($obj instanceof $class && \in_array($method, $methods)) { + if ($obj instanceof $class && \in_array($method, $methods, true)) { $allowed = true; break; } } if (!$allowed) { - $class = \get_class($obj); + $class = $obj::class; throw new SecurityNotAllowedMethodError(\sprintf('Calling "%s" method on a "%s" object is not allowed.', $method, $class), $class, $method); } } @@ -116,14 +116,14 @@ public function checkPropertyAllowed($obj, $property): void { $allowed = false; foreach ($this->allowedProperties as $class => $properties) { - if ($obj instanceof $class && \in_array($property, \is_array($properties) ? $properties : [$properties])) { + if ($obj instanceof $class && \in_array($property, \is_array($properties) ? $properties : [$properties], true)) { $allowed = true; break; } } if (!$allowed) { - $class = \get_class($obj); + $class = $obj::class; throw new SecurityNotAllowedPropertyError(\sprintf('Calling "%s" property on a "%s" object is not allowed.', $property, $class), $class, $property); } } diff --git a/app/vendor/twig/twig/src/Template.php b/app/vendor/twig/twig/src/Template.php index 156752f8b..faf7aee1e 100644 --- a/app/vendor/twig/twig/src/Template.php +++ b/app/vendor/twig/twig/src/Template.php @@ -89,7 +89,7 @@ public function getParent(array $context): self|TemplateWrapper|false } if (!isset($this->parents[$parent])) { - $this->parents[$parent] = $this->loadTemplate($parent); + $this->parents[$parent] = $this->load($parent, -1); } return $this->parents[$parent]; @@ -270,21 +270,15 @@ public function getBlockNames(array $context, array $blocks = []): array /** * @param string|TemplateWrapper|array $template */ - protected function loadTemplate($template, $templateName = null, $line = null, $index = null): self|TemplateWrapper + protected function load(string|TemplateWrapper|array $template, int $line, int|null $index = null): self { try { if (\is_array($template)) { - return $this->env->resolveTemplate($template); + return $this->env->resolveTemplate($template)->unwrap(); } if ($template instanceof TemplateWrapper) { - return $template; - } - - if ($template instanceof self) { - trigger_deprecation('twig/twig', '3.9', 'Passing a "%s" instance to "%s" is deprecated.', self::class, __METHOD__); - - return $template; + return $template->unwrap(); } if ($template === $this->getTemplateName()) { @@ -299,14 +293,14 @@ protected function loadTemplate($template, $templateName = null, $line = null, $ return $this->env->loadTemplate($class, $template, $index); } catch (Error $e) { if (!$e->getSourceContext()) { - $e->setSourceContext($templateName ? new Source('', $templateName) : $this->getSourceContext()); + $e->setSourceContext($this->getSourceContext()); } if ($e->getTemplateLine() > 0) { throw $e; } - if (!$line) { + if (-1 === $line) { $e->guess(); } else { $e->setTemplateLine($line); @@ -316,6 +310,26 @@ protected function loadTemplate($template, $templateName = null, $line = null, $ } } + /** + * @param string|TemplateWrapper|array $template + * + * @deprecated since Twig 3.21 and will be removed in 4.0. Use Template::load() instead. + */ + protected function loadTemplate($template, $templateName = null, int|null $line = null, int|null $index = null): self|TemplateWrapper + { + trigger_deprecation('twig/twig', '3.21', 'The "%s" method is deprecated.', __METHOD__); + + if (null === $line) { + $line = -1; + } + + if ($template instanceof self) { + return $template; + } + + return $this->load($template, $line, $index); + } + /** * @internal * diff --git a/app/vendor/twig/twig/src/Test/IntegrationTestCase.php b/app/vendor/twig/twig/src/Test/IntegrationTestCase.php index f4a5dc7e5..f3f7adcee 100644 --- a/app/vendor/twig/twig/src/Test/IntegrationTestCase.php +++ b/app/vendor/twig/twig/src/Test/IntegrationTestCase.php @@ -275,14 +275,14 @@ protected function doIntegrationTest($file, $message, $condition, $templates, $e } catch (\Exception $e) { if (false !== $exception) { $message = $e->getMessage(); - $this->assertSame(trim($exception), trim(\sprintf('%s: %s', \get_class($e), $message))); + $this->assertSame(trim($exception), trim(\sprintf('%s: %s', $e::class, $message))); $last = substr($message, \strlen($message) - 1); $this->assertTrue('.' === $last || '?' === $last, 'Exception message must end with a dot or a question mark.'); return; } - throw new Error(\sprintf('%s: %s', \get_class($e), $e->getMessage()), -1, null, $e); + throw new Error(\sprintf('%s: %s', $e::class, $e->getMessage()), -1, null, $e); } finally { restore_error_handler(); } @@ -293,14 +293,14 @@ protected function doIntegrationTest($file, $message, $condition, $templates, $e $output = trim($template->render(eval($match[1].';')), "\n "); } catch (\Exception $e) { if (false !== $exception) { - $this->assertStringMatchesFormat(trim($exception), trim(\sprintf('%s: %s', \get_class($e), $e->getMessage()))); + $this->assertStringMatchesFormat(trim($exception), trim(\sprintf('%s: %s', $e::class, $e->getMessage()))); return; } - $e = new Error(\sprintf('%s: %s', \get_class($e), $e->getMessage()), -1, null, $e); + $e = new Error(\sprintf('%s: %s', $e::class, $e->getMessage()), -1, null, $e); - $output = trim(\sprintf('%s: %s', \get_class($e), $e->getMessage())); + $output = trim(\sprintf('%s: %s', $e::class, $e->getMessage())); } if (false !== $exception) { diff --git a/app/vendor/twig/twig/src/Token.php b/app/vendor/twig/twig/src/Token.php index a4da548cb..823c77387 100644 --- a/app/vendor/twig/twig/src/Token.php +++ b/app/vendor/twig/twig/src/Token.php @@ -30,7 +30,13 @@ final class Token public const PUNCTUATION_TYPE = 9; public const INTERPOLATION_START_TYPE = 10; public const INTERPOLATION_END_TYPE = 11; + /** + * @deprecated since Twig 3.21, "arrow" is now an operator + */ public const ARROW_TYPE = 12; + /** + * @deprecated since Twig 3.21, "spread" is now an operator + */ public const SPREAD_TYPE = 13; public function __construct( @@ -38,6 +44,12 @@ public function __construct( private $value, private int $lineno, ) { + if (self::ARROW_TYPE === $type) { + trigger_deprecation('twig/twig', '3.21', 'The "%s" token type is deprecated, "arrow" is now an operator.', self::ARROW_TYPE); + } + if (self::SPREAD_TYPE === $type) { + trigger_deprecation('twig/twig', '3.21', 'The "%s" token type is deprecated, "spread" is now an operator.', self::SPREAD_TYPE); + } } public function __toString(): string @@ -63,9 +75,46 @@ public function test($type, $values = null): bool $type = self::NAME_TYPE; } - return ($this->type === $type) && ( + if (self::ARROW_TYPE === $type) { + trigger_deprecation('twig/twig', '3.21', 'The "%s" token type is deprecated, "arrow" is now an operator.', self::typeToEnglish(self::ARROW_TYPE)); + + return self::OPERATOR_TYPE === $this->type && '=>' === $this->value; + } + if (self::SPREAD_TYPE === $type) { + trigger_deprecation('twig/twig', '3.21', 'The "%s" token type is deprecated, "spread" is now an operator.', self::typeToEnglish(self::SPREAD_TYPE)); + + return self::OPERATOR_TYPE === $this->type && '...' === $this->value; + } + + $typeMatches = $this->type === $type; + if ($typeMatches && self::PUNCTUATION_TYPE === $type && \in_array($this->value, ['(', '[', '|', '.', '?', '?:'], true) && $values) { + foreach ((array) $values as $value) { + if (\in_array($value, ['(', '[', '|', '.', '?', '?:'], true)) { + trigger_deprecation('twig/twig', '3.21', 'The "%s" token is now an "%s" token instead of a "%s" one.', $this->value, self::typeToEnglish(self::OPERATOR_TYPE), $this->toEnglish()); + + break; + } + } + } + if (!$typeMatches) { + if (self::OPERATOR_TYPE === $type && self::PUNCTUATION_TYPE === $this->type) { + if ($values) { + foreach ((array) $values as $value) { + if (\in_array($value, ['(', '[', '|', '.', '?', '?:'], true)) { + $typeMatches = true; + + break; + } + } + } else { + $typeMatches = true; + } + } + } + + return $typeMatches && ( null === $values - || (\is_array($values) && \in_array($this->value, $values)) + || (\is_array($values) && \in_array($this->value, $values, true)) || $this->value == $values ); } @@ -85,9 +134,6 @@ public function getType(): int return $this->type; } - /** - * @return mixed - */ public function getValue() { return $this->value; diff --git a/app/vendor/twig/twig/src/TokenParser/AbstractTokenParser.php b/app/vendor/twig/twig/src/TokenParser/AbstractTokenParser.php index 720ea6762..8acaa6f56 100644 --- a/app/vendor/twig/twig/src/TokenParser/AbstractTokenParser.php +++ b/app/vendor/twig/twig/src/TokenParser/AbstractTokenParser.php @@ -11,7 +11,11 @@ namespace Twig\TokenParser; +use Twig\Lexer; +use Twig\Node\Expression\Variable\AssignContextVariable; +use Twig\Node\Nodes; use Twig\Parser; +use Twig\Token; /** * Base class for all token parsers. @@ -29,4 +33,29 @@ public function setParser(Parser $parser): void { $this->parser = $parser; } + + /** + * Parses an assignment expression like "a, b". + */ + protected function parseAssignmentExpression(): Nodes + { + $stream = $this->parser->getStream(); + $targets = []; + while (true) { + $token = $stream->getCurrent(); + if ($stream->test(Token::OPERATOR_TYPE) && preg_match(Lexer::REGEX_NAME, $token->getValue())) { + // in this context, string operators are variable names + $stream->next(); + } else { + $stream->expect(Token::NAME_TYPE, null, 'Only variables can be assigned to'); + } + $targets[] = new AssignContextVariable($token->getValue(), $token->getLine()); + + if (!$stream->nextIf(Token::PUNCTUATION_TYPE, ',')) { + break; + } + } + + return new Nodes($targets); + } } diff --git a/app/vendor/twig/twig/src/TokenParser/ApplyTokenParser.php b/app/vendor/twig/twig/src/TokenParser/ApplyTokenParser.php index 0c9507482..5b560e749 100644 --- a/app/vendor/twig/twig/src/TokenParser/ApplyTokenParser.php +++ b/app/vendor/twig/twig/src/TokenParser/ApplyTokenParser.php @@ -11,6 +11,7 @@ namespace Twig\TokenParser; +use Twig\ExpressionParser\Infix\FilterExpressionParser; use Twig\Node\Expression\Variable\LocalVariable; use Twig\Node\Node; use Twig\Node\Nodes; @@ -33,7 +34,15 @@ public function parse(Token $token): Node { $lineno = $token->getLine(); $ref = new LocalVariable(null, $lineno); - $filter = $this->parser->getExpressionParser()->parseFilterExpressionRaw($ref); + $filter = $ref; + $op = $this->parser->getEnvironment()->getExpressionParsers()->getByClass(FilterExpressionParser::class); + while (true) { + $filter = $op->parse($this->parser, $filter, $this->parser->getCurrentToken()); + if (!$this->parser->getStream()->test(Token::OPERATOR_TYPE, '|')) { + break; + } + $this->parser->getStream()->next(); + } $this->parser->getStream()->expect(Token::BLOCK_END_TYPE); $body = $this->parser->subparse([$this, 'decideApplyEnd'], true); diff --git a/app/vendor/twig/twig/src/TokenParser/AutoEscapeTokenParser.php b/app/vendor/twig/twig/src/TokenParser/AutoEscapeTokenParser.php index b50b29e65..86feb27e6 100644 --- a/app/vendor/twig/twig/src/TokenParser/AutoEscapeTokenParser.php +++ b/app/vendor/twig/twig/src/TokenParser/AutoEscapeTokenParser.php @@ -32,7 +32,7 @@ public function parse(Token $token): Node if ($stream->test(Token::BLOCK_END_TYPE)) { $value = 'html'; } else { - $expr = $this->parser->getExpressionParser()->parseExpression(); + $expr = $this->parser->parseExpression(); if (!$expr instanceof ConstantExpression) { throw new SyntaxError('An escaping strategy must be a string or false.', $stream->getCurrent()->getLine(), $stream->getSourceContext()); } diff --git a/app/vendor/twig/twig/src/TokenParser/BlockTokenParser.php b/app/vendor/twig/twig/src/TokenParser/BlockTokenParser.php index 3561b99cd..452b323e5 100644 --- a/app/vendor/twig/twig/src/TokenParser/BlockTokenParser.php +++ b/app/vendor/twig/twig/src/TokenParser/BlockTokenParser.php @@ -53,7 +53,7 @@ public function parse(Token $token): Node } } else { $body = new Nodes([ - new PrintNode($this->parser->getExpressionParser()->parseExpression(), $lineno), + new PrintNode($this->parser->parseExpression(), $lineno), ]); } $stream->expect(Token::BLOCK_END_TYPE); diff --git a/app/vendor/twig/twig/src/TokenParser/DeprecatedTokenParser.php b/app/vendor/twig/twig/src/TokenParser/DeprecatedTokenParser.php index 164ef26ee..df1ba381f 100644 --- a/app/vendor/twig/twig/src/TokenParser/DeprecatedTokenParser.php +++ b/app/vendor/twig/twig/src/TokenParser/DeprecatedTokenParser.php @@ -33,8 +33,7 @@ final class DeprecatedTokenParser extends AbstractTokenParser public function parse(Token $token): Node { $stream = $this->parser->getStream(); - $expressionParser = $this->parser->getExpressionParser(); - $expr = $expressionParser->parseExpression(); + $expr = $this->parser->parseExpression(); $node = new DeprecatedNode($expr, $token->getLine()); while ($stream->test(Token::NAME_TYPE)) { @@ -44,10 +43,10 @@ public function parse(Token $token): Node switch ($k) { case 'package': - $node->setNode('package', $expressionParser->parseExpression()); + $node->setNode('package', $this->parser->parseExpression()); break; case 'version': - $node->setNode('version', $expressionParser->parseExpression()); + $node->setNode('version', $this->parser->parseExpression()); break; default: throw new SyntaxError(\sprintf('Unknown "%s" option.', $k), $stream->getCurrent()->getLine(), $stream->getSourceContext()); diff --git a/app/vendor/twig/twig/src/TokenParser/DoTokenParser.php b/app/vendor/twig/twig/src/TokenParser/DoTokenParser.php index 8afd48559..ca9d03d45 100644 --- a/app/vendor/twig/twig/src/TokenParser/DoTokenParser.php +++ b/app/vendor/twig/twig/src/TokenParser/DoTokenParser.php @@ -24,7 +24,7 @@ final class DoTokenParser extends AbstractTokenParser { public function parse(Token $token): Node { - $expr = $this->parser->getExpressionParser()->parseExpression(); + $expr = $this->parser->parseExpression(); $this->parser->getStream()->expect(Token::BLOCK_END_TYPE); diff --git a/app/vendor/twig/twig/src/TokenParser/EmbedTokenParser.php b/app/vendor/twig/twig/src/TokenParser/EmbedTokenParser.php index f1acbf1ef..fa2791046 100644 --- a/app/vendor/twig/twig/src/TokenParser/EmbedTokenParser.php +++ b/app/vendor/twig/twig/src/TokenParser/EmbedTokenParser.php @@ -28,7 +28,7 @@ public function parse(Token $token): Node { $stream = $this->parser->getStream(); - $parent = $this->parser->getExpressionParser()->parseExpression(); + $parent = $this->parser->parseExpression(); [$variables, $only, $ignoreMissing] = $this->parseArguments(); diff --git a/app/vendor/twig/twig/src/TokenParser/ExtendsTokenParser.php b/app/vendor/twig/twig/src/TokenParser/ExtendsTokenParser.php index a93afe8cd..8f6469818 100644 --- a/app/vendor/twig/twig/src/TokenParser/ExtendsTokenParser.php +++ b/app/vendor/twig/twig/src/TokenParser/ExtendsTokenParser.php @@ -36,7 +36,7 @@ public function parse(Token $token): Node throw new SyntaxError('Cannot use "extend" in a macro.', $token->getLine(), $stream->getSourceContext()); } - $this->parser->setParent($this->parser->getExpressionParser()->parseExpression()); + $this->parser->setParent($this->parser->parseExpression()); $stream->expect(Token::BLOCK_END_TYPE); diff --git a/app/vendor/twig/twig/src/TokenParser/ForTokenParser.php b/app/vendor/twig/twig/src/TokenParser/ForTokenParser.php index 3e08b22fa..21166fc1f 100644 --- a/app/vendor/twig/twig/src/TokenParser/ForTokenParser.php +++ b/app/vendor/twig/twig/src/TokenParser/ForTokenParser.php @@ -35,9 +35,9 @@ public function parse(Token $token): Node { $lineno = $token->getLine(); $stream = $this->parser->getStream(); - $targets = $this->parser->getExpressionParser()->parseAssignmentExpression(); + $targets = $this->parseAssignmentExpression(); $stream->expect(Token::OPERATOR_TYPE, 'in'); - $seq = $this->parser->getExpressionParser()->parseExpression(); + $seq = $this->parser->parseExpression(); $stream->expect(Token::BLOCK_END_TYPE); $body = $this->parser->subparse([$this, 'decideForFork']); diff --git a/app/vendor/twig/twig/src/TokenParser/FromTokenParser.php b/app/vendor/twig/twig/src/TokenParser/FromTokenParser.php index c8732df29..1c80a1717 100644 --- a/app/vendor/twig/twig/src/TokenParser/FromTokenParser.php +++ b/app/vendor/twig/twig/src/TokenParser/FromTokenParser.php @@ -29,7 +29,7 @@ final class FromTokenParser extends AbstractTokenParser { public function parse(Token $token): Node { - $macro = $this->parser->getExpressionParser()->parseExpression(); + $macro = $this->parser->parseExpression(); $stream = $this->parser->getStream(); $stream->expect(Token::NAME_TYPE, 'import'); diff --git a/app/vendor/twig/twig/src/TokenParser/GuardTokenParser.php b/app/vendor/twig/twig/src/TokenParser/GuardTokenParser.php index 1fcf76cd7..656766af5 100644 --- a/app/vendor/twig/twig/src/TokenParser/GuardTokenParser.php +++ b/app/vendor/twig/twig/src/TokenParser/GuardTokenParser.php @@ -26,7 +26,7 @@ public function parse(Token $token): Node { $stream = $this->parser->getStream(); $typeToken = $stream->expect(Token::NAME_TYPE); - if (!\in_array($typeToken->getValue(), ['function', 'filter', 'test'])) { + if (!\in_array($typeToken->getValue(), ['function', 'filter', 'test'], true)) { throw new SyntaxError(\sprintf('Supported guard types are function, filter and test, "%s" given.', $typeToken->getValue()), $typeToken->getLine(), $stream->getSourceContext()); } $method = 'get'.$typeToken->getValue(); diff --git a/app/vendor/twig/twig/src/TokenParser/IfTokenParser.php b/app/vendor/twig/twig/src/TokenParser/IfTokenParser.php index 6b9010563..4e3588e5b 100644 --- a/app/vendor/twig/twig/src/TokenParser/IfTokenParser.php +++ b/app/vendor/twig/twig/src/TokenParser/IfTokenParser.php @@ -36,7 +36,7 @@ final class IfTokenParser extends AbstractTokenParser public function parse(Token $token): Node { $lineno = $token->getLine(); - $expr = $this->parser->getExpressionParser()->parseExpression(); + $expr = $this->parser->parseExpression(); $stream = $this->parser->getStream(); $stream->expect(Token::BLOCK_END_TYPE); $body = $this->parser->subparse([$this, 'decideIfFork']); @@ -52,7 +52,7 @@ public function parse(Token $token): Node break; case 'elseif': - $expr = $this->parser->getExpressionParser()->parseExpression(); + $expr = $this->parser->parseExpression(); $stream->expect(Token::BLOCK_END_TYPE); $body = $this->parser->subparse([$this, 'decideIfFork']); $tests[] = $expr; diff --git a/app/vendor/twig/twig/src/TokenParser/ImportTokenParser.php b/app/vendor/twig/twig/src/TokenParser/ImportTokenParser.php index f23584a5a..6dcb7662c 100644 --- a/app/vendor/twig/twig/src/TokenParser/ImportTokenParser.php +++ b/app/vendor/twig/twig/src/TokenParser/ImportTokenParser.php @@ -28,7 +28,7 @@ final class ImportTokenParser extends AbstractTokenParser { public function parse(Token $token): Node { - $macro = $this->parser->getExpressionParser()->parseExpression(); + $macro = $this->parser->parseExpression(); $this->parser->getStream()->expect(Token::NAME_TYPE, 'as'); $name = $this->parser->getStream()->expect(Token::NAME_TYPE)->getValue(); $var = new AssignTemplateVariable(new TemplateVariable($name, $token->getLine()), $this->parser->isMainScope()); diff --git a/app/vendor/twig/twig/src/TokenParser/IncludeTokenParser.php b/app/vendor/twig/twig/src/TokenParser/IncludeTokenParser.php index c5ce180ad..55ac1516c 100644 --- a/app/vendor/twig/twig/src/TokenParser/IncludeTokenParser.php +++ b/app/vendor/twig/twig/src/TokenParser/IncludeTokenParser.php @@ -30,7 +30,7 @@ class IncludeTokenParser extends AbstractTokenParser { public function parse(Token $token): Node { - $expr = $this->parser->getExpressionParser()->parseExpression(); + $expr = $this->parser->parseExpression(); [$variables, $only, $ignoreMissing] = $this->parseArguments(); @@ -53,7 +53,7 @@ protected function parseArguments() $variables = null; if ($stream->nextIf(Token::NAME_TYPE, 'with')) { - $variables = $this->parser->getExpressionParser()->parseExpression(); + $variables = $this->parser->parseExpression(); } $only = false; diff --git a/app/vendor/twig/twig/src/TokenParser/MacroTokenParser.php b/app/vendor/twig/twig/src/TokenParser/MacroTokenParser.php index 33379be03..38e66c810 100644 --- a/app/vendor/twig/twig/src/TokenParser/MacroTokenParser.php +++ b/app/vendor/twig/twig/src/TokenParser/MacroTokenParser.php @@ -73,7 +73,7 @@ private function parseDefinition(): ArrayExpression { $arguments = new ArrayExpression([], $this->parser->getCurrentToken()->getLine()); $stream = $this->parser->getStream(); - $stream->expect(Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis'); + $stream->expect(Token::OPERATOR_TYPE, '(', 'A list of arguments must begin with an opening parenthesis'); while (!$stream->test(Token::PUNCTUATION_TYPE, ')')) { if (\count($arguments)) { $stream->expect(Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma'); @@ -87,7 +87,7 @@ private function parseDefinition(): ArrayExpression $token = $stream->expect(Token::NAME_TYPE, null, 'An argument must be a name'); $name = new LocalVariable($token->getValue(), $this->parser->getCurrentToken()->getLine()); if ($token = $stream->nextIf(Token::OPERATOR_TYPE, '=')) { - $default = $this->parser->getExpressionParser()->parseExpression(); + $default = $this->parser->parseExpression(); } else { $default = new ConstantExpression(null, $this->parser->getCurrentToken()->getLine()); $default->setAttribute('is_implicit', true); diff --git a/app/vendor/twig/twig/src/TokenParser/SetTokenParser.php b/app/vendor/twig/twig/src/TokenParser/SetTokenParser.php index bb43907bd..1aabbf582 100644 --- a/app/vendor/twig/twig/src/TokenParser/SetTokenParser.php +++ b/app/vendor/twig/twig/src/TokenParser/SetTokenParser.php @@ -13,6 +13,7 @@ use Twig\Error\SyntaxError; use Twig\Node\Node; +use Twig\Node\Nodes; use Twig\Node\SetNode; use Twig\Token; @@ -34,11 +35,11 @@ public function parse(Token $token): Node { $lineno = $token->getLine(); $stream = $this->parser->getStream(); - $names = $this->parser->getExpressionParser()->parseAssignmentExpression(); + $names = $this->parseAssignmentExpression(); $capture = false; if ($stream->nextIf(Token::OPERATOR_TYPE, '=')) { - $values = $this->parser->getExpressionParser()->parseMultitargetExpression(); + $values = $this->parseMultitargetExpression(); $stream->expect(Token::BLOCK_END_TYPE); @@ -70,4 +71,17 @@ public function getTag(): string { return 'set'; } + + private function parseMultitargetExpression(): Nodes + { + $targets = []; + while (true) { + $targets[] = $this->parser->parseExpression(); + if (!$this->parser->getStream()->nextIf(Token::PUNCTUATION_TYPE, ',')) { + break; + } + } + + return new Nodes($targets); + } } diff --git a/app/vendor/twig/twig/src/TokenParser/TypesTokenParser.php b/app/vendor/twig/twig/src/TokenParser/TypesTokenParser.php index a7da0f5ec..2c7b77c02 100644 --- a/app/vendor/twig/twig/src/TokenParser/TypesTokenParser.php +++ b/app/vendor/twig/twig/src/TokenParser/TypesTokenParser.php @@ -63,7 +63,7 @@ private function parseSimpleMappingExpression(TokenStream $stream): array if ($stream->nextIf(Token::OPERATOR_TYPE, '?:')) { $isOptional = true; } else { - $isOptional = null !== $stream->nextIf(Token::PUNCTUATION_TYPE, '?'); + $isOptional = null !== $stream->nextIf(Token::OPERATOR_TYPE, '?'); $stream->expect(Token::PUNCTUATION_TYPE, ':', 'A type name must be followed by a colon (:)'); } diff --git a/app/vendor/twig/twig/src/TokenParser/UseTokenParser.php b/app/vendor/twig/twig/src/TokenParser/UseTokenParser.php index ebd95aa31..41386c8b4 100644 --- a/app/vendor/twig/twig/src/TokenParser/UseTokenParser.php +++ b/app/vendor/twig/twig/src/TokenParser/UseTokenParser.php @@ -36,7 +36,7 @@ final class UseTokenParser extends AbstractTokenParser { public function parse(Token $token): Node { - $template = $this->parser->getExpressionParser()->parseExpression(); + $template = $this->parser->parseExpression(); $stream = $this->parser->getStream(); if (!$template instanceof ConstantExpression) { diff --git a/app/vendor/twig/twig/src/TokenParser/WithTokenParser.php b/app/vendor/twig/twig/src/TokenParser/WithTokenParser.php index 8ce4f02b2..83470d865 100644 --- a/app/vendor/twig/twig/src/TokenParser/WithTokenParser.php +++ b/app/vendor/twig/twig/src/TokenParser/WithTokenParser.php @@ -31,7 +31,7 @@ public function parse(Token $token): Node $variables = null; $only = false; if (!$stream->test(Token::BLOCK_END_TYPE)) { - $variables = $this->parser->getExpressionParser()->parseExpression(); + $variables = $this->parser->parseExpression(); $only = (bool) $stream->nextIf(Token::NAME_TYPE, 'only'); } diff --git a/app/vendor/twig/twig/src/Util/TemplateDirIterator.php b/app/vendor/twig/twig/src/Util/TemplateDirIterator.php index 3bef14bee..d739b285f 100644 --- a/app/vendor/twig/twig/src/Util/TemplateDirIterator.php +++ b/app/vendor/twig/twig/src/Util/TemplateDirIterator.php @@ -17,7 +17,7 @@ class TemplateDirIterator extends \IteratorIterator { /** - * @return mixed + * @return string */ #[\ReturnTypeWillChange] public function current() @@ -26,7 +26,7 @@ public function current() } /** - * @return mixed + * @return string */ #[\ReturnTypeWillChange] public function key()